diff --git a/deployment.goerli_live.json b/deployment.goerli_live.json index 94a2de6..a3255ae 100644 --- a/deployment.goerli_live.json +++ b/deployment.goerli_live.json @@ -2,19 +2,19 @@ "name": "goerli_live", "chainId": "5", "contracts": { - "ConsensusLayerFeeDispatcher": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", - "ConsensusLayerFeeDispatcher_Implementation": "0xC82c3D7515CDFf71c732cF5A240e86E53db0e21B", - "ConsensusLayerFeeDispatcher_Proxy": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", - "ExecutionLayerFeeDispatcher": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", - "ExecutionLayerFeeDispatcher_Implementation": "0xd68bA9327a3E2B1b173Ed31Bc882e7E70b461Fed", - "ExecutionLayerFeeDispatcher_Proxy": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", - "FeeRecipient": "0x8909BEE5B1CB83c42e7ff192e9dA34074104a4bb", - "StakingContract": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9", - "StakingContract_Implementation": "0xe8129e75a5324D7C95Aa36Dd4BaBF4fed825f5c3", - "StakingContract_Proxy": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9" + "ConsensusLayerFeeDispatcher": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", + "ConsensusLayerFeeDispatcher_Implementation": "0xb62a9d615d3018c22631b26F668Ed0882bA01813", + "ConsensusLayerFeeDispatcher_Proxy": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", + "ExecutionLayerFeeDispatcher": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", + "ExecutionLayerFeeDispatcher_Implementation": "0xa69dDEBd0B6893A6F3d34A5df610d0E2ED433D18", + "ExecutionLayerFeeDispatcher_Proxy": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", + "FeeRecipient": "0x1AcD717aDF8A3A1e4c23C6510cfbE76834E3f1bf", + "StakingContract": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543", + "StakingContract_Implementation": "0x7f14a8048De0c3BaAe292177Aa8b8fe55b32E704", + "StakingContract_Proxy": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543" }, "namedAccounts": { - "deployer": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", + "deployer": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", "proxyAdmin": "0x3B9B2C07eff60aC828117C997E04c61890Ad2Ed7", "admin": "0xC4b8469165d0A0e0939500BdeCE7c0CD3415a9fb", "depositContract": "0xff50ed3d0ec03aC01D4C79aAd74928BFF48a7b2b", diff --git a/deployments/goerli_live/ConsensusLayerFeeDispatcher.json b/deployments/goerli_live/ConsensusLayerFeeDispatcher.json index 7c83a48..6ac867b 100644 --- a/deployments/goerli_live/ConsensusLayerFeeDispatcher.json +++ b/deployments/goerli_live/ConsensusLayerFeeDispatcher.json @@ -1,5 +1,5 @@ { - "address": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", + "address": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", "abi": [ { "inputs": [], @@ -224,6 +224,12 @@ "name": "feeRecipient", "type": "address" }, + { + "indexed": false, + "internalType": "bytes32", + "name": "pubKeyRoot", + "type": "bytes32" + }, { "indexed": false, "internalType": "uint256", @@ -326,52 +332,52 @@ "type": "constructor" } ], - "transactionHash": "0x1fec24e2ab4f44850df4dd81ee7de06e4ae8900740b7020affb73ce5aa8daf89", + "transactionHash": "0xc118031edcaa693283c0b6d1fc588e0a45a3b67e614496741c9c35255f3a0879", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", - "transactionIndex": 5, - "gasUsed": "731293", - "logsBloom": "0x00000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000800000000000000000000000000000000000000000000400000000000000004000000000000000000000800000000000000000000000000000000000000000000000800000000000100000000000000020000000000000000000000000000000000400000000000000000010000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x10178d6e4200f86178527bf93d436f34f8c87701d51ac7c8148776f8675f5d19", - "transactionHash": "0x1fec24e2ab4f44850df4dd81ee7de06e4ae8900740b7020affb73ce5aa8daf89", + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", + "transactionIndex": 19, + "gasUsed": "731305", + "logsBloom": "0x00000000000000000000000000000000400000040000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000002000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000020000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000400000000000000010000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x1721a6764592f4c2919be1968d2cba31dd6a20822b167c4de1cc0ed541f9dcb4", + "transactionHash": "0xc118031edcaa693283c0b6d1fc588e0a45a3b67e614496741c9c35255f3a0879", "logs": [ { - "transactionIndex": 5, - "blockNumber": 7476023, - "transactionHash": "0x1fec24e2ab4f44850df4dd81ee7de06e4ae8900740b7020affb73ce5aa8daf89", - "address": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", + "transactionIndex": 19, + "blockNumber": 7633614, + "transactionHash": "0xc118031edcaa693283c0b6d1fc588e0a45a3b67e614496741c9c35255f3a0879", + "address": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", "topics": [ "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", - "0x000000000000000000000000c82c3d7515cdff71c732cf5a240e86e53db0e21b" + "0x000000000000000000000000b62a9d615d3018c22631b26f668ed0882ba01813" ], "data": "0x", - "logIndex": 8, - "blockHash": "0x10178d6e4200f86178527bf93d436f34f8c87701d51ac7c8148776f8675f5d19" + "logIndex": 58, + "blockHash": "0x1721a6764592f4c2919be1968d2cba31dd6a20822b167c4de1cc0ed541f9dcb4" }, { - "transactionIndex": 5, - "blockNumber": 7476023, - "transactionHash": "0x1fec24e2ab4f44850df4dd81ee7de06e4ae8900740b7020affb73ce5aa8daf89", - "address": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", + "transactionIndex": 19, + "blockNumber": 7633614, + "transactionHash": "0xc118031edcaa693283c0b6d1fc588e0a45a3b67e614496741c9c35255f3a0879", + "address": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", "topics": [ "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f" ], "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b9b2c07eff60ac828117c997e04c61890ad2ed7", - "logIndex": 9, - "blockHash": "0x10178d6e4200f86178527bf93d436f34f8c87701d51ac7c8148776f8675f5d19" + "logIndex": 59, + "blockHash": "0x1721a6764592f4c2919be1968d2cba31dd6a20822b167c4de1cc0ed541f9dcb4" } ], - "blockNumber": 7476023, - "cumulativeGasUsed": "1069782", + "blockNumber": 7633614, + "cumulativeGasUsed": "5607494", "status": 1, "byzantium": true }, "args": [ - "0xC82c3D7515CDFf71c732cF5A240e86E53db0e21B", + "0xb62a9d615d3018c22631b26F668Ed0882bA01813", "0x3B9B2C07eff60aC828117C997E04c61890Ad2Ed7", - "0x5f0f28d9000000000000000000000000fabff6e6f6ed3e602b2257008ea3ce1ec3539af9" + "0x5f0f28d9000000000000000000000000e8ff2a04837aac535199eecb5ece52b2735b3543" ], "numDeployments": 1, "solcInputHash": "8fad9248104c7377e7ee874218595b1c", @@ -381,10 +387,10 @@ "execute": { "methodName": "initCLD", "args": [ - "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9" + "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543" ] }, - "implementation": "0xC82c3D7515CDFf71c732cF5A240e86E53db0e21B", + "implementation": "0xb62a9d615d3018c22631b26F668Ed0882bA01813", "devdoc": { "author": "SkillZ", "kind": "dev", diff --git a/deployments/goerli_live/ConsensusLayerFeeDispatcher_Implementation.json b/deployments/goerli_live/ConsensusLayerFeeDispatcher_Implementation.json index 8ba8e94..e7211a3 100644 --- a/deployments/goerli_live/ConsensusLayerFeeDispatcher_Implementation.json +++ b/deployments/goerli_live/ConsensusLayerFeeDispatcher_Implementation.json @@ -1,5 +1,5 @@ { - "address": "0xC82c3D7515CDFf71c732cF5A240e86E53db0e21B", + "address": "0xb62a9d615d3018c22631b26F668Ed0882bA01813", "abi": [ { "inputs": [ @@ -80,6 +80,12 @@ "name": "feeRecipient", "type": "address" }, + { + "indexed": false, + "internalType": "bytes32", + "name": "pubKeyRoot", + "type": "bytes32" + }, { "indexed": false, "internalType": "uint256", @@ -169,19 +175,19 @@ "type": "receive" } ], - "transactionHash": "0xecffd267d1c3d23a61223741accc6449ad15e63baf3fb98b65ce0fe19f10ac75", + "transactionHash": "0xddd1ccd08ddd5af3c93f2b547888f640137f93ea678b6644cd5ab9cb693958af", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0xC82c3D7515CDFf71c732cF5A240e86E53db0e21B", - "transactionIndex": 6, + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0xb62a9d615d3018c22631b26F668Ed0882bA01813", + "transactionIndex": 29, "gasUsed": "262786", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x18986f8e45583bd9bd0a007f86f31b940f71609611c9979aee751be97eca2777", - "transactionHash": "0xecffd267d1c3d23a61223741accc6449ad15e63baf3fb98b65ce0fe19f10ac75", + "blockHash": "0xac8c80723b70960abb819ceb97e56237240ccf9a28b8c6afb6c48df4cad5a78d", + "transactionHash": "0xddd1ccd08ddd5af3c93f2b547888f640137f93ea678b6644cd5ab9cb693958af", "logs": [], - "blockNumber": 7476022, - "cumulativeGasUsed": "3787301", + "blockNumber": 7633612, + "cumulativeGasUsed": "7238835", "status": 1, "byzantium": true }, @@ -189,10 +195,10 @@ 1 ], "numDeployments": 1, - "solcInputHash": "721f6bc7fc7142905e230dbfd85db3e8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_version\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"FeeRecipientReceiveError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotImplemented\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"TreasuryReceiveError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"WithdrawerReceiveError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroBalanceWithdrawal\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nodeOperatorFee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"treasuryFee\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dispatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_publicKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"getWithdrawer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_stakingContract\",\"type\":\"address\"}],\"name\":\"initCLD\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Kiln\",\"kind\":\"dev\",\"methods\":{\"getWithdrawer(bytes32)\":{\"params\":{\"_publicKeyRoot\":\"Public key root to get the owner\"}},\"initCLD(address)\":{\"params\":{\"_stakingContract\":\"Address of the Staking Contract\"}}},\"title\":\"Consensus Layer Fee Recipient\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\"},\"dispatch(bytes32)\":{\"notice\":\"Performs a withdrawal on this contract's balance\"},\"getStakingContract()\":{\"notice\":\"Retrieve the staking contract address\"},\"getWithdrawer(bytes32)\":{\"notice\":\"Retrieve the assigned withdrawer for the given public key root\"},\"initCLD(address)\":{\"notice\":\"Initialize the contract by storing the staking contract\"}},\"notice\":\"This contract can be used to receive fees from a validator and split them with a node operator\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/contracts/ConsensusLayerFeeDispatcher.sol\":\"ConsensusLayerFeeDispatcher\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/contracts/ConsensusLayerFeeDispatcher.sol\":{\"content\":\"//SPDX-License-Identifier: BUSL-1.1\\npragma solidity >=0.8.10;\\n\\nimport \\\"./libs/DispatchersStorageLib.sol\\\";\\nimport \\\"./interfaces/IStakingContractFeeDetails.sol\\\";\\nimport \\\"./interfaces/IFeeDispatcher.sol\\\";\\n\\n/// @title Consensus Layer Fee Recipient\\n/// @author Kiln\\n/// @notice This contract can be used to receive fees from a validator and split them with a node operator\\ncontract ConsensusLayerFeeDispatcher is IFeeDispatcher {\\n using DispatchersStorageLib for bytes32;\\n\\n event Withdrawal(\\n address indexed withdrawer,\\n address indexed feeRecipient,\\n uint256 rewards,\\n uint256 nodeOperatorFee,\\n uint256 treasuryFee\\n );\\n\\n error TreasuryReceiveError(bytes errorData);\\n error FeeRecipientReceiveError(bytes errorData);\\n error WithdrawerReceiveError(bytes errorData);\\n error ZeroBalanceWithdrawal();\\n error AlreadyInitialized();\\n error InvalidCall();\\n error NotImplemented();\\n\\n bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =\\n keccak256(\\\"ConsensusLayerFeeRecipient.stakingContractAddress\\\");\\n uint256 internal constant BASIS_POINTS = 10_000;\\n bytes32 internal constant VERSION_SLOT = keccak256(\\\"ConsensusLayerFeeRecipient.version\\\");\\n\\n /// @notice Ensures an initialisation call has been called only once per _version value\\n /// @param _version The current initialisation value\\n modifier init(uint256 _version) {\\n if (_version != VERSION_SLOT.getUint256() + 1) {\\n revert AlreadyInitialized();\\n }\\n\\n VERSION_SLOT.setUint256(_version);\\n\\n _;\\n }\\n\\n /// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\\n constructor(uint256 _version) {\\n VERSION_SLOT.setUint256(_version);\\n }\\n\\n /// @notice Initialize the contract by storing the staking contract\\n /// @param _stakingContract Address of the Staking Contract\\n function initCLD(address _stakingContract) external init(1) {\\n STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);\\n }\\n\\n /// @notice Performs a withdrawal on this contract's balance\\n function dispatch(bytes32) external payable {\\n revert NotImplemented();\\n /*\\n uint256 balance = address(this).balance; // this has taken into account msg.value\\n if (balance == 0) {\\n revert ZeroBalanceWithdrawal();\\n }\\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\\n );\\n address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\\n address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);\\n address treasury = stakingContract.getTreasury();\\n uint256 globalFee;\\n\\n if (balance >= 32 ether) {\\n // withdrawing a healthy & exited validator\\n globalFee = ((balance - 32 ether) * stakingContract.getGlobalFee()) / BASIS_POINTS;\\n } else if (balance <= 16 ether) {\\n // withdrawing from what looks like skimming\\n globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;\\n }\\n\\n uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;\\n\\n (bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}(\\\"\\\");\\n if (status == false) {\\n revert WithdrawerReceiveError(data);\\n }\\n if (globalFee > 0) {\\n (status, data) = treasury.call{value: globalFee - operatorFee}(\\\"\\\");\\n if (status == false) {\\n revert FeeRecipientReceiveError(data);\\n }\\n }\\n if (operatorFee > 0) {\\n (status, data) = operator.call{value: operatorFee}(\\\"\\\");\\n if (status == false) {\\n revert TreasuryReceiveError(data);\\n }\\n }\\n emit Withdrawal(withdrawer, operator, balance - globalFee, operatorFee, globalFee - operatorFee);\\n */\\n }\\n\\n /// @notice Retrieve the staking contract address\\n function getStakingContract() external view returns (address) {\\n return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();\\n }\\n\\n /// @notice Retrieve the assigned withdrawer for the given public key root\\n /// @param _publicKeyRoot Public key root to get the owner\\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {\\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\\n );\\n return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\\n }\\n\\n receive() external payable {\\n revert InvalidCall();\\n }\\n\\n fallback() external payable {\\n revert InvalidCall();\\n }\\n}\\n\",\"keccak256\":\"0xe5b8514f354298169cccdf011dbb301f7bec0b7849a147600e6fb094216a9089\",\"license\":\"BUSL-1.1\"},\"src/contracts/interfaces/IFeeDispatcher.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IFeeDispatcher {\\n function dispatch(bytes32 _publicKeyRoot) external payable;\\n\\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address);\\n}\\n\",\"keccak256\":\"0x75efa5a697b32235188a62f730b7ab2a2fc5c422a93010aa0b18e93ea1bade45\",\"license\":\"MIT\"},\"src/contracts/interfaces/IStakingContractFeeDetails.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IStakingContractFeeDetails {\\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address);\\n\\n function getTreasury() external view returns (address);\\n\\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address);\\n\\n function getGlobalFee() external view returns (uint256);\\n\\n function getOperatorFee() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xa3f0dccf7edeb80f5d9078fe2a62118a2b222f136b786aebd3cc6fa5499276a8\",\"license\":\"MIT\"},\"src/contracts/libs/DispatchersStorageLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary DispatchersStorageLib {\\n function getUint256(bytes32 position) internal view returns (uint256 data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setUint256(bytes32 position, uint256 data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n\\n function getAddress(bytes32 position) internal view returns (address data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setAddress(bytes32 position, address data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x585a11c0ae6f9fda70d5d242ce02336bfd60fd75afed28495156307ba944f6cc\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b506040516103f23803806103f283398101604081905261002f91610070565b610066817f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef61006c60201b61028f1790919060201c565b50610089565b9055565b60006020828403121561008257600080fd5b5051919050565b61035a806100986000396000f3fe6080604052600436106100435760003560e01c806327de90161461007a5780635f0f28d9146100b65780638e68dce4146100d8578063ce120650146100ed57610061565b366100615760405163574b16a760e11b815260040160405180910390fd5b60405163574b16a760e11b815260040160405180910390fd5b34801561008657600080fd5b5061009a610095366004610293565b610100565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c257600080fd5b506100d66100d13660046102c4565b61019e565b005b3480156100e457600080fd5b5061009a610247565b6100d66100fb366004610293565b610276565b60008061012b7ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a515490565b60405163a740080160e01b8152600481018590529091506001600160a01b0382169063a740080190602401602060405180830381865afa158015610173573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019791906102e1565b9392505050565b60016101c87f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef5490565b6101d39060016102fe565b81146101f15760405162dc149f60e41b815260040160405180910390fd5b61021a7f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef829055565b6102437ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a51839055565b5050565b60006102717ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a515490565b905090565b60405163d623472560e01b815260040160405180910390fd5b9055565b6000602082840312156102a557600080fd5b5035919050565b6001600160a01b03811681146102c157600080fd5b50565b6000602082840312156102d657600080fd5b8135610197816102ac565b6000602082840312156102f357600080fd5b8151610197816102ac565b6000821982111561031f57634e487b7160e01b600052601160045260246000fd5b50019056fea26469706673582212202663a6b6fd8a309dddc426c504c0f90177c1c5f85ddaf5eace20a1c50c9d5f0e64736f6c634300080d0033", - "deployedBytecode": "0x6080604052600436106100435760003560e01c806327de90161461007a5780635f0f28d9146100b65780638e68dce4146100d8578063ce120650146100ed57610061565b366100615760405163574b16a760e11b815260040160405180910390fd5b60405163574b16a760e11b815260040160405180910390fd5b34801561008657600080fd5b5061009a610095366004610293565b610100565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c257600080fd5b506100d66100d13660046102c4565b61019e565b005b3480156100e457600080fd5b5061009a610247565b6100d66100fb366004610293565b610276565b60008061012b7ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a515490565b60405163a740080160e01b8152600481018590529091506001600160a01b0382169063a740080190602401602060405180830381865afa158015610173573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019791906102e1565b9392505050565b60016101c87f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef5490565b6101d39060016102fe565b81146101f15760405162dc149f60e41b815260040160405180910390fd5b61021a7f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef829055565b6102437ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a51839055565b5050565b60006102717ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a515490565b905090565b60405163d623472560e01b815260040160405180910390fd5b9055565b6000602082840312156102a557600080fd5b5035919050565b6001600160a01b03811681146102c157600080fd5b50565b6000602082840312156102d657600080fd5b8135610197816102ac565b6000602082840312156102f357600080fd5b8151610197816102ac565b6000821982111561031f57634e487b7160e01b600052601160045260246000fd5b50019056fea26469706673582212202663a6b6fd8a309dddc426c504c0f90177c1c5f85ddaf5eace20a1c50c9d5f0e64736f6c634300080d0033", + "solcInputHash": "7c01cac1856570acc6f28ecd3fd2c735", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_version\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"FeeRecipientReceiveError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotImplemented\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"TreasuryReceiveError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"WithdrawerReceiveError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroBalanceWithdrawal\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"pubKeyRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nodeOperatorFee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"treasuryFee\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dispatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_publicKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"getWithdrawer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_stakingContract\",\"type\":\"address\"}],\"name\":\"initCLD\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Kiln\",\"kind\":\"dev\",\"methods\":{\"getWithdrawer(bytes32)\":{\"params\":{\"_publicKeyRoot\":\"Public key root to get the owner\"}},\"initCLD(address)\":{\"params\":{\"_stakingContract\":\"Address of the Staking Contract\"}}},\"title\":\"Consensus Layer Fee Recipient\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\"},\"dispatch(bytes32)\":{\"notice\":\"Performs a withdrawal on this contract's balance\"},\"getStakingContract()\":{\"notice\":\"Retrieve the staking contract address\"},\"getWithdrawer(bytes32)\":{\"notice\":\"Retrieve the assigned withdrawer for the given public key root\"},\"initCLD(address)\":{\"notice\":\"Initialize the contract by storing the staking contract\"}},\"notice\":\"This contract can be used to receive fees from a validator and split them with a node operator\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/contracts/ConsensusLayerFeeDispatcher.sol\":\"ConsensusLayerFeeDispatcher\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/contracts/ConsensusLayerFeeDispatcher.sol\":{\"content\":\"//SPDX-License-Identifier: BUSL-1.1\\npragma solidity >=0.8.10;\\n\\nimport \\\"./libs/DispatchersStorageLib.sol\\\";\\nimport \\\"./interfaces/IStakingContractFeeDetails.sol\\\";\\nimport \\\"./interfaces/IFeeDispatcher.sol\\\";\\n\\n/// @title Consensus Layer Fee Recipient\\n/// @author Kiln\\n/// @notice This contract can be used to receive fees from a validator and split them with a node operator\\ncontract ConsensusLayerFeeDispatcher is IFeeDispatcher {\\n using DispatchersStorageLib for bytes32;\\n\\n event Withdrawal(\\n address indexed withdrawer,\\n address indexed feeRecipient,\\n bytes32 pubKeyRoot,\\n uint256 rewards,\\n uint256 nodeOperatorFee,\\n uint256 treasuryFee\\n );\\n\\n error TreasuryReceiveError(bytes errorData);\\n error FeeRecipientReceiveError(bytes errorData);\\n error WithdrawerReceiveError(bytes errorData);\\n error ZeroBalanceWithdrawal();\\n error AlreadyInitialized();\\n error InvalidCall();\\n error NotImplemented();\\n\\n bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =\\n keccak256(\\\"ConsensusLayerFeeRecipient.stakingContractAddress\\\");\\n uint256 internal constant BASIS_POINTS = 10_000;\\n bytes32 internal constant VERSION_SLOT = keccak256(\\\"ConsensusLayerFeeRecipient.version\\\");\\n\\n /// @notice Ensures an initialisation call has been called only once per _version value\\n /// @param _version The current initialisation value\\n modifier init(uint256 _version) {\\n if (_version != VERSION_SLOT.getUint256() + 1) {\\n revert AlreadyInitialized();\\n }\\n\\n VERSION_SLOT.setUint256(_version);\\n\\n _;\\n }\\n\\n /// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\\n constructor(uint256 _version) {\\n VERSION_SLOT.setUint256(_version);\\n }\\n\\n /// @notice Initialize the contract by storing the staking contract\\n /// @param _stakingContract Address of the Staking Contract\\n function initCLD(address _stakingContract) external init(1) {\\n STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);\\n }\\n\\n /// @notice Performs a withdrawal on this contract's balance\\n function dispatch(bytes32) external payable {\\n revert NotImplemented();\\n /*\\n uint256 balance = address(this).balance; // this has taken into account msg.value\\n if (balance == 0) {\\n revert ZeroBalanceWithdrawal();\\n }\\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\\n );\\n address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\\n address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);\\n address treasury = stakingContract.getTreasury();\\n uint256 globalFee;\\n\\n if (balance >= 32 ether) {\\n // withdrawing a healthy & exited validator\\n globalFee = ((balance - 32 ether) * stakingContract.getGlobalFee()) / BASIS_POINTS;\\n } else if (balance <= 16 ether) {\\n // withdrawing from what looks like skimming\\n globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;\\n }\\n\\n uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;\\n\\n (bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}(\\\"\\\");\\n if (status == false) {\\n revert WithdrawerReceiveError(data);\\n }\\n if (globalFee > 0) {\\n (status, data) = treasury.call{value: globalFee - operatorFee}(\\\"\\\");\\n if (status == false) {\\n revert FeeRecipientReceiveError(data);\\n }\\n }\\n if (operatorFee > 0) {\\n (status, data) = operator.call{value: operatorFee}(\\\"\\\");\\n if (status == false) {\\n revert TreasuryReceiveError(data);\\n }\\n }\\n emit Withdrawal(withdrawer, operator, balance - globalFee, operatorFee, globalFee - operatorFee);\\n */\\n }\\n\\n /// @notice Retrieve the staking contract address\\n function getStakingContract() external view returns (address) {\\n return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();\\n }\\n\\n /// @notice Retrieve the assigned withdrawer for the given public key root\\n /// @param _publicKeyRoot Public key root to get the owner\\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {\\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\\n );\\n return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\\n }\\n\\n receive() external payable {\\n revert InvalidCall();\\n }\\n\\n fallback() external payable {\\n revert InvalidCall();\\n }\\n}\\n\",\"keccak256\":\"0x902499807222841d87c74fa8aa216a8435edd4a2c61567e2742a1a54f0d887be\",\"license\":\"BUSL-1.1\"},\"src/contracts/interfaces/IFeeDispatcher.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IFeeDispatcher {\\n function dispatch(bytes32 _publicKeyRoot) external payable;\\n\\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address);\\n}\\n\",\"keccak256\":\"0x75efa5a697b32235188a62f730b7ab2a2fc5c422a93010aa0b18e93ea1bade45\",\"license\":\"MIT\"},\"src/contracts/interfaces/IStakingContractFeeDetails.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IStakingContractFeeDetails {\\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address);\\n\\n function getTreasury() external view returns (address);\\n\\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address);\\n\\n function getGlobalFee() external view returns (uint256);\\n\\n function getOperatorFee() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xa3f0dccf7edeb80f5d9078fe2a62118a2b222f136b786aebd3cc6fa5499276a8\",\"license\":\"MIT\"},\"src/contracts/libs/DispatchersStorageLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary DispatchersStorageLib {\\n function getUint256(bytes32 position) internal view returns (uint256 data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setUint256(bytes32 position, uint256 data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n\\n function getAddress(bytes32 position) internal view returns (address data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setAddress(bytes32 position, address data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x585a11c0ae6f9fda70d5d242ce02336bfd60fd75afed28495156307ba944f6cc\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506040516103f23803806103f283398101604081905261002f91610070565b610066817f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef61006c60201b61028f1790919060201c565b50610089565b9055565b60006020828403121561008257600080fd5b5051919050565b61035a806100986000396000f3fe6080604052600436106100435760003560e01c806327de90161461007a5780635f0f28d9146100b65780638e68dce4146100d8578063ce120650146100ed57610061565b366100615760405163574b16a760e11b815260040160405180910390fd5b60405163574b16a760e11b815260040160405180910390fd5b34801561008657600080fd5b5061009a610095366004610293565b610100565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c257600080fd5b506100d66100d13660046102c4565b61019e565b005b3480156100e457600080fd5b5061009a610247565b6100d66100fb366004610293565b610276565b60008061012b7ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a515490565b60405163a740080160e01b8152600481018590529091506001600160a01b0382169063a740080190602401602060405180830381865afa158015610173573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019791906102e1565b9392505050565b60016101c87f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef5490565b6101d39060016102fe565b81146101f15760405162dc149f60e41b815260040160405180910390fd5b61021a7f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef829055565b6102437ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a51839055565b5050565b60006102717ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a515490565b905090565b60405163d623472560e01b815260040160405180910390fd5b9055565b6000602082840312156102a557600080fd5b5035919050565b6001600160a01b03811681146102c157600080fd5b50565b6000602082840312156102d657600080fd5b8135610197816102ac565b6000602082840312156102f357600080fd5b8151610197816102ac565b6000821982111561031f57634e487b7160e01b600052601160045260246000fd5b50019056fea26469706673582212207197d60c6837e88856c998b751294e0777db82e7f50ec3acdaceb63488d1a50e64736f6c634300080d0033", + "deployedBytecode": "0x6080604052600436106100435760003560e01c806327de90161461007a5780635f0f28d9146100b65780638e68dce4146100d8578063ce120650146100ed57610061565b366100615760405163574b16a760e11b815260040160405180910390fd5b60405163574b16a760e11b815260040160405180910390fd5b34801561008657600080fd5b5061009a610095366004610293565b610100565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c257600080fd5b506100d66100d13660046102c4565b61019e565b005b3480156100e457600080fd5b5061009a610247565b6100d66100fb366004610293565b610276565b60008061012b7ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a515490565b60405163a740080160e01b8152600481018590529091506001600160a01b0382169063a740080190602401602060405180830381865afa158015610173573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019791906102e1565b9392505050565b60016101c87f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef5490565b6101d39060016102fe565b81146101f15760405162dc149f60e41b815260040160405180910390fd5b61021a7f6081a8ce97ad8a3951bac5b885ad6097d6b55cb45a6dd62b5069939f8c95ffef829055565b6102437ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a51839055565b5050565b60006102717ff0fe62e71ff1ce44ef40d55534c386cf3d375849a5782af5d4e66df449ae3a515490565b905090565b60405163d623472560e01b815260040160405180910390fd5b9055565b6000602082840312156102a557600080fd5b5035919050565b6001600160a01b03811681146102c157600080fd5b50565b6000602082840312156102d657600080fd5b8135610197816102ac565b6000602082840312156102f357600080fd5b8151610197816102ac565b6000821982111561031f57634e487b7160e01b600052601160045260246000fd5b50019056fea26469706673582212207197d60c6837e88856c998b751294e0777db82e7f50ec3acdaceb63488d1a50e64736f6c634300080d0033", "devdoc": { "author": "Kiln", "kind": "dev", diff --git a/deployments/goerli_live/ConsensusLayerFeeDispatcher_Proxy.json b/deployments/goerli_live/ConsensusLayerFeeDispatcher_Proxy.json index 5a907f2..611ea52 100644 --- a/deployments/goerli_live/ConsensusLayerFeeDispatcher_Proxy.json +++ b/deployments/goerli_live/ConsensusLayerFeeDispatcher_Proxy.json @@ -1,5 +1,5 @@ { - "address": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", + "address": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", "abi": [ { "inputs": [ @@ -178,52 +178,52 @@ "type": "receive" } ], - "transactionHash": "0x1fec24e2ab4f44850df4dd81ee7de06e4ae8900740b7020affb73ce5aa8daf89", + "transactionHash": "0xc118031edcaa693283c0b6d1fc588e0a45a3b67e614496741c9c35255f3a0879", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", - "transactionIndex": 5, - "gasUsed": "731293", - "logsBloom": "0x00000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000800000000000000000000000000000000000000000000400000000000000004000000000000000000000800000000000000000000000000000000000000000000000800000000000100000000000000020000000000000000000000000000000000400000000000000000010000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x10178d6e4200f86178527bf93d436f34f8c87701d51ac7c8148776f8675f5d19", - "transactionHash": "0x1fec24e2ab4f44850df4dd81ee7de06e4ae8900740b7020affb73ce5aa8daf89", + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", + "transactionIndex": 19, + "gasUsed": "731305", + "logsBloom": "0x00000000000000000000000000000000400000040000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000002000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000020000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000400000000000000010000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x1721a6764592f4c2919be1968d2cba31dd6a20822b167c4de1cc0ed541f9dcb4", + "transactionHash": "0xc118031edcaa693283c0b6d1fc588e0a45a3b67e614496741c9c35255f3a0879", "logs": [ { - "transactionIndex": 5, - "blockNumber": 7476023, - "transactionHash": "0x1fec24e2ab4f44850df4dd81ee7de06e4ae8900740b7020affb73ce5aa8daf89", - "address": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", + "transactionIndex": 19, + "blockNumber": 7633614, + "transactionHash": "0xc118031edcaa693283c0b6d1fc588e0a45a3b67e614496741c9c35255f3a0879", + "address": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", "topics": [ "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", - "0x000000000000000000000000c82c3d7515cdff71c732cf5a240e86e53db0e21b" + "0x000000000000000000000000b62a9d615d3018c22631b26f668ed0882ba01813" ], "data": "0x", - "logIndex": 8, - "blockHash": "0x10178d6e4200f86178527bf93d436f34f8c87701d51ac7c8148776f8675f5d19" + "logIndex": 58, + "blockHash": "0x1721a6764592f4c2919be1968d2cba31dd6a20822b167c4de1cc0ed541f9dcb4" }, { - "transactionIndex": 5, - "blockNumber": 7476023, - "transactionHash": "0x1fec24e2ab4f44850df4dd81ee7de06e4ae8900740b7020affb73ce5aa8daf89", - "address": "0x8DAA332F78e9261969cdAB643F057608Dbe71121", + "transactionIndex": 19, + "blockNumber": 7633614, + "transactionHash": "0xc118031edcaa693283c0b6d1fc588e0a45a3b67e614496741c9c35255f3a0879", + "address": "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", "topics": [ "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f" ], "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b9b2c07eff60ac828117c997e04c61890ad2ed7", - "logIndex": 9, - "blockHash": "0x10178d6e4200f86178527bf93d436f34f8c87701d51ac7c8148776f8675f5d19" + "logIndex": 59, + "blockHash": "0x1721a6764592f4c2919be1968d2cba31dd6a20822b167c4de1cc0ed541f9dcb4" } ], - "blockNumber": 7476023, - "cumulativeGasUsed": "1069782", + "blockNumber": 7633614, + "cumulativeGasUsed": "5607494", "status": 1, "byzantium": true }, "args": [ - "0xC82c3D7515CDFf71c732cF5A240e86E53db0e21B", + "0xb62a9d615d3018c22631b26F668Ed0882bA01813", "0x3B9B2C07eff60aC828117C997E04c61890Ad2Ed7", - "0x5f0f28d9000000000000000000000000fabff6e6f6ed3e602b2257008ea3ce1ec3539af9" + "0x5f0f28d9000000000000000000000000e8ff2a04837aac535199eecb5ece52b2735b3543" ], "numDeployments": 1, "solcInputHash": "8fad9248104c7377e7ee874218595b1c", diff --git a/deployments/goerli_live/ExecutionLayerFeeDispatcher.json b/deployments/goerli_live/ExecutionLayerFeeDispatcher.json index f7840c3..00056df 100644 --- a/deployments/goerli_live/ExecutionLayerFeeDispatcher.json +++ b/deployments/goerli_live/ExecutionLayerFeeDispatcher.json @@ -1,5 +1,5 @@ { - "address": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", + "address": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", "abi": [ { "inputs": [], @@ -219,6 +219,12 @@ "name": "feeRecipient", "type": "address" }, + { + "indexed": false, + "internalType": "bytes32", + "name": "pubKeyRoot", + "type": "bytes32" + }, { "indexed": false, "internalType": "uint256", @@ -321,52 +327,52 @@ "type": "constructor" } ], - "transactionHash": "0xd688d6d9ac63c5b350d3c6f9ea659a5f1b56aafe90c38c3932cc692d13118f76", + "transactionHash": "0xcc7aec91f3315d10cff8aa0e4916c1c82df0b96433065d2fdfefac3ff7e2552d", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", - "transactionIndex": 35, - "gasUsed": "731304", - "logsBloom": "0x00000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000800000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000080000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000004000000000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000800010000000000000000000000000000000000000", - "blockHash": "0xbfd9f12ddc67697553404033ffc5ede9c68126c785481605b3196619f54d6de4", - "transactionHash": "0xd688d6d9ac63c5b350d3c6f9ea659a5f1b56aafe90c38c3932cc692d13118f76", + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", + "transactionIndex": 26, + "gasUsed": "731316", + "logsBloom": "0x00000000000000000000000000000000400000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000080000000000000000000000000000000000000008000000000000000000000000800000000000420000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000400000000000000000000000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x426ca3d6533ffbf684d4f584cc8a43ae24e7fcc0ad7482adfe27fe08e2638d5f", + "transactionHash": "0xcc7aec91f3315d10cff8aa0e4916c1c82df0b96433065d2fdfefac3ff7e2552d", "logs": [ { - "transactionIndex": 35, - "blockNumber": 7476025, - "transactionHash": "0xd688d6d9ac63c5b350d3c6f9ea659a5f1b56aafe90c38c3932cc692d13118f76", - "address": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", + "transactionIndex": 26, + "blockNumber": 7633617, + "transactionHash": "0xcc7aec91f3315d10cff8aa0e4916c1c82df0b96433065d2fdfefac3ff7e2552d", + "address": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", "topics": [ "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", - "0x000000000000000000000000d68ba9327a3e2b1b173ed31bc882e7e70b461fed" + "0x000000000000000000000000a69ddebd0b6893a6f3d34a5df610d0e2ed433d18" ], "data": "0x", - "logIndex": 85, - "blockHash": "0xbfd9f12ddc67697553404033ffc5ede9c68126c785481605b3196619f54d6de4" + "logIndex": 37, + "blockHash": "0x426ca3d6533ffbf684d4f584cc8a43ae24e7fcc0ad7482adfe27fe08e2638d5f" }, { - "transactionIndex": 35, - "blockNumber": 7476025, - "transactionHash": "0xd688d6d9ac63c5b350d3c6f9ea659a5f1b56aafe90c38c3932cc692d13118f76", - "address": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", + "transactionIndex": 26, + "blockNumber": 7633617, + "transactionHash": "0xcc7aec91f3315d10cff8aa0e4916c1c82df0b96433065d2fdfefac3ff7e2552d", + "address": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", "topics": [ "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f" ], "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b9b2c07eff60ac828117c997e04c61890ad2ed7", - "logIndex": 86, - "blockHash": "0xbfd9f12ddc67697553404033ffc5ede9c68126c785481605b3196619f54d6de4" + "logIndex": 38, + "blockHash": "0x426ca3d6533ffbf684d4f584cc8a43ae24e7fcc0ad7482adfe27fe08e2638d5f" } ], - "blockNumber": 7476025, - "cumulativeGasUsed": "9116243", + "blockNumber": 7633617, + "cumulativeGasUsed": "6720363", "status": 1, "byzantium": true }, "args": [ - "0xd68bA9327a3E2B1b173Ed31Bc882e7E70b461Fed", + "0xa69dDEBd0B6893A6F3d34A5df610d0E2ED433D18", "0x3B9B2C07eff60aC828117C997E04c61890Ad2Ed7", - "0x068a8c8d000000000000000000000000fabff6e6f6ed3e602b2257008ea3ce1ec3539af9" + "0x068a8c8d000000000000000000000000e8ff2a04837aac535199eecb5ece52b2735b3543" ], "numDeployments": 1, "solcInputHash": "8fad9248104c7377e7ee874218595b1c", @@ -376,10 +382,10 @@ "execute": { "methodName": "initELD", "args": [ - "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9" + "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543" ] }, - "implementation": "0xd68bA9327a3E2B1b173Ed31Bc882e7E70b461Fed", + "implementation": "0xa69dDEBd0B6893A6F3d34A5df610d0E2ED433D18", "devdoc": { "author": "SkillZ", "kind": "dev", diff --git a/deployments/goerli_live/ExecutionLayerFeeDispatcher_Implementation.json b/deployments/goerli_live/ExecutionLayerFeeDispatcher_Implementation.json index f6c491c..ece67d8 100644 --- a/deployments/goerli_live/ExecutionLayerFeeDispatcher_Implementation.json +++ b/deployments/goerli_live/ExecutionLayerFeeDispatcher_Implementation.json @@ -1,5 +1,5 @@ { - "address": "0xd68bA9327a3E2B1b173Ed31Bc882e7E70b461Fed", + "address": "0xa69dDEBd0B6893A6F3d34A5df610d0E2ED433D18", "abi": [ { "inputs": [ @@ -75,6 +75,12 @@ "name": "feeRecipient", "type": "address" }, + { + "indexed": false, + "internalType": "bytes32", + "name": "pubKeyRoot", + "type": "bytes32" + }, { "indexed": false, "internalType": "uint256", @@ -164,19 +170,19 @@ "type": "receive" } ], - "transactionHash": "0x536730d9179bde5c30587656601f83a7dd20012f7d03b213c72b01415480785a", + "transactionHash": "0x27479be62df7b574250eb2e11dc4a0f20cca98113c9179ff4b7fc714ebc32c38", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0xd68bA9327a3E2B1b173Ed31Bc882e7E70b461Fed", - "transactionIndex": 14, - "gasUsed": "544344", + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0xa69dDEBd0B6893A6F3d34A5df610d0E2ED433D18", + "transactionIndex": 6, + "gasUsed": "545640", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xbdd13df570b0213fa9bcfb5b8bdbc409d9f6d803df1d1da23976ad26fcda10db", - "transactionHash": "0x536730d9179bde5c30587656601f83a7dd20012f7d03b213c72b01415480785a", + "blockHash": "0xed4e8873a2737f65bd5731f500d201778c0dc9814de6fc01b559dd774e874273", + "transactionHash": "0x27479be62df7b574250eb2e11dc4a0f20cca98113c9179ff4b7fc714ebc32c38", "logs": [], - "blockNumber": 7476024, - "cumulativeGasUsed": "8772343", + "blockNumber": 7633615, + "cumulativeGasUsed": "905916", "status": 1, "byzantium": true }, @@ -184,10 +190,10 @@ 1 ], "numDeployments": 1, - "solcInputHash": "721f6bc7fc7142905e230dbfd85db3e8", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_version\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"FeeRecipientReceiveError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"TreasuryReceiveError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"WithdrawerReceiveError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroBalanceWithdrawal\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nodeOperatorFee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"treasuryFee\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_publicKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"dispatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_publicKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"getWithdrawer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_stakingContract\",\"type\":\"address\"}],\"name\":\"initELD\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Kiln\",\"kind\":\"dev\",\"methods\":{\"getWithdrawer(bytes32)\":{\"params\":{\"_publicKeyRoot\":\"Public key root to get the owner\"}},\"initELD(address)\":{\"params\":{\"_stakingContract\":\"Address of the Staking Contract\"}}},\"title\":\"Execution Layer Fee Recipient\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\"},\"dispatch(bytes32)\":{\"notice\":\"Performs a withdrawal on this contract's balance\"},\"getStakingContract()\":{\"notice\":\"Retrieve the staking contract address\"},\"getWithdrawer(bytes32)\":{\"notice\":\"Retrieve the assigned withdrawer for the given public key root\"},\"initELD(address)\":{\"notice\":\"Initialize the contract by storing the staking contract and the public key in storage\"}},\"notice\":\"This contract can be used to receive fees from a validator and split them with a node operator\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/contracts/ExecutionLayerFeeDispatcher.sol\":\"ExecutionLayerFeeDispatcher\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/contracts/ExecutionLayerFeeDispatcher.sol\":{\"content\":\"//SPDX-License-Identifier: BUSL-1.1\\npragma solidity >=0.8.10;\\n\\nimport \\\"./libs/DispatchersStorageLib.sol\\\";\\nimport \\\"./interfaces/IStakingContractFeeDetails.sol\\\";\\nimport \\\"./interfaces/IFeeDispatcher.sol\\\";\\n\\n/// @title Execution Layer Fee Recipient\\n/// @author Kiln\\n/// @notice This contract can be used to receive fees from a validator and split them with a node operator\\ncontract ExecutionLayerFeeDispatcher is IFeeDispatcher {\\n using DispatchersStorageLib for bytes32;\\n\\n event Withdrawal(\\n address indexed withdrawer,\\n address indexed feeRecipient,\\n uint256 rewards,\\n uint256 nodeOperatorFee,\\n uint256 treasuryFee\\n );\\n\\n error TreasuryReceiveError(bytes errorData);\\n error FeeRecipientReceiveError(bytes errorData);\\n error WithdrawerReceiveError(bytes errorData);\\n error ZeroBalanceWithdrawal();\\n error AlreadyInitialized();\\n error InvalidCall();\\n\\n bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =\\n keccak256(\\\"ExecutionLayerFeeRecipient.stakingContractAddress\\\");\\n uint256 internal constant BASIS_POINTS = 10_000;\\n bytes32 internal constant VERSION_SLOT = keccak256(\\\"ExecutionLayerFeeRecipient.version\\\");\\n\\n /// @notice Ensures an initialisation call has been called only once per _version value\\n /// @param _version The current initialisation value\\n modifier init(uint256 _version) {\\n if (_version != VERSION_SLOT.getUint256() + 1) {\\n revert AlreadyInitialized();\\n }\\n\\n VERSION_SLOT.setUint256(_version);\\n\\n _;\\n }\\n\\n /// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\\n constructor(uint256 _version) {\\n VERSION_SLOT.setUint256(_version);\\n }\\n\\n /// @notice Initialize the contract by storing the staking contract and the public key in storage\\n /// @param _stakingContract Address of the Staking Contract\\n function initELD(address _stakingContract) external init(1) {\\n STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);\\n }\\n\\n /// @notice Performs a withdrawal on this contract's balance\\n function dispatch(bytes32 _publicKeyRoot) external payable {\\n uint256 balance = address(this).balance;\\n if (balance == 0) {\\n revert ZeroBalanceWithdrawal();\\n }\\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\\n );\\n address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\\n address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);\\n address treasury = stakingContract.getTreasury();\\n uint256 globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;\\n uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;\\n\\n (bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}(\\\"\\\");\\n if (status == false) {\\n revert WithdrawerReceiveError(data);\\n }\\n if (globalFee > 0) {\\n (status, data) = treasury.call{value: globalFee - operatorFee}(\\\"\\\");\\n if (status == false) {\\n revert FeeRecipientReceiveError(data);\\n }\\n }\\n if (operatorFee > 0) {\\n (status, data) = operator.call{value: operatorFee}(\\\"\\\");\\n if (status == false) {\\n revert TreasuryReceiveError(data);\\n }\\n }\\n emit Withdrawal(withdrawer, operator, balance - globalFee, operatorFee, globalFee - operatorFee);\\n }\\n\\n /// @notice Retrieve the staking contract address\\n function getStakingContract() external view returns (address) {\\n return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();\\n }\\n\\n /// @notice Retrieve the assigned withdrawer for the given public key root\\n /// @param _publicKeyRoot Public key root to get the owner\\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {\\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\\n );\\n return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\\n }\\n\\n receive() external payable {\\n revert InvalidCall();\\n }\\n\\n fallback() external payable {\\n revert InvalidCall();\\n }\\n}\\n\",\"keccak256\":\"0x71871152e7ff388e527f70f714954fac2f9e88c5b92d18bd882502aed0e8d4ad\",\"license\":\"BUSL-1.1\"},\"src/contracts/interfaces/IFeeDispatcher.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IFeeDispatcher {\\n function dispatch(bytes32 _publicKeyRoot) external payable;\\n\\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address);\\n}\\n\",\"keccak256\":\"0x75efa5a697b32235188a62f730b7ab2a2fc5c422a93010aa0b18e93ea1bade45\",\"license\":\"MIT\"},\"src/contracts/interfaces/IStakingContractFeeDetails.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IStakingContractFeeDetails {\\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address);\\n\\n function getTreasury() external view returns (address);\\n\\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address);\\n\\n function getGlobalFee() external view returns (uint256);\\n\\n function getOperatorFee() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xa3f0dccf7edeb80f5d9078fe2a62118a2b222f136b786aebd3cc6fa5499276a8\",\"license\":\"MIT\"},\"src/contracts/libs/DispatchersStorageLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary DispatchersStorageLib {\\n function getUint256(bytes32 position) internal view returns (uint256 data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setUint256(bytes32 position, uint256 data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n\\n function getAddress(bytes32 position) internal view returns (address data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setAddress(bytes32 position, address data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x585a11c0ae6f9fda70d5d242ce02336bfd60fd75afed28495156307ba944f6cc\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b5060405161090b38038061090b83398101604081905261002f91610070565b610066817f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b161006c60201b6106ba1790919060201c565b50610089565b9055565b60006020828403121561008257600080fd5b5051919050565b610873806100986000396000f3fe6080604052600436106100435760003560e01c8063068a8c8d1461007a57806327de90161461009c5780638e68dce4146100d8578063ce120650146100ed57610061565b366100615760405163574b16a760e11b815260040160405180910390fd5b60405163574b16a760e11b815260040160405180910390fd5b34801561008657600080fd5b5061009a6100953660046106d6565b610100565b005b3480156100a857600080fd5b506100bc6100b73660046106f3565b610197565b6040516001600160a01b03909116815260200160405180910390f35b3480156100e457600080fd5b506100bc610223565b61009a6100fb3660046106f3565b610240565b600161012a7f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b15490565b610135906001610722565b81146101535760405162dc149f60e41b815260040160405180910390fd5b61017c7f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b1829055565b61019360008051602061081e833981519152839055565b5050565b6000806101b060008051602061081e8339815191525490565b60405163a740080160e01b8152600481018590529091506001600160a01b0382169063a740080190602401602060405180830381865afa1580156101f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061021c919061073a565b9392505050565b600061023b60008051602061081e8339815191525490565b905090565b47600081900361026357604051635b2b158560e11b815260040160405180910390fd5b600061027b60008051602061081e8339815191525490565b60405163a740080160e01b8152600481018590529091506000906001600160a01b0383169063a740080190602401602060405180830381865afa1580156102c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ea919061073a565b604051634d6fc8f760e11b8152600481018690529091506000906001600160a01b03841690639adf91ee90602401602060405180830381865afa158015610335573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610359919061073a565b90506000836001600160a01b0316633b19e84a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561039b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103bf919061073a565b90506000612710856001600160a01b0316631bcbfaba6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104289190610757565b6104329088610770565b61043c919061078f565b90506000612710866001600160a01b031663286966086040518163ffffffff1660e01b8152600401602060405180830381865afa158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a59190610757565b6104af9084610770565b6104b9919061078f565b90506000806001600160a01b0387166104d2858b6107b1565b604051600081818185875af1925050503d806000811461050e576040519150601f19603f3d011682016040523d82523d6000602084013e610513565b606091505b509092509050811515600003610547578060405163ce13343d60e01b815260040161053e91906107c8565b60405180910390fd5b83156105cd576001600160a01b03851661056184866107b1565b604051600081818185875af1925050503d806000811461059d576040519150601f19603f3d011682016040523d82523d6000602084013e6105a2565b606091505b5090925090508115156000036105cd578060405163e5ea83e760e01b815260040161053e91906107c8565b821561064c576040516001600160a01b038716908490600081818185875af1925050503d806000811461061c576040519150601f19603f3d011682016040523d82523d6000602084013e610621565b606091505b50909250905081151560000361064c578060405163bc98622d60e01b815260040161053e91906107c8565b6001600160a01b038087169088167f0373e649c2cd6407bd569d5c66304cce4b4977c361734b811045f83c7bfe8c8b610685878d6107b1565b86610690818a6107b1565b6040805193845260208401929092529082015260600160405180910390a350505050505050505050565b9055565b6001600160a01b03811681146106d357600080fd5b50565b6000602082840312156106e857600080fd5b813561021c816106be565b60006020828403121561070557600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b600082198211156107355761073561070c565b500190565b60006020828403121561074c57600080fd5b815161021c816106be565b60006020828403121561076957600080fd5b5051919050565b600081600019048311821515161561078a5761078a61070c565b500290565b6000826107ac57634e487b7160e01b600052601260045260246000fd5b500490565b6000828210156107c3576107c361070c565b500390565b600060208083528351808285015260005b818110156107f5578581018301518582016040015282016107d9565b81811115610807576000604083870101525b50601f01601f191692909201604001939250505056feda87ab80a3be8afba92a2e1fa9eebe6df07c3e4f871642fcbd8b843ff0112511a264697066735822122093a72dff92c479aad50e33061cbf19d60a16ab15e00f4fa5cb32d26ad2fb9ff164736f6c634300080d0033", - "deployedBytecode": "0x6080604052600436106100435760003560e01c8063068a8c8d1461007a57806327de90161461009c5780638e68dce4146100d8578063ce120650146100ed57610061565b366100615760405163574b16a760e11b815260040160405180910390fd5b60405163574b16a760e11b815260040160405180910390fd5b34801561008657600080fd5b5061009a6100953660046106d6565b610100565b005b3480156100a857600080fd5b506100bc6100b73660046106f3565b610197565b6040516001600160a01b03909116815260200160405180910390f35b3480156100e457600080fd5b506100bc610223565b61009a6100fb3660046106f3565b610240565b600161012a7f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b15490565b610135906001610722565b81146101535760405162dc149f60e41b815260040160405180910390fd5b61017c7f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b1829055565b61019360008051602061081e833981519152839055565b5050565b6000806101b060008051602061081e8339815191525490565b60405163a740080160e01b8152600481018590529091506001600160a01b0382169063a740080190602401602060405180830381865afa1580156101f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061021c919061073a565b9392505050565b600061023b60008051602061081e8339815191525490565b905090565b47600081900361026357604051635b2b158560e11b815260040160405180910390fd5b600061027b60008051602061081e8339815191525490565b60405163a740080160e01b8152600481018590529091506000906001600160a01b0383169063a740080190602401602060405180830381865afa1580156102c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ea919061073a565b604051634d6fc8f760e11b8152600481018690529091506000906001600160a01b03841690639adf91ee90602401602060405180830381865afa158015610335573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610359919061073a565b90506000836001600160a01b0316633b19e84a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561039b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103bf919061073a565b90506000612710856001600160a01b0316631bcbfaba6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104289190610757565b6104329088610770565b61043c919061078f565b90506000612710866001600160a01b031663286966086040518163ffffffff1660e01b8152600401602060405180830381865afa158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a59190610757565b6104af9084610770565b6104b9919061078f565b90506000806001600160a01b0387166104d2858b6107b1565b604051600081818185875af1925050503d806000811461050e576040519150601f19603f3d011682016040523d82523d6000602084013e610513565b606091505b509092509050811515600003610547578060405163ce13343d60e01b815260040161053e91906107c8565b60405180910390fd5b83156105cd576001600160a01b03851661056184866107b1565b604051600081818185875af1925050503d806000811461059d576040519150601f19603f3d011682016040523d82523d6000602084013e6105a2565b606091505b5090925090508115156000036105cd578060405163e5ea83e760e01b815260040161053e91906107c8565b821561064c576040516001600160a01b038716908490600081818185875af1925050503d806000811461061c576040519150601f19603f3d011682016040523d82523d6000602084013e610621565b606091505b50909250905081151560000361064c578060405163bc98622d60e01b815260040161053e91906107c8565b6001600160a01b038087169088167f0373e649c2cd6407bd569d5c66304cce4b4977c361734b811045f83c7bfe8c8b610685878d6107b1565b86610690818a6107b1565b6040805193845260208401929092529082015260600160405180910390a350505050505050505050565b9055565b6001600160a01b03811681146106d357600080fd5b50565b6000602082840312156106e857600080fd5b813561021c816106be565b60006020828403121561070557600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b600082198211156107355761073561070c565b500190565b60006020828403121561074c57600080fd5b815161021c816106be565b60006020828403121561076957600080fd5b5051919050565b600081600019048311821515161561078a5761078a61070c565b500290565b6000826107ac57634e487b7160e01b600052601260045260246000fd5b500490565b6000828210156107c3576107c361070c565b500390565b600060208083528351808285015260005b818110156107f5578581018301518582016040015282016107d9565b81811115610807576000604083870101525b50601f01601f191692909201604001939250505056feda87ab80a3be8afba92a2e1fa9eebe6df07c3e4f871642fcbd8b843ff0112511a264697066735822122093a72dff92c479aad50e33061cbf19d60a16ab15e00f4fa5cb32d26ad2fb9ff164736f6c634300080d0033", + "solcInputHash": "7c01cac1856570acc6f28ecd3fd2c735", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_version\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"FeeRecipientReceiveError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"TreasuryReceiveError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorData\",\"type\":\"bytes\"}],\"name\":\"WithdrawerReceiveError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroBalanceWithdrawal\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"pubKeyRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nodeOperatorFee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"treasuryFee\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_publicKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"dispatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStakingContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_publicKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"getWithdrawer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_stakingContract\",\"type\":\"address\"}],\"name\":\"initELD\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Kiln\",\"kind\":\"dev\",\"methods\":{\"getWithdrawer(bytes32)\":{\"params\":{\"_publicKeyRoot\":\"Public key root to get the owner\"}},\"initELD(address)\":{\"params\":{\"_stakingContract\":\"Address of the Staking Contract\"}}},\"title\":\"Execution Layer Fee Recipient\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\"},\"dispatch(bytes32)\":{\"notice\":\"Performs a withdrawal on this contract's balance\"},\"getStakingContract()\":{\"notice\":\"Retrieve the staking contract address\"},\"getWithdrawer(bytes32)\":{\"notice\":\"Retrieve the assigned withdrawer for the given public key root\"},\"initELD(address)\":{\"notice\":\"Initialize the contract by storing the staking contract and the public key in storage\"}},\"notice\":\"This contract can be used to receive fees from a validator and split them with a node operator\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/contracts/ExecutionLayerFeeDispatcher.sol\":\"ExecutionLayerFeeDispatcher\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/contracts/ExecutionLayerFeeDispatcher.sol\":{\"content\":\"//SPDX-License-Identifier: BUSL-1.1\\npragma solidity >=0.8.10;\\n\\nimport \\\"./libs/DispatchersStorageLib.sol\\\";\\nimport \\\"./interfaces/IStakingContractFeeDetails.sol\\\";\\nimport \\\"./interfaces/IFeeDispatcher.sol\\\";\\n\\n/// @title Execution Layer Fee Recipient\\n/// @author Kiln\\n/// @notice This contract can be used to receive fees from a validator and split them with a node operator\\ncontract ExecutionLayerFeeDispatcher is IFeeDispatcher {\\n using DispatchersStorageLib for bytes32;\\n\\n event Withdrawal(\\n address indexed withdrawer,\\n address indexed feeRecipient,\\n bytes32 pubKeyRoot,\\n uint256 rewards,\\n uint256 nodeOperatorFee,\\n uint256 treasuryFee\\n );\\n\\n error TreasuryReceiveError(bytes errorData);\\n error FeeRecipientReceiveError(bytes errorData);\\n error WithdrawerReceiveError(bytes errorData);\\n error ZeroBalanceWithdrawal();\\n error AlreadyInitialized();\\n error InvalidCall();\\n\\n bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =\\n keccak256(\\\"ExecutionLayerFeeRecipient.stakingContractAddress\\\");\\n uint256 internal constant BASIS_POINTS = 10_000;\\n bytes32 internal constant VERSION_SLOT = keccak256(\\\"ExecutionLayerFeeRecipient.version\\\");\\n\\n /// @notice Ensures an initialisation call has been called only once per _version value\\n /// @param _version The current initialisation value\\n modifier init(uint256 _version) {\\n if (_version != VERSION_SLOT.getUint256() + 1) {\\n revert AlreadyInitialized();\\n }\\n\\n VERSION_SLOT.setUint256(_version);\\n\\n _;\\n }\\n\\n /// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\\n constructor(uint256 _version) {\\n VERSION_SLOT.setUint256(_version);\\n }\\n\\n /// @notice Initialize the contract by storing the staking contract and the public key in storage\\n /// @param _stakingContract Address of the Staking Contract\\n function initELD(address _stakingContract) external init(1) {\\n STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);\\n }\\n\\n /// @notice Performs a withdrawal on this contract's balance\\n function dispatch(bytes32 _publicKeyRoot) external payable {\\n uint256 balance = address(this).balance;\\n if (balance == 0) {\\n revert ZeroBalanceWithdrawal();\\n }\\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\\n );\\n address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\\n address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);\\n address treasury = stakingContract.getTreasury();\\n uint256 globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;\\n uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;\\n\\n (bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}(\\\"\\\");\\n if (status == false) {\\n revert WithdrawerReceiveError(data);\\n }\\n if (globalFee > 0) {\\n (status, data) = treasury.call{value: globalFee - operatorFee}(\\\"\\\");\\n if (status == false) {\\n revert FeeRecipientReceiveError(data);\\n }\\n }\\n if (operatorFee > 0) {\\n (status, data) = operator.call{value: operatorFee}(\\\"\\\");\\n if (status == false) {\\n revert TreasuryReceiveError(data);\\n }\\n }\\n emit Withdrawal(\\n withdrawer,\\n operator,\\n _publicKeyRoot,\\n balance - globalFee,\\n operatorFee,\\n globalFee - operatorFee\\n );\\n }\\n\\n /// @notice Retrieve the staking contract address\\n function getStakingContract() external view returns (address) {\\n return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();\\n }\\n\\n /// @notice Retrieve the assigned withdrawer for the given public key root\\n /// @param _publicKeyRoot Public key root to get the owner\\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {\\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\\n );\\n return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\\n }\\n\\n receive() external payable {\\n revert InvalidCall();\\n }\\n\\n fallback() external payable {\\n revert InvalidCall();\\n }\\n}\\n\",\"keccak256\":\"0x89c772651ce9f5f92fd12c1328a4f3b4121aa9284f299f243696bfc9d17edd0b\",\"license\":\"BUSL-1.1\"},\"src/contracts/interfaces/IFeeDispatcher.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IFeeDispatcher {\\n function dispatch(bytes32 _publicKeyRoot) external payable;\\n\\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address);\\n}\\n\",\"keccak256\":\"0x75efa5a697b32235188a62f730b7ab2a2fc5c422a93010aa0b18e93ea1bade45\",\"license\":\"MIT\"},\"src/contracts/interfaces/IStakingContractFeeDetails.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IStakingContractFeeDetails {\\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address);\\n\\n function getTreasury() external view returns (address);\\n\\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address);\\n\\n function getGlobalFee() external view returns (uint256);\\n\\n function getOperatorFee() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xa3f0dccf7edeb80f5d9078fe2a62118a2b222f136b786aebd3cc6fa5499276a8\",\"license\":\"MIT\"},\"src/contracts/libs/DispatchersStorageLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary DispatchersStorageLib {\\n function getUint256(bytes32 position) internal view returns (uint256 data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setUint256(bytes32 position, uint256 data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n\\n function getAddress(bytes32 position) internal view returns (address data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setAddress(bytes32 position, address data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x585a11c0ae6f9fda70d5d242ce02336bfd60fd75afed28495156307ba944f6cc\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5060405161091138038061091183398101604081905261002f91610070565b610066817f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b161006c60201b6106c01790919060201c565b50610089565b9055565b60006020828403121561008257600080fd5b5051919050565b610879806100986000396000f3fe6080604052600436106100435760003560e01c8063068a8c8d1461007a57806327de90161461009c5780638e68dce4146100d8578063ce120650146100ed57610061565b366100615760405163574b16a760e11b815260040160405180910390fd5b60405163574b16a760e11b815260040160405180910390fd5b34801561008657600080fd5b5061009a6100953660046106dc565b610100565b005b3480156100a857600080fd5b506100bc6100b73660046106f9565b610197565b6040516001600160a01b03909116815260200160405180910390f35b3480156100e457600080fd5b506100bc610223565b61009a6100fb3660046106f9565b610240565b600161012a7f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b15490565b610135906001610728565b81146101535760405162dc149f60e41b815260040160405180910390fd5b61017c7f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b1829055565b610193600080516020610824833981519152839055565b5050565b6000806101b06000805160206108248339815191525490565b60405163a740080160e01b8152600481018590529091506001600160a01b0382169063a740080190602401602060405180830381865afa1580156101f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061021c9190610740565b9392505050565b600061023b6000805160206108248339815191525490565b905090565b47600081900361026357604051635b2b158560e11b815260040160405180910390fd5b600061027b6000805160206108248339815191525490565b60405163a740080160e01b8152600481018590529091506000906001600160a01b0383169063a740080190602401602060405180830381865afa1580156102c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ea9190610740565b604051634d6fc8f760e11b8152600481018690529091506000906001600160a01b03841690639adf91ee90602401602060405180830381865afa158015610335573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103599190610740565b90506000836001600160a01b0316633b19e84a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561039b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103bf9190610740565b90506000612710856001600160a01b0316631bcbfaba6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610404573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610428919061075d565b6104329088610776565b61043c9190610795565b90506000612710866001600160a01b031663286966086040518163ffffffff1660e01b8152600401602060405180830381865afa158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a5919061075d565b6104af9084610776565b6104b99190610795565b90506000806001600160a01b0387166104d2858b6107b7565b604051600081818185875af1925050503d806000811461050e576040519150601f19603f3d011682016040523d82523d6000602084013e610513565b606091505b509092509050811515600003610547578060405163ce13343d60e01b815260040161053e91906107ce565b60405180910390fd5b83156105cd576001600160a01b03851661056184866107b7565b604051600081818185875af1925050503d806000811461059d576040519150601f19603f3d011682016040523d82523d6000602084013e6105a2565b606091505b5090925090508115156000036105cd578060405163e5ea83e760e01b815260040161053e91906107ce565b821561064c576040516001600160a01b038716908490600081818185875af1925050503d806000811461061c576040519150601f19603f3d011682016040523d82523d6000602084013e610621565b606091505b50909250905081151560000361064c578060405163bc98622d60e01b815260040161053e91906107ce565b6001600160a01b038087169088167f570610cb78811f3a7f90d272791d0a5e71648fb7368280519fc5866e5184db1d8c610686888e6107b7565b87610691818b6107b7565b60408051948552602085019390935291830152606082015260800160405180910390a350505050505050505050565b9055565b6001600160a01b03811681146106d957600080fd5b50565b6000602082840312156106ee57600080fd5b813561021c816106c4565b60006020828403121561070b57600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561073b5761073b610712565b500190565b60006020828403121561075257600080fd5b815161021c816106c4565b60006020828403121561076f57600080fd5b5051919050565b600081600019048311821515161561079057610790610712565b500290565b6000826107b257634e487b7160e01b600052601260045260246000fd5b500490565b6000828210156107c9576107c9610712565b500390565b600060208083528351808285015260005b818110156107fb578581018301518582016040015282016107df565b8181111561080d576000604083870101525b50601f01601f191692909201604001939250505056feda87ab80a3be8afba92a2e1fa9eebe6df07c3e4f871642fcbd8b843ff0112511a26469706673582212203b1d6386025c5f4108dbe846462f38f34be3ef1564c6795ce41f6fc1ea4865fa64736f6c634300080d0033", + "deployedBytecode": "0x6080604052600436106100435760003560e01c8063068a8c8d1461007a57806327de90161461009c5780638e68dce4146100d8578063ce120650146100ed57610061565b366100615760405163574b16a760e11b815260040160405180910390fd5b60405163574b16a760e11b815260040160405180910390fd5b34801561008657600080fd5b5061009a6100953660046106dc565b610100565b005b3480156100a857600080fd5b506100bc6100b73660046106f9565b610197565b6040516001600160a01b03909116815260200160405180910390f35b3480156100e457600080fd5b506100bc610223565b61009a6100fb3660046106f9565b610240565b600161012a7f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b15490565b610135906001610728565b81146101535760405162dc149f60e41b815260040160405180910390fd5b61017c7f2a83e6f793b1db0be720b1fadaabc888b1b7e5af00b045d6d837e073182510b1829055565b610193600080516020610824833981519152839055565b5050565b6000806101b06000805160206108248339815191525490565b60405163a740080160e01b8152600481018590529091506001600160a01b0382169063a740080190602401602060405180830381865afa1580156101f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061021c9190610740565b9392505050565b600061023b6000805160206108248339815191525490565b905090565b47600081900361026357604051635b2b158560e11b815260040160405180910390fd5b600061027b6000805160206108248339815191525490565b60405163a740080160e01b8152600481018590529091506000906001600160a01b0383169063a740080190602401602060405180830381865afa1580156102c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ea9190610740565b604051634d6fc8f760e11b8152600481018690529091506000906001600160a01b03841690639adf91ee90602401602060405180830381865afa158015610335573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103599190610740565b90506000836001600160a01b0316633b19e84a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561039b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103bf9190610740565b90506000612710856001600160a01b0316631bcbfaba6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610404573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610428919061075d565b6104329088610776565b61043c9190610795565b90506000612710866001600160a01b031663286966086040518163ffffffff1660e01b8152600401602060405180830381865afa158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a5919061075d565b6104af9084610776565b6104b99190610795565b90506000806001600160a01b0387166104d2858b6107b7565b604051600081818185875af1925050503d806000811461050e576040519150601f19603f3d011682016040523d82523d6000602084013e610513565b606091505b509092509050811515600003610547578060405163ce13343d60e01b815260040161053e91906107ce565b60405180910390fd5b83156105cd576001600160a01b03851661056184866107b7565b604051600081818185875af1925050503d806000811461059d576040519150601f19603f3d011682016040523d82523d6000602084013e6105a2565b606091505b5090925090508115156000036105cd578060405163e5ea83e760e01b815260040161053e91906107ce565b821561064c576040516001600160a01b038716908490600081818185875af1925050503d806000811461061c576040519150601f19603f3d011682016040523d82523d6000602084013e610621565b606091505b50909250905081151560000361064c578060405163bc98622d60e01b815260040161053e91906107ce565b6001600160a01b038087169088167f570610cb78811f3a7f90d272791d0a5e71648fb7368280519fc5866e5184db1d8c610686888e6107b7565b87610691818b6107b7565b60408051948552602085019390935291830152606082015260800160405180910390a350505050505050505050565b9055565b6001600160a01b03811681146106d957600080fd5b50565b6000602082840312156106ee57600080fd5b813561021c816106c4565b60006020828403121561070b57600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561073b5761073b610712565b500190565b60006020828403121561075257600080fd5b815161021c816106c4565b60006020828403121561076f57600080fd5b5051919050565b600081600019048311821515161561079057610790610712565b500290565b6000826107b257634e487b7160e01b600052601260045260246000fd5b500490565b6000828210156107c9576107c9610712565b500390565b600060208083528351808285015260005b818110156107fb578581018301518582016040015282016107df565b8181111561080d576000604083870101525b50601f01601f191692909201604001939250505056feda87ab80a3be8afba92a2e1fa9eebe6df07c3e4f871642fcbd8b843ff0112511a26469706673582212203b1d6386025c5f4108dbe846462f38f34be3ef1564c6795ce41f6fc1ea4865fa64736f6c634300080d0033", "devdoc": { "author": "Kiln", "kind": "dev", diff --git a/deployments/goerli_live/ExecutionLayerFeeDispatcher_Proxy.json b/deployments/goerli_live/ExecutionLayerFeeDispatcher_Proxy.json index abef79b..b57b029 100644 --- a/deployments/goerli_live/ExecutionLayerFeeDispatcher_Proxy.json +++ b/deployments/goerli_live/ExecutionLayerFeeDispatcher_Proxy.json @@ -1,5 +1,5 @@ { - "address": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", + "address": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", "abi": [ { "inputs": [ @@ -178,52 +178,52 @@ "type": "receive" } ], - "transactionHash": "0xd688d6d9ac63c5b350d3c6f9ea659a5f1b56aafe90c38c3932cc692d13118f76", + "transactionHash": "0xcc7aec91f3315d10cff8aa0e4916c1c82df0b96433065d2fdfefac3ff7e2552d", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", - "transactionIndex": 35, - "gasUsed": "731304", - "logsBloom": "0x00000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000800000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000080000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000004000000000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000800010000000000000000000000000000000000000", - "blockHash": "0xbfd9f12ddc67697553404033ffc5ede9c68126c785481605b3196619f54d6de4", - "transactionHash": "0xd688d6d9ac63c5b350d3c6f9ea659a5f1b56aafe90c38c3932cc692d13118f76", + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", + "transactionIndex": 26, + "gasUsed": "731316", + "logsBloom": "0x00000000000000000000000000000000400000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000080000000000000000000000000000000000000008000000000000000000000000800000000000420000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000400000000000000000000000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x426ca3d6533ffbf684d4f584cc8a43ae24e7fcc0ad7482adfe27fe08e2638d5f", + "transactionHash": "0xcc7aec91f3315d10cff8aa0e4916c1c82df0b96433065d2fdfefac3ff7e2552d", "logs": [ { - "transactionIndex": 35, - "blockNumber": 7476025, - "transactionHash": "0xd688d6d9ac63c5b350d3c6f9ea659a5f1b56aafe90c38c3932cc692d13118f76", - "address": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", + "transactionIndex": 26, + "blockNumber": 7633617, + "transactionHash": "0xcc7aec91f3315d10cff8aa0e4916c1c82df0b96433065d2fdfefac3ff7e2552d", + "address": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", "topics": [ "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", - "0x000000000000000000000000d68ba9327a3e2b1b173ed31bc882e7e70b461fed" + "0x000000000000000000000000a69ddebd0b6893a6f3d34a5df610d0e2ed433d18" ], "data": "0x", - "logIndex": 85, - "blockHash": "0xbfd9f12ddc67697553404033ffc5ede9c68126c785481605b3196619f54d6de4" + "logIndex": 37, + "blockHash": "0x426ca3d6533ffbf684d4f584cc8a43ae24e7fcc0ad7482adfe27fe08e2638d5f" }, { - "transactionIndex": 35, - "blockNumber": 7476025, - "transactionHash": "0xd688d6d9ac63c5b350d3c6f9ea659a5f1b56aafe90c38c3932cc692d13118f76", - "address": "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", + "transactionIndex": 26, + "blockNumber": 7633617, + "transactionHash": "0xcc7aec91f3315d10cff8aa0e4916c1c82df0b96433065d2fdfefac3ff7e2552d", + "address": "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", "topics": [ "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f" ], "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b9b2c07eff60ac828117c997e04c61890ad2ed7", - "logIndex": 86, - "blockHash": "0xbfd9f12ddc67697553404033ffc5ede9c68126c785481605b3196619f54d6de4" + "logIndex": 38, + "blockHash": "0x426ca3d6533ffbf684d4f584cc8a43ae24e7fcc0ad7482adfe27fe08e2638d5f" } ], - "blockNumber": 7476025, - "cumulativeGasUsed": "9116243", + "blockNumber": 7633617, + "cumulativeGasUsed": "6720363", "status": 1, "byzantium": true }, "args": [ - "0xd68bA9327a3E2B1b173Ed31Bc882e7E70b461Fed", + "0xa69dDEBd0B6893A6F3d34A5df610d0E2ED433D18", "0x3B9B2C07eff60aC828117C997E04c61890Ad2Ed7", - "0x068a8c8d000000000000000000000000fabff6e6f6ed3e602b2257008ea3ce1ec3539af9" + "0x068a8c8d000000000000000000000000e8ff2a04837aac535199eecb5ece52b2735b3543" ], "numDeployments": 1, "solcInputHash": "8fad9248104c7377e7ee874218595b1c", diff --git a/deployments/goerli_live/FeeRecipient.json b/deployments/goerli_live/FeeRecipient.json index fd2cf58..80bde56 100644 --- a/deployments/goerli_live/FeeRecipient.json +++ b/deployments/goerli_live/FeeRecipient.json @@ -1,5 +1,5 @@ { - "address": "0x8909BEE5B1CB83c42e7ff192e9dA34074104a4bb", + "address": "0x1AcD717aDF8A3A1e4c23C6510cfbE76834E3f1bf", "abi": [ { "inputs": [], @@ -66,25 +66,25 @@ "type": "receive" } ], - "transactionHash": "0xf784ad9fc020e9e0f81c885d1a4c75fca0e2fe69e56d09e9172fab943945a321", + "transactionHash": "0x754771f42a1630e0c925de6df4e229748be458f28b55599612a114c9eef650e9", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0x8909BEE5B1CB83c42e7ff192e9dA34074104a4bb", - "transactionIndex": 82, + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0x1AcD717aDF8A3A1e4c23C6510cfbE76834E3f1bf", + "transactionIndex": 38, "gasUsed": "198883", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x6700d7b6f417a152108895ed3350ee106cc0a36fe6fb75be399c74c51050ad5e", - "transactionHash": "0xf784ad9fc020e9e0f81c885d1a4c75fca0e2fe69e56d09e9172fab943945a321", + "blockHash": "0x890d43d23b9f5d50ec248b67a5ee6325a04a3a6f1a0fb6fe2e8caa1250c91e04", + "transactionHash": "0x754771f42a1630e0c925de6df4e229748be458f28b55599612a114c9eef650e9", "logs": [], - "blockNumber": 7476021, - "cumulativeGasUsed": "15108933", + "blockNumber": 7633611, + "cumulativeGasUsed": "9753281", "status": 1, "byzantium": true }, "args": [], "numDeployments": 1, - "solcInputHash": "721f6bc7fc7142905e230dbfd85db3e8", + "solcInputHash": "7c01cac1856570acc6f28ecd3fd2c735", "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"getPublicKeyRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWithdrawer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_dispatcher\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"_publicKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"init(address,bytes32)\":{\"params\":{\"_dispatcher\":\"Address that will handle the fee dispatching\",\"_publicKeyRoot\":\"Public Key root assigned to this receiver\"}},\"withdraw()\":{\"details\":\"Can be called by any wallet as recipients are not parameters\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getPublicKeyRoot()\":{\"notice\":\"Retrieve the assigned public key root\"},\"getWithdrawer()\":{\"notice\":\"retrieve the assigned withdrawer\"},\"init(address,bytes32)\":{\"notice\":\"Initializes the receiver\"},\"withdraw()\":{\"notice\":\"Triggers a withdrawal by sending its funds + its public key root to the dispatcher\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/contracts/FeeRecipient.sol\":\"FeeRecipient\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/contracts/FeeRecipient.sol\":{\"content\":\"//SPDX-License-Identifier: BUSL-1.1\\npragma solidity >=0.8.10;\\n\\nimport \\\"./interfaces/IFeeDispatcher.sol\\\";\\n\\ncontract FeeRecipient {\\n /// @notice Constructor replay prevention\\n bool internal initialized;\\n /// @notice Address where funds are sent to be dispatched\\n IFeeDispatcher internal dispatcher;\\n /// @notice Public Key root assigned to this receiver\\n bytes32 internal publicKeyRoot;\\n\\n error AlreadyInitialized();\\n\\n /// @notice Initializes the receiver\\n /// @param _dispatcher Address that will handle the fee dispatching\\n /// @param _publicKeyRoot Public Key root assigned to this receiver\\n function init(address _dispatcher, bytes32 _publicKeyRoot) external {\\n if (initialized) {\\n revert AlreadyInitialized();\\n }\\n initialized = true;\\n dispatcher = IFeeDispatcher(_dispatcher);\\n publicKeyRoot = _publicKeyRoot;\\n }\\n\\n /// @notice Empty calldata fallback\\n receive() external payable {}\\n\\n /// @notice Non-empty calldata fallback\\n fallback() external payable {}\\n\\n /// @notice Triggers a withdrawal by sending its funds + its public key root to the dispatcher\\n /// @dev Can be called by any wallet as recipients are not parameters\\n function withdraw() external {\\n dispatcher.dispatch{value: address(this).balance}(publicKeyRoot);\\n }\\n\\n /// @notice Retrieve the assigned public key root\\n function getPublicKeyRoot() external view returns (bytes32) {\\n return publicKeyRoot;\\n }\\n\\n /// @notice retrieve the assigned withdrawer\\n function getWithdrawer() external view returns (address) {\\n return dispatcher.getWithdrawer(publicKeyRoot);\\n }\\n}\\n\",\"keccak256\":\"0xf788bf2e0e2112b0322904479f0704ac8fb23601f760326fec7f564ec0101090\",\"license\":\"BUSL-1.1\"},\"src/contracts/interfaces/IFeeDispatcher.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IFeeDispatcher {\\n function dispatch(bytes32 _publicKeyRoot) external payable;\\n\\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address);\\n}\\n\",\"keccak256\":\"0x75efa5a697b32235188a62f730b7ab2a2fc5c422a93010aa0b18e93ea1bade45\",\"license\":\"MIT\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506102a3806100206000396000f3fe6080604052600436106100405760003560e01c80632cc0b254146100495780633ccfd60b146100695780637d38d21f1461007e5780637f763702146100b057005b3661004757005b005b34801561005557600080fd5b5061004761006436600461021d565b6100ce565b34801561007557600080fd5b50610047610120565b34801561008a57600080fd5b5061009361018a565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100bc57600080fd5b506001546040519081526020016100a7565b60005460ff16156100f15760405162dc149f60e41b815260040160405180910390fd5b600080546001600160a01b03909316610100026001600160a81b03199093169290921760019081179092559055565b600054600154604051630ce1206560e41b815260048101919091526101009091046001600160a01b03169063ce1206509047906024016000604051808303818588803b15801561016f57600080fd5b505af1158015610183573d6000803e3d6000fd5b5050505050565b600080546001546040516313ef480b60e11b815260048101919091526101009091046001600160a01b0316906327de901690602401602060405180830381865afa1580156101dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102009190610249565b905090565b6001600160a01b038116811461021a57600080fd5b50565b6000806040838503121561023057600080fd5b823561023b81610205565b946020939093013593505050565b60006020828403121561025b57600080fd5b815161026681610205565b939250505056fea26469706673582212208eb3032a325d9c07889449598ba3999e3438d216376d0fb3031dbfbf383d522964736f6c634300080d0033", "deployedBytecode": "0x6080604052600436106100405760003560e01c80632cc0b254146100495780633ccfd60b146100695780637d38d21f1461007e5780637f763702146100b057005b3661004757005b005b34801561005557600080fd5b5061004761006436600461021d565b6100ce565b34801561007557600080fd5b50610047610120565b34801561008a57600080fd5b5061009361018a565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100bc57600080fd5b506001546040519081526020016100a7565b60005460ff16156100f15760405162dc149f60e41b815260040160405180910390fd5b600080546001600160a01b03909316610100026001600160a81b03199093169290921760019081179092559055565b600054600154604051630ce1206560e41b815260048101919091526101009091046001600160a01b03169063ce1206509047906024016000604051808303818588803b15801561016f57600080fd5b505af1158015610183573d6000803e3d6000fd5b5050505050565b600080546001546040516313ef480b60e11b815260048101919091526101009091046001600160a01b0316906327de901690602401602060405180830381865afa1580156101dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102009190610249565b905090565b6001600160a01b038116811461021a57600080fd5b50565b6000806040838503121561023057600080fd5b823561023b81610205565b946020939093013593505050565b60006020828403121561025b57600080fd5b815161026681610205565b939250505056fea26469706673582212208eb3032a325d9c07889449598ba3999e3438d216376d0fb3031dbfbf383d522964736f6c634300080d0033", @@ -124,7 +124,7 @@ "storageLayout": { "storage": [ { - "astId": 491, + "astId": 496, "contract": "src/contracts/FeeRecipient.sol:FeeRecipient", "label": "initialized", "offset": 0, @@ -132,15 +132,15 @@ "type": "t_bool" }, { - "astId": 495, + "astId": 500, "contract": "src/contracts/FeeRecipient.sol:FeeRecipient", "label": "dispatcher", "offset": 1, "slot": "0", - "type": "t_contract(IFeeDispatcher)593" + "type": "t_contract(IFeeDispatcher)598" }, { - "astId": 498, + "astId": 503, "contract": "src/contracts/FeeRecipient.sol:FeeRecipient", "label": "publicKeyRoot", "offset": 0, @@ -159,7 +159,7 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_contract(IFeeDispatcher)593": { + "t_contract(IFeeDispatcher)598": { "encoding": "inplace", "label": "contract IFeeDispatcher", "numberOfBytes": "20" diff --git a/deployments/goerli_live/StakingContract.json b/deployments/goerli_live/StakingContract.json index e21d2c3..7abb93b 100644 --- a/deployments/goerli_live/StakingContract.json +++ b/deployments/goerli_live/StakingContract.json @@ -1,5 +1,5 @@ { - "address": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9", + "address": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543", "abi": [ { "inputs": [], @@ -182,6 +182,11 @@ "name": "DuplicateValidatorKey", "type": "error" }, + { + "inputs": [], + "name": "Forbidden", + "type": "error" + }, { "inputs": [], "name": "FundedValidatorDeletionAttempt", @@ -263,6 +268,147 @@ "name": "UnsortedIndexes", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_operatorIndex", + "type": "uint256" + } + ], + "name": "ActivatedOperator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "ChangedAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newGlobalFee", + "type": "uint256" + } + ], + "name": "ChangedGlobalFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "operatorIndex", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "operatorAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "feeRecipientAddress", + "type": "address" + } + ], + "name": "ChangedOperatorAddresses", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newOperatorFee", + "type": "uint256" + } + ], + "name": "ChangedOperatorFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "operatorIndex", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "ChangedOperatorLimit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newTreasury", + "type": "address" + } + ], + "name": "ChangedTreasury", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "newWithdrawer", + "type": "address" + } + ], + "name": "ChangedWithdrawer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_operatorIndex", + "type": "uint256" + } + ], + "name": "DeactivatedOperator", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -283,11 +429,55 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "signature", + "type": "bytes" } ], "name": "Deposit", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "operatorAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "feeRecipientAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "NewOperator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "SetWithdrawerCustomizationStatus", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -321,6 +511,12 @@ "internalType": "bytes", "name": "publicKeys", "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "signatures", + "type": "bytes" } ], "name": "ValidatorKeysAdded", @@ -892,6 +1088,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_enabled", + "type": "bool" + } + ], + "name": "setWithdrawerCustomizationEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -966,52 +1175,52 @@ "type": "constructor" } ], - "transactionHash": "0x68f55b5e08089000625fef7b009a4f752aaae649c0a380397841227a96c5f718", + "transactionHash": "0x4fe4f74d8e46b177403b71e8119c8d90f598d30b9ec690945d71e44eb5ac96f1", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9", - "transactionIndex": 33, + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543", + "transactionIndex": 16, "gasUsed": "890236", - "logsBloom": "0x00000000000000000000000000000000400000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000010000000000000000080400000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x7ef4cd037726387dd9593e2c2745150e96a5a5424b68f1dc96c6a6e2b05ac2d7", - "transactionHash": "0x68f55b5e08089000625fef7b009a4f752aaae649c0a380397841227a96c5f718", + "logsBloom": "0x00000000000000000000000000000000400000080000000000000000000000000000000000000000000000000000000000040040000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000008000000000001000000000000000000000800000000000000000000000000001000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xc7a4c9cc122115baefe04a46acea0372c92e09afb32e3bda3b3810361dd69fef", + "transactionHash": "0x4fe4f74d8e46b177403b71e8119c8d90f598d30b9ec690945d71e44eb5ac96f1", "logs": [ { - "transactionIndex": 33, - "blockNumber": 7476027, - "transactionHash": "0x68f55b5e08089000625fef7b009a4f752aaae649c0a380397841227a96c5f718", - "address": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9", + "transactionIndex": 16, + "blockNumber": 7633620, + "transactionHash": "0x4fe4f74d8e46b177403b71e8119c8d90f598d30b9ec690945d71e44eb5ac96f1", + "address": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543", "topics": [ "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", - "0x000000000000000000000000e8129e75a5324d7c95aa36dd4babf4fed825f5c3" + "0x0000000000000000000000007f14a8048de0c3baae292177aa8b8fe55b32e704" ], "data": "0x", - "logIndex": 99, - "blockHash": "0x7ef4cd037726387dd9593e2c2745150e96a5a5424b68f1dc96c6a6e2b05ac2d7" + "logIndex": 20, + "blockHash": "0xc7a4c9cc122115baefe04a46acea0372c92e09afb32e3bda3b3810361dd69fef" }, { - "transactionIndex": 33, - "blockNumber": 7476027, - "transactionHash": "0x68f55b5e08089000625fef7b009a4f752aaae649c0a380397841227a96c5f718", - "address": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9", + "transactionIndex": 16, + "blockNumber": 7633620, + "transactionHash": "0x4fe4f74d8e46b177403b71e8119c8d90f598d30b9ec690945d71e44eb5ac96f1", + "address": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543", "topics": [ "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f" ], "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b9b2c07eff60ac828117c997e04c61890ad2ed7", - "logIndex": 100, - "blockHash": "0x7ef4cd037726387dd9593e2c2745150e96a5a5424b68f1dc96c6a6e2b05ac2d7" + "logIndex": 21, + "blockHash": "0xc7a4c9cc122115baefe04a46acea0372c92e09afb32e3bda3b3810361dd69fef" } ], - "blockNumber": 7476027, - "cumulativeGasUsed": "10422347", + "blockNumber": 7633620, + "cumulativeGasUsed": "5292552", "status": 1, "byzantium": true }, "args": [ - "0xe8129e75a5324D7C95Aa36Dd4BaBF4fed825f5c3", + "0x7f14a8048De0c3BaAe292177Aa8b8fe55b32E704", "0x3B9B2C07eff60aC828117C997E04c61890Ad2Ed7", - "0x08b3a073000000000000000000000000c4b8469165d0a0e0939500bdece7c0cd3415a9fb0000000000000000000000005137b5540730d44326fbb237184425a9fb311ddf000000000000000000000000ff50ed3d0ec03ac01d4c79aad74928bff48a7b2b000000000000000000000000800e3f26134488f6d28dda1af6870dbf70790aa30000000000000000000000008daa332f78e9261969cdab643f057608dbe711210000000000000000000000008909bee5b1cb83c42e7ff192e9da34074104a4bb00000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d0" + "0x08b3a073000000000000000000000000c4b8469165d0a0e0939500bdece7c0cd3415a9fb0000000000000000000000005137b5540730d44326fbb237184425a9fb311ddf000000000000000000000000ff50ed3d0ec03ac01d4c79aad74928bff48a7b2b000000000000000000000000639d818639b85a1892bfbb40bd724b4ddea43c0c00000000000000000000000050dba42662fd69f5fd9236540aad9f99f7f6b3b20000000000000000000000001acd717adf8a3a1e4c23c6510cfbe76834e3f1bf00000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d0" ], "numDeployments": 1, "solcInputHash": "8fad9248104c7377e7ee874218595b1c", @@ -1024,14 +1233,14 @@ "0xC4b8469165d0A0e0939500BdeCE7c0CD3415a9fb", "0x5137B5540730d44326fBb237184425A9FB311DdF", "0xff50ed3d0ec03aC01D4C79aAd74928BFF48a7b2b", - "0x800E3F26134488f6d28DDA1Af6870dbF70790aa3", - "0x8DAA332F78e9261969cdAB643F057608Dbe71121", - "0x8909BEE5B1CB83c42e7ff192e9dA34074104a4bb", + "0x639d818639B85a1892Bfbb40Bd724b4Ddea43C0C", + "0x50Dba42662FD69f5Fd9236540aaD9f99f7F6b3b2", + "0x1AcD717aDF8A3A1e4c23C6510cfbE76834E3f1bf", 1000, 2000 ] }, - "implementation": "0xe8129e75a5324D7C95Aa36Dd4BaBF4fed825f5c3", + "implementation": "0x7f14a8048De0c3BaAe292177Aa8b8fe55b32E704", "devdoc": { "author": "SkillZ", "kind": "dev", diff --git a/deployments/goerli_live/StakingContract_Implementation.json b/deployments/goerli_live/StakingContract_Implementation.json index 0ab089c..f412848 100644 --- a/deployments/goerli_live/StakingContract_Implementation.json +++ b/deployments/goerli_live/StakingContract_Implementation.json @@ -1,5 +1,5 @@ { - "address": "0xe8129e75a5324D7C95Aa36Dd4BaBF4fed825f5c3", + "address": "0x7f14a8048De0c3BaAe292177Aa8b8fe55b32E704", "abi": [ { "inputs": [], @@ -27,6 +27,11 @@ "name": "DuplicateValidatorKey", "type": "error" }, + { + "inputs": [], + "name": "Forbidden", + "type": "error" + }, { "inputs": [], "name": "FundedValidatorDeletionAttempt", @@ -108,6 +113,147 @@ "name": "UnsortedIndexes", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_operatorIndex", + "type": "uint256" + } + ], + "name": "ActivatedOperator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "ChangedAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newGlobalFee", + "type": "uint256" + } + ], + "name": "ChangedGlobalFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "operatorIndex", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "operatorAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "feeRecipientAddress", + "type": "address" + } + ], + "name": "ChangedOperatorAddresses", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newOperatorFee", + "type": "uint256" + } + ], + "name": "ChangedOperatorFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "operatorIndex", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "ChangedOperatorLimit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newTreasury", + "type": "address" + } + ], + "name": "ChangedTreasury", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "newWithdrawer", + "type": "address" + } + ], + "name": "ChangedWithdrawer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_operatorIndex", + "type": "uint256" + } + ], + "name": "DeactivatedOperator", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -128,11 +274,55 @@ "internalType": "bytes", "name": "publicKey", "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "signature", + "type": "bytes" } ], "name": "Deposit", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "operatorAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "feeRecipientAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "NewOperator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "SetWithdrawerCustomizationStatus", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -166,6 +356,12 @@ "internalType": "bytes", "name": "publicKeys", "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "signatures", + "type": "bytes" } ], "name": "ValidatorKeysAdded", @@ -741,6 +937,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_enabled", + "type": "bool" + } + ], + "name": "setWithdrawerCustomizationEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -798,28 +1007,28 @@ "type": "receive" } ], - "transactionHash": "0x2f9ddc88c20d9de1652194a4b48e1c3b0798f0874c09f5041ef2146dad479684", + "transactionHash": "0x0598da1ceea362cb8ff58f69918133b0c0ccb6e79815fac24e7864a2824e43dc", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0xe8129e75a5324D7C95Aa36Dd4BaBF4fed825f5c3", - "transactionIndex": 24, - "gasUsed": "4458934", + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0x7f14a8048De0c3BaAe292177Aa8b8fe55b32E704", + "transactionIndex": 26, + "gasUsed": "4780001", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x913a899c46736a0a4a904d6541082598b2421fa57f8f1ffa7976db33fc9a836f", - "transactionHash": "0x2f9ddc88c20d9de1652194a4b48e1c3b0798f0874c09f5041ef2146dad479684", + "blockHash": "0xe32067bab944ca328122719244e456d051c8e7ca0285a384b0bc60869e168801", + "transactionHash": "0x0598da1ceea362cb8ff58f69918133b0c0ccb6e79815fac24e7864a2824e43dc", "logs": [], - "blockNumber": 7476026, - "cumulativeGasUsed": "6204013", + "blockNumber": 7633619, + "cumulativeGasUsed": "9601088", "status": 1, "byzantium": true }, "args": [], "numDeployments": 1, - "solcInputHash": "9b429e318c7698f5c83d9f1f7ab2fb85", - "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Deactivated\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DepositFailure\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"DuplicateValidatorKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FundedValidatorDeletionAttempt\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidArgument\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDepositValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPublicKeys\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidValidatorCount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaximumOperatorCountAlreadyReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoOperators\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEnoughValidators\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"limit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"keyCount\",\"type\":\"uint256\"}],\"name\":\"OperatorLimitTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsortedIndexes\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"operatorIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"name\":\"ValidatorKeyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"operatorIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"publicKeys\",\"type\":\"bytes\"}],\"name\":\"ValidatorKeysAdded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"DEPOSIT_SIZE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PUBLIC_KEY_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SIGNATURE_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_newFeeRecipient\",\"type\":\"address\"}],\"name\":\"activateOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_operatorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeRecipientAddress\",\"type\":\"address\"}],\"name\":\"addOperator\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_keyCount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_publicKeys\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_signatures\",\"type\":\"bytes\"}],\"name\":\"addValidators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_temporaryFeeRecipient\",\"type\":\"address\"}],\"name\":\"deactivateOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAvailableValidatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"getCLFeeRecipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"getELFeeRecipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGlobalFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"}],\"name\":\"getOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"operatorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeRecipientAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"limit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"keys\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"funded\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"deactivated\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOperatorFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"pubKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"getOperatorFeeRecipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPendingAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTreasury\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_validatorIndex\",\"type\":\"uint256\"}],\"name\":\"getValidator\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"funded\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"getWithdrawer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_publicKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"getWithdrawerFromPublicKeyRoot\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_admin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_treasury\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_depositContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_elDispatcher\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_clDispatcher\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeRecipientImplementation\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_globalFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_operatorFee\",\"type\":\"uint256\"}],\"name\":\"initialize_1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_indexes\",\"type\":\"uint256[]\"}],\"name\":\"removeValidators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_globalFee\",\"type\":\"uint256\"}],\"name\":\"setGlobalFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_operatorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeRecipientAddress\",\"type\":\"address\"}],\"name\":\"setOperatorAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorFee\",\"type\":\"uint256\"}],\"name\":\"setOperatorFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_limit\",\"type\":\"uint256\"}],\"name\":\"setOperatorLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newTreasury\",\"type\":\"address\"}],\"name\":\"setTreasury\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"_newWithdrawer\",\"type\":\"address\"}],\"name\":\"setWithdrawer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newAdmin\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"withdrawCLFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"withdrawELFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Kiln\",\"kind\":\"dev\",\"methods\":{\"acceptOwnership()\":{\"details\":\"Only callable by new admin\"},\"activateOperator(uint256,address)\":{\"params\":{\"_newFeeRecipient\":\"Sets the fee recipient address\",\"_operatorIndex\":\"Operator Index\"}},\"addOperator(address,address)\":{\"details\":\"Only callable by admin\",\"params\":{\"_feeRecipientAddress\":\"Operator address used to manage rewards\",\"_operatorAddress\":\"Operator address allowed to add / remove validators\"}},\"addValidators(uint256,uint256,bytes,bytes)\":{\"details\":\"Only callable by operator\",\"params\":{\"_keyCount\":\"Number of keys added\",\"_operatorIndex\":\"Operator Index\",\"_publicKeys\":\"Concatenated _keyCount public keys\",\"_signatures\":\"Concatenated _keyCount signatures\"}},\"deactivateOperator(uint256,address)\":{\"params\":{\"_operatorIndex\":\"Operator Index\",\"_temporaryFeeRecipient\":\"Temporary address to receive funds decided by the system admin\"}},\"deposit()\":{\"details\":\"A multiple of 32 ETH should be sent\"},\"getCLFeeRecipient(bytes)\":{\"params\":{\"_publicKey\":\"Validator to get the recipient\"}},\"getELFeeRecipient(bytes)\":{\"params\":{\"_publicKey\":\"Validator to get the recipient\"}},\"getOperator(uint256)\":{\"params\":{\"_operatorIndex\":\"Operator index\"}},\"getValidator(uint256,uint256)\":{\"params\":{\"_operatorIndex\":\"Index of the operator running the validator\",\"_validatorIndex\":\"Index of the validator\"}},\"getWithdrawer(bytes)\":{\"params\":{\"_publicKey\":\"Public Key to check\"}},\"getWithdrawerFromPublicKeyRoot(bytes32)\":{\"params\":{\"_publicKeyRoot\":\"Hash of the public key\"}},\"removeValidators(uint256,uint256[])\":{\"details\":\"Only callable by operatorIndexes should be provided in decreasing orderThe limit will be set to the lowest removed operator index to ensure all changes above the lowest removed validator key are verified by the system administrator\",\"params\":{\"_indexes\":\"List of indexes to delete, in decreasing order\",\"_operatorIndex\":\"Operator Index\"}},\"setGlobalFee(uint256)\":{\"params\":{\"_globalFee\":\"Fee in Basis Point\"}},\"setOperatorAddresses(uint256,address,address)\":{\"details\":\"Only callable by fee recipient address manager\",\"params\":{\"_feeRecipientAddress\":\"New operator address for reward management\",\"_operatorAddress\":\"New operator address for operations management\",\"_operatorIndex\":\"Index of the operator to update\"}},\"setOperatorFee(uint256)\":{\"params\":{\"_operatorFee\":\"Fee in Basis Point\"}},\"setOperatorLimit(uint256,uint256)\":{\"details\":\"Only callable by adminLimit should not exceed the validator key count of the operatorKeys should be registered before limit is increasedAllows all keys to be verified by the system admin before limit is increased\",\"params\":{\"_limit\":\"New staking limit\",\"_operatorIndex\":\"Operator Index\"}},\"setTreasury(address)\":{\"details\":\"Only callable by admin\",\"params\":{\"_newTreasury\":\"New Treasury address\"}},\"setWithdrawer(bytes,address)\":{\"details\":\"Only callable by current public key withdrawer\",\"params\":{\"_newWithdrawer\":\"New withdrawer address\",\"_publicKey\":\"Public key to change withdrawer\"}},\"transferOwnership(address)\":{\"details\":\"Only callable by admin\",\"params\":{\"_newAdmin\":\"New Administrator address\"}},\"withdraw(bytes)\":{\"details\":\"Reverts if any is null\",\"params\":{\"_publicKey\":\"Validator to withdraw Execution and Consensus Layer Fees from\"}},\"withdrawCLFee(bytes)\":{\"details\":\"Funds are sent to the withdrawer accountThis method is public on purpose\",\"params\":{\"_publicKey\":\"Validator to withdraw Consensus Layer Fees from\"}},\"withdrawELFee(bytes)\":{\"details\":\"Funds are sent to the withdrawer accountThis method is public on purpose\",\"params\":{\"_publicKey\":\"Validator to withdraw Execution Layer Fees from\"}}},\"title\":\"Ethereum Staking Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"acceptOwnership()\":{\"notice\":\"New admin must accept its role by calling this method\"},\"activateOperator(uint256,address)\":{\"notice\":\"Activates an operator, without changing its 0 staking limit\"},\"addOperator(address,address)\":{\"notice\":\"Add new operator\"},\"addValidators(uint256,uint256,bytes,bytes)\":{\"notice\":\"Add new validator public keys and signatures\"},\"deactivateOperator(uint256,address)\":{\"notice\":\"Deactivates an operator and changes the fee recipient address and the staking limit\"},\"deposit()\":{\"notice\":\"Explicit deposit method using msg.sender\"},\"getAdmin()\":{\"notice\":\"Retrieve system admin\"},\"getAvailableValidatorCount()\":{\"notice\":\"Get the total available keys that are ready to be used for deposits\"},\"getCLFeeRecipient(bytes)\":{\"notice\":\"Compute the Consensus Layer Fee recipient address for a given validator public key\"},\"getELFeeRecipient(bytes)\":{\"notice\":\"Compute the Execution Layer Fee recipient address for a given validator public key\"},\"getGlobalFee()\":{\"notice\":\"Retrieve the global fee\"},\"getOperator(uint256)\":{\"notice\":\"Retrieve operator details\"},\"getOperatorFee()\":{\"notice\":\"Retrieve the operator fee\"},\"getOperatorFeeRecipient(bytes32)\":{\"notice\":\"Retrieve the Execution & Consensus Layer Fee operator recipient for a given public key\"},\"getPendingAdmin()\":{\"notice\":\"Get the new admin's address previously set for an ownership transfer\"},\"getTreasury()\":{\"notice\":\"Retrieve system treasury\"},\"getValidator(uint256,uint256)\":{\"notice\":\"Get details about a validator\"},\"getWithdrawer(bytes)\":{\"notice\":\"Retrieve withdrawer of public key\"},\"getWithdrawerFromPublicKeyRoot(bytes32)\":{\"notice\":\"Retrieve withdrawer of public key root\"},\"removeValidators(uint256,uint256[])\":{\"notice\":\"Remove unfunded validators\"},\"setGlobalFee(uint256)\":{\"notice\":\"Change the Global fee\"},\"setOperatorAddresses(uint256,address,address)\":{\"notice\":\"Set new operator addresses (operations and reward management)\"},\"setOperatorFee(uint256)\":{\"notice\":\"Change the Operator fee\"},\"setOperatorLimit(uint256,uint256)\":{\"notice\":\"Set operator staking limits\"},\"setTreasury(address)\":{\"notice\":\"Set new treasury\"},\"setWithdrawer(bytes,address)\":{\"notice\":\"Set withdrawer for public key\"},\"transferOwnership(address)\":{\"notice\":\"Set new admin\"},\"withdraw(bytes)\":{\"notice\":\"Withdraw both Consensus and Execution Layer Fee for a given validator public key\"},\"withdrawCLFee(bytes)\":{\"notice\":\"Withdraw the Consensus Layer Fee for a given validator public key\"},\"withdrawELFee(bytes)\":{\"notice\":\"Withdraw the Execution Layer Fee for a given validator public key\"}},\"notice\":\"You can use this contract to store validator keys and have users fund them and trigger deposits.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/contracts/StakingContract.sol\":\"StakingContract\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/proxy/Clones.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\\n * deploying minimal proxy contracts, also known as \\\"clones\\\".\\n *\\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\\n *\\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\\n * deterministic method.\\n *\\n * _Available since v3.4._\\n */\\nlibrary Clones {\\n /**\\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\\n *\\n * This function uses the create opcode, which should never revert.\\n */\\n function clone(address implementation) internal returns (address instance) {\\n assembly {\\n let ptr := mload(0x40)\\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\\n mstore(add(ptr, 0x14), shl(0x60, implementation))\\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\\n instance := create(0, ptr, 0x37)\\n }\\n require(instance != address(0), \\\"ERC1167: create failed\\\");\\n }\\n\\n /**\\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\\n *\\n * This function uses the create2 opcode and a `salt` to deterministically deploy\\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\\n * the clones cannot be deployed twice at the same address.\\n */\\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\\n assembly {\\n let ptr := mload(0x40)\\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\\n mstore(add(ptr, 0x14), shl(0x60, implementation))\\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\\n instance := create2(0, ptr, 0x37, salt)\\n }\\n require(instance != address(0), \\\"ERC1167: create2 failed\\\");\\n }\\n\\n /**\\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\\n */\\n function predictDeterministicAddress(\\n address implementation,\\n bytes32 salt,\\n address deployer\\n ) internal pure returns (address predicted) {\\n assembly {\\n let ptr := mload(0x40)\\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\\n mstore(add(ptr, 0x14), shl(0x60, implementation))\\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\\n mstore(add(ptr, 0x38), shl(0x60, deployer))\\n mstore(add(ptr, 0x4c), salt)\\n mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\\n predicted := keccak256(add(ptr, 0x37), 0x55)\\n }\\n }\\n\\n /**\\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\\n */\\n function predictDeterministicAddress(address implementation, bytes32 salt)\\n internal\\n view\\n returns (address predicted)\\n {\\n return predictDeterministicAddress(implementation, salt, address(this));\\n }\\n}\\n\",\"keccak256\":\"0x1cc0efb01cbf008b768fd7b334786a6e358809198bb7e67f1c530af4957c6a21\",\"license\":\"MIT\"},\"src/contracts/StakingContract.sol\":{\"content\":\"//SPDX-License-Identifier: BUSL-1.1\\npragma solidity >=0.8.10;\\n\\nimport \\\"./libs/UintLib.sol\\\";\\nimport \\\"./libs/BytesLib.sol\\\";\\nimport \\\"./interfaces/IFeeRecipient.sol\\\";\\nimport \\\"./interfaces/IDepositContract.sol\\\";\\nimport \\\"./libs/StakingContractStorageLib.sol\\\";\\nimport \\\"@openzeppelin/contracts/proxy/Clones.sol\\\";\\n\\n/// @title Ethereum Staking Contract\\n/// @author Kiln\\n/// @notice You can use this contract to store validator keys and have users fund them and trigger deposits.\\ncontract StakingContract {\\n using StakingContractStorageLib for bytes32;\\n\\n uint256 internal constant EXECUTION_LAYER_SALT_PREFIX = 0;\\n uint256 internal constant CONSENSUS_LAYER_SALT_PREFIX = 1;\\n uint256 public constant SIGNATURE_LENGTH = 96;\\n uint256 public constant PUBLIC_KEY_LENGTH = 48;\\n uint256 public constant DEPOSIT_SIZE = 32 ether;\\n uint256 internal constant BASIS_POINTS = 10_000;\\n\\n error Deactivated();\\n error NoOperators();\\n error InvalidCall();\\n error Unauthorized();\\n error InvalidFee();\\n error DepositFailure();\\n error InvalidArgument();\\n error UnsortedIndexes();\\n error InvalidPublicKeys();\\n error InvalidSignatures();\\n error AlreadyInitialized();\\n error InvalidDepositValue();\\n error NotEnoughValidators();\\n error InvalidValidatorCount();\\n error DuplicateValidatorKey(bytes);\\n error FundedValidatorDeletionAttempt();\\n error OperatorLimitTooHigh(uint256 limit, uint256 keyCount);\\n error MaximumOperatorCountAlreadyReached();\\n\\n struct ValidatorAllocationCache {\\n bool used;\\n uint8 operatorIndex;\\n uint32 funded;\\n uint32 toDeposit;\\n uint32 available;\\n }\\n\\n event Deposit(address indexed caller, address indexed withdrawer, bytes publicKey);\\n event ValidatorKeysAdded(uint256 indexed operatorIndex, bytes publicKeys);\\n event ValidatorKeyRemoved(uint256 indexed operatorIndex, bytes publicKey);\\n\\n /// @notice Ensures an initialisation call has been called only once per _version value\\n /// @param _version The current initialisation value\\n modifier init(uint256 _version) {\\n if (_version != StakingContractStorageLib.getVersion() + 1) {\\n revert AlreadyInitialized();\\n }\\n\\n StakingContractStorageLib.setVersion(_version);\\n _;\\n }\\n\\n /// @notice Ensures that the caller is the admin\\n modifier onlyAdmin() {\\n if (msg.sender != StakingContractStorageLib.getAdmin()) {\\n revert Unauthorized();\\n }\\n\\n _;\\n }\\n\\n /// @notice Ensures that the caller is the admin or the operator\\n modifier onlyActiveOperatorOrAdmin(uint256 _operatorIndex) {\\n if (msg.sender == StakingContractStorageLib.getAdmin()) {\\n _;\\n } else {\\n _onlyActiveOperator(_operatorIndex);\\n _;\\n }\\n }\\n\\n /// @notice Ensures that the caller is the admin\\n modifier onlyActiveOperator(uint256 _operatorIndex) {\\n _onlyActiveOperator(_operatorIndex);\\n _;\\n }\\n\\n /// @notice Ensures that the caller is the operator fee recipient\\n modifier onlyOperatorFeeRecipient(uint256 _operatorIndex) {\\n StakingContractStorageLib.OperatorInfo memory operatorInfo = StakingContractStorageLib.getOperators().value[\\n _operatorIndex\\n ];\\n\\n if (operatorInfo.deactivated) {\\n revert Deactivated();\\n }\\n\\n if (msg.sender != operatorInfo.feeRecipient) {\\n revert Unauthorized();\\n }\\n\\n _;\\n }\\n\\n /// @notice Explicit deposit method using msg.sender\\n /// @dev A multiple of 32 ETH should be sent\\n function deposit() external payable {\\n _deposit(msg.sender);\\n }\\n\\n /// @notice Implicit deposit method\\n /// @dev A multiple of 32 ETH should be sent\\n /// @dev The withdrawer is set to the message sender address\\n receive() external payable {\\n _deposit(msg.sender);\\n }\\n\\n /// @notice Fallback detection\\n /// @dev Fails on any call that fallbacks\\n fallback() external payable {\\n revert InvalidCall();\\n }\\n\\n function initialize_1(\\n address _admin,\\n address _treasury,\\n address _depositContract,\\n address _elDispatcher,\\n address _clDispatcher,\\n address _feeRecipientImplementation,\\n uint256 _globalFee,\\n uint256 _operatorFee\\n ) external init(1) {\\n StakingContractStorageLib.setAdmin(_admin);\\n StakingContractStorageLib.setTreasury(_treasury);\\n\\n if (_globalFee > BASIS_POINTS) {\\n revert InvalidFee();\\n }\\n StakingContractStorageLib.setGlobalFee(_globalFee);\\n if (_operatorFee > BASIS_POINTS) {\\n revert InvalidFee();\\n }\\n StakingContractStorageLib.setOperatorFee(_operatorFee);\\n\\n StakingContractStorageLib.setELDispatcher(_elDispatcher);\\n StakingContractStorageLib.setCLDispatcher(_clDispatcher);\\n StakingContractStorageLib.setDepositContract(_depositContract);\\n StakingContractStorageLib.setFeeRecipientImplementation(_feeRecipientImplementation);\\n }\\n\\n /// @notice Retrieve system admin\\n function getAdmin() external view returns (address) {\\n return StakingContractStorageLib.getAdmin();\\n }\\n\\n /// @notice Set new treasury\\n /// @dev Only callable by admin\\n /// @param _newTreasury New Treasury address\\n function setTreasury(address _newTreasury) external onlyAdmin {\\n return StakingContractStorageLib.setTreasury(_newTreasury);\\n }\\n\\n /// @notice Retrieve system treasury\\n function getTreasury() external view returns (address) {\\n return StakingContractStorageLib.getTreasury();\\n }\\n\\n /// @notice Retrieve the global fee\\n function getGlobalFee() external view returns (uint256) {\\n return StakingContractStorageLib.getGlobalFee();\\n }\\n\\n /// @notice Retrieve the operator fee\\n function getOperatorFee() external view returns (uint256) {\\n return StakingContractStorageLib.getOperatorFee();\\n }\\n\\n /// @notice Compute the Execution Layer Fee recipient address for a given validator public key\\n /// @param _publicKey Validator to get the recipient\\n function getELFeeRecipient(bytes calldata _publicKey) external view returns (address) {\\n return _getDeterministicReceiver(_publicKey, EXECUTION_LAYER_SALT_PREFIX);\\n }\\n\\n /// @notice Compute the Consensus Layer Fee recipient address for a given validator public key\\n /// @param _publicKey Validator to get the recipient\\n function getCLFeeRecipient(bytes calldata _publicKey) external view returns (address) {\\n return _getDeterministicReceiver(_publicKey, CONSENSUS_LAYER_SALT_PREFIX);\\n }\\n\\n /// @notice Retrieve the Execution & Consensus Layer Fee operator recipient for a given public key\\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address) {\\n return\\n StakingContractStorageLib\\n .getOperators()\\n .value[StakingContractStorageLib.getOperatorIndexPerValidator().value[pubKeyRoot].operatorIndex]\\n .feeRecipient;\\n }\\n\\n /// @notice Retrieve withdrawer of public key\\n /// @param _publicKey Public Key to check\\n function getWithdrawer(bytes calldata _publicKey) external view returns (address) {\\n return _getWithdrawer(_getPubKeyRoot(_publicKey));\\n }\\n\\n /// @notice Retrieve withdrawer of public key root\\n /// @param _publicKeyRoot Hash of the public key\\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address) {\\n return _getWithdrawer(_publicKeyRoot);\\n }\\n\\n /// @notice Retrieve operator details\\n /// @param _operatorIndex Operator index\\n function getOperator(uint256 _operatorIndex)\\n external\\n view\\n returns (\\n address operatorAddress,\\n address feeRecipientAddress,\\n uint256 limit,\\n uint256 keys,\\n uint256 funded,\\n uint256 available,\\n bool deactivated\\n )\\n {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n if (_operatorIndex < operators.value.length) {\\n StakingContractStorageLib.ValidatorsFundingInfo memory _operatorInfo = StakingContractStorageLib\\n .getValidatorsFundingInfo(_operatorIndex);\\n StakingContractStorageLib.OperatorInfo memory _operator = operators.value[_operatorIndex];\\n\\n (operatorAddress, feeRecipientAddress, limit, keys, deactivated) = (\\n _operator.operator,\\n _operator.feeRecipient,\\n _operator.limit,\\n _operator.publicKeys.length,\\n _operator.deactivated\\n );\\n (funded, available) = (_operatorInfo.funded, _operatorInfo.availableKeys);\\n }\\n }\\n\\n /// @notice Get details about a validator\\n /// @param _operatorIndex Index of the operator running the validator\\n /// @param _validatorIndex Index of the validator\\n function getValidator(uint256 _operatorIndex, uint256 _validatorIndex)\\n external\\n view\\n returns (\\n bytes memory publicKey,\\n bytes memory signature,\\n address withdrawer,\\n bool funded\\n )\\n {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n publicKey = operators.value[_operatorIndex].publicKeys[_validatorIndex];\\n signature = operators.value[_operatorIndex].signatures[_validatorIndex];\\n withdrawer = _getWithdrawer(_getPubKeyRoot(publicKey));\\n funded = _validatorIndex < StakingContractStorageLib.getValidatorsFundingInfo(_operatorIndex).funded;\\n }\\n\\n /// @notice Get the total available keys that are ready to be used for deposits\\n function getAvailableValidatorCount() external view returns (uint256) {\\n return StakingContractStorageLib.getTotalAvailableValidators();\\n }\\n\\n /// @notice Set new admin\\n /// @dev Only callable by admin\\n /// @param _newAdmin New Administrator address\\n function transferOwnership(address _newAdmin) external onlyAdmin {\\n StakingContractStorageLib.setPendingAdmin(_newAdmin);\\n }\\n\\n /// @notice New admin must accept its role by calling this method\\n /// @dev Only callable by new admin\\n function acceptOwnership() external {\\n address newAdmin = StakingContractStorageLib.getPendingAdmin();\\n\\n if (msg.sender != newAdmin) {\\n revert Unauthorized();\\n }\\n StakingContractStorageLib.setAdmin(newAdmin);\\n }\\n\\n /// @notice Get the new admin's address previously set for an ownership transfer\\n function getPendingAdmin() external view returns (address) {\\n return StakingContractStorageLib.getPendingAdmin();\\n }\\n\\n /// @notice Add new operator\\n /// @dev Only callable by admin\\n /// @param _operatorAddress Operator address allowed to add / remove validators\\n /// @param _feeRecipientAddress Operator address used to manage rewards\\n function addOperator(address _operatorAddress, address _feeRecipientAddress) external onlyAdmin returns (uint256) {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n StakingContractStorageLib.OperatorInfo memory newOperator;\\n\\n if (operators.value.length == 251) {\\n revert MaximumOperatorCountAlreadyReached();\\n }\\n newOperator.operator = _operatorAddress;\\n newOperator.feeRecipient = _feeRecipientAddress;\\n operators.value.push(newOperator);\\n return operators.value.length - 1;\\n }\\n\\n /// @notice Set new operator addresses (operations and reward management)\\n /// @dev Only callable by fee recipient address manager\\n /// @param _operatorIndex Index of the operator to update\\n /// @param _operatorAddress New operator address for operations management\\n /// @param _feeRecipientAddress New operator address for reward management\\n function setOperatorAddresses(\\n uint256 _operatorIndex,\\n address _operatorAddress,\\n address _feeRecipientAddress\\n ) external onlyOperatorFeeRecipient(_operatorIndex) {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n\\n operators.value[_operatorIndex].operator = _operatorAddress;\\n operators.value[_operatorIndex].feeRecipient = _feeRecipientAddress;\\n }\\n\\n /// @notice Set withdrawer for public key\\n /// @dev Only callable by current public key withdrawer\\n /// @param _publicKey Public key to change withdrawer\\n /// @param _newWithdrawer New withdrawer address\\n function setWithdrawer(bytes calldata _publicKey, address _newWithdrawer) external {\\n bytes32 pubkeyRoot = sha256(BytesLib.pad64(_publicKey));\\n StakingContractStorageLib.WithdrawersSlot storage withdrawers = StakingContractStorageLib.getWithdrawers();\\n\\n if (withdrawers.value[pubkeyRoot] != msg.sender) {\\n revert Unauthorized();\\n }\\n\\n withdrawers.value[pubkeyRoot] = _newWithdrawer;\\n }\\n\\n /// @notice Set operator staking limits\\n /// @dev Only callable by admin\\n /// @dev Limit should not exceed the validator key count of the operator\\n /// @dev Keys should be registered before limit is increased\\n /// @dev Allows all keys to be verified by the system admin before limit is increased\\n /// @param _operatorIndex Operator Index\\n /// @param _limit New staking limit\\n function setOperatorLimit(uint256 _operatorIndex, uint256 _limit) external onlyAdmin {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n if (operators.value[_operatorIndex].deactivated) {\\n revert Deactivated();\\n }\\n uint256 publicKeyCount = operators.value[_operatorIndex].publicKeys.length;\\n if (publicKeyCount < _limit) {\\n revert OperatorLimitTooHigh(_limit, publicKeyCount);\\n }\\n operators.value[_operatorIndex].limit = _limit;\\n _updateAvailableValidatorCount(_operatorIndex);\\n }\\n\\n /// @notice Deactivates an operator and changes the fee recipient address and the staking limit\\n /// @param _operatorIndex Operator Index\\n /// @param _temporaryFeeRecipient Temporary address to receive funds decided by the system admin\\n function deactivateOperator(uint256 _operatorIndex, address _temporaryFeeRecipient) external onlyAdmin {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n operators.value[_operatorIndex].limit = 0;\\n operators.value[_operatorIndex].deactivated = true;\\n operators.value[_operatorIndex].feeRecipient = _temporaryFeeRecipient;\\n _updateAvailableValidatorCount(_operatorIndex);\\n }\\n\\n /// @notice Activates an operator, without changing its 0 staking limit\\n /// @param _operatorIndex Operator Index\\n /// @param _newFeeRecipient Sets the fee recipient address\\n function activateOperator(uint256 _operatorIndex, address _newFeeRecipient) external onlyAdmin {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n operators.value[_operatorIndex].deactivated = false;\\n operators.value[_operatorIndex].feeRecipient = _newFeeRecipient;\\n }\\n\\n /// @notice Change the Operator fee\\n /// @param _operatorFee Fee in Basis Point\\n function setOperatorFee(uint256 _operatorFee) external onlyAdmin {\\n if (_operatorFee > BASIS_POINTS) {\\n revert InvalidFee();\\n }\\n StakingContractStorageLib.setOperatorFee(_operatorFee);\\n }\\n\\n /// @notice Change the Global fee\\n /// @param _globalFee Fee in Basis Point\\n function setGlobalFee(uint256 _globalFee) external onlyAdmin {\\n if (_globalFee > BASIS_POINTS) {\\n revert InvalidFee();\\n }\\n StakingContractStorageLib.setGlobalFee(_globalFee);\\n }\\n\\n /// @notice Add new validator public keys and signatures\\n /// @dev Only callable by operator\\n /// @param _operatorIndex Operator Index\\n /// @param _keyCount Number of keys added\\n /// @param _publicKeys Concatenated _keyCount public keys\\n /// @param _signatures Concatenated _keyCount signatures\\n function addValidators(\\n uint256 _operatorIndex,\\n uint256 _keyCount,\\n bytes calldata _publicKeys,\\n bytes calldata _signatures\\n ) external onlyActiveOperator(_operatorIndex) {\\n if (_keyCount == 0) {\\n revert InvalidArgument();\\n }\\n\\n if (_publicKeys.length % PUBLIC_KEY_LENGTH != 0 || _publicKeys.length / PUBLIC_KEY_LENGTH != _keyCount) {\\n revert InvalidPublicKeys();\\n }\\n\\n if (_signatures.length % SIGNATURE_LENGTH != 0 || _signatures.length / SIGNATURE_LENGTH != _keyCount) {\\n revert InvalidSignatures();\\n }\\n\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n StakingContractStorageLib.OperatorIndexPerValidatorSlot\\n storage operatorIndexPerValidator = StakingContractStorageLib.getOperatorIndexPerValidator();\\n\\n for (uint256 i; i < _keyCount; ) {\\n bytes memory publicKey = BytesLib.slice(_publicKeys, i * PUBLIC_KEY_LENGTH, PUBLIC_KEY_LENGTH);\\n bytes memory signature = BytesLib.slice(_signatures, i * SIGNATURE_LENGTH, SIGNATURE_LENGTH);\\n\\n operators.value[_operatorIndex].publicKeys.push(publicKey);\\n operators.value[_operatorIndex].signatures.push(signature);\\n\\n bytes32 pubKeyRoot = _getPubKeyRoot(publicKey);\\n\\n if (operatorIndexPerValidator.value[pubKeyRoot].enabled) {\\n revert DuplicateValidatorKey(publicKey);\\n }\\n\\n operatorIndexPerValidator.value[pubKeyRoot] = StakingContractStorageLib.OperatorIndex({\\n enabled: true,\\n operatorIndex: uint32(_operatorIndex)\\n });\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n emit ValidatorKeysAdded(_operatorIndex, _publicKeys);\\n\\n _updateAvailableValidatorCount(_operatorIndex);\\n }\\n\\n /// @notice Remove unfunded validators\\n /// @dev Only callable by operator\\n /// @dev Indexes should be provided in decreasing order\\n /// @dev The limit will be set to the lowest removed operator index to ensure all changes above the\\n /// lowest removed validator key are verified by the system administrator\\n /// @param _operatorIndex Operator Index\\n /// @param _indexes List of indexes to delete, in decreasing order\\n function removeValidators(uint256 _operatorIndex, uint256[] calldata _indexes)\\n external\\n onlyActiveOperatorOrAdmin(_operatorIndex)\\n {\\n if (_indexes.length == 0) {\\n revert InvalidArgument();\\n }\\n\\n StakingContractStorageLib.ValidatorsFundingInfo memory operatorInfo = StakingContractStorageLib\\n .getValidatorsFundingInfo(_operatorIndex);\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n\\n if (_indexes[_indexes.length - 1] < operatorInfo.funded) {\\n revert FundedValidatorDeletionAttempt();\\n }\\n for (uint256 i; i < _indexes.length; ) {\\n if (i > 0 && _indexes[i] >= _indexes[i - 1]) {\\n revert UnsortedIndexes();\\n }\\n\\n emit ValidatorKeyRemoved(_operatorIndex, operators.value[_operatorIndex].publicKeys[_indexes[i]]);\\n if (_indexes[i] == operators.value[_operatorIndex].publicKeys.length - 1) {\\n operators.value[_operatorIndex].publicKeys.pop();\\n operators.value[_operatorIndex].signatures.pop();\\n } else {\\n operators.value[_operatorIndex].publicKeys[_indexes[i]] = operators.value[_operatorIndex].publicKeys[\\n operators.value[_operatorIndex].publicKeys.length - 1\\n ];\\n operators.value[_operatorIndex].publicKeys.pop();\\n operators.value[_operatorIndex].signatures[_indexes[i]] = operators.value[_operatorIndex].signatures[\\n operators.value[_operatorIndex].signatures.length - 1\\n ];\\n operators.value[_operatorIndex].signatures.pop();\\n }\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n if (_indexes[_indexes.length - 1] < operators.value[_operatorIndex].limit) {\\n operators.value[_operatorIndex].limit = _indexes[_indexes.length - 1];\\n }\\n\\n _updateAvailableValidatorCount(_operatorIndex);\\n }\\n\\n /// @notice Withdraw the Execution Layer Fee for a given validator public key\\n /// @dev Funds are sent to the withdrawer account\\n /// @dev This method is public on purpose\\n /// @param _publicKey Validator to withdraw Execution Layer Fees from\\n function withdrawELFee(bytes calldata _publicKey) external {\\n _deployAndWithdraw(_publicKey, EXECUTION_LAYER_SALT_PREFIX, StakingContractStorageLib.getELDispatcher());\\n }\\n\\n /// @notice Withdraw the Consensus Layer Fee for a given validator public key\\n /// @dev Funds are sent to the withdrawer account\\n /// @dev This method is public on purpose\\n /// @param _publicKey Validator to withdraw Consensus Layer Fees from\\n function withdrawCLFee(bytes calldata _publicKey) external {\\n _deployAndWithdraw(_publicKey, CONSENSUS_LAYER_SALT_PREFIX, StakingContractStorageLib.getCLDispatcher());\\n }\\n\\n /// @notice Withdraw both Consensus and Execution Layer Fee for a given validator public key\\n /// @dev Reverts if any is null\\n /// @param _publicKey Validator to withdraw Execution and Consensus Layer Fees from\\n function withdraw(bytes calldata _publicKey) external {\\n _deployAndWithdraw(_publicKey, EXECUTION_LAYER_SALT_PREFIX, StakingContractStorageLib.getELDispatcher());\\n _deployAndWithdraw(_publicKey, CONSENSUS_LAYER_SALT_PREFIX, StakingContractStorageLib.getCLDispatcher());\\n }\\n\\n /// \\u2588\\u2588 \\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\n /// \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\n /// \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\n /// \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\n /// \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n\\n function _onlyActiveOperator(uint256 _operatorIndex) internal view {\\n StakingContractStorageLib.OperatorInfo memory operatorInfo = StakingContractStorageLib.getOperators().value[\\n _operatorIndex\\n ];\\n\\n if (operatorInfo.deactivated) {\\n revert Deactivated();\\n }\\n\\n if (msg.sender != operatorInfo.operator) {\\n revert Unauthorized();\\n }\\n }\\n\\n function _getPubKeyRoot(bytes memory _publicKey) internal pure returns (bytes32) {\\n return sha256(BytesLib.pad64(_publicKey));\\n }\\n\\n function _getWithdrawer(bytes32 _publicKeyRoot) internal view returns (address) {\\n return StakingContractStorageLib.getWithdrawers().value[_publicKeyRoot];\\n }\\n\\n function _updateAvailableValidatorCount(uint256 _operatorIndex) internal {\\n StakingContractStorageLib.ValidatorsFundingInfo memory validatorFundingInfo = StakingContractStorageLib\\n .getValidatorsFundingInfo(_operatorIndex);\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n\\n uint32 oldAvailableCount = validatorFundingInfo.availableKeys;\\n uint32 newAvailableCount = 0;\\n uint256 cap = _min(operators.value[_operatorIndex].limit, operators.value[_operatorIndex].publicKeys.length);\\n\\n if (cap <= validatorFundingInfo.funded) {\\n StakingContractStorageLib.setValidatorsFundingInfo(_operatorIndex, 0, validatorFundingInfo.funded);\\n } else {\\n newAvailableCount = uint32(cap - validatorFundingInfo.funded);\\n StakingContractStorageLib.setValidatorsFundingInfo(\\n _operatorIndex,\\n newAvailableCount,\\n validatorFundingInfo.funded\\n );\\n }\\n\\n if (oldAvailableCount != newAvailableCount) {\\n StakingContractStorageLib.setTotalAvailableValidators(\\n (StakingContractStorageLib.getTotalAvailableValidators() - oldAvailableCount) + newAvailableCount\\n );\\n }\\n }\\n\\n function _addressToWithdrawalCredentials(address _recipient) internal pure returns (bytes32) {\\n return\\n bytes32(uint256(uint160(_recipient)) + 0x0100000000000000000000000000000000000000000000000000000000000000);\\n }\\n\\n function _depositValidatorsOfOperator(\\n uint256 _operatorIndex,\\n uint256 _validatorCount,\\n address _withdrawer\\n ) internal {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n StakingContractStorageLib.OperatorInfo storage operator = operators.value[_operatorIndex];\\n StakingContractStorageLib.ValidatorsFundingInfo memory vfi = StakingContractStorageLib.getValidatorsFundingInfo(\\n _operatorIndex\\n );\\n\\n for (uint256 i = vfi.funded; i < vfi.funded + _validatorCount; ) {\\n bytes memory publicKey = operator.publicKeys[i];\\n bytes memory signature = operator.signatures[i];\\n address consensusLayerRecipient = _getDeterministicReceiver(publicKey, CONSENSUS_LAYER_SALT_PREFIX);\\n bytes32 withdrawalCredentials = _addressToWithdrawalCredentials(consensusLayerRecipient);\\n _depositValidator(publicKey, signature, withdrawalCredentials);\\n bytes32 pubkeyRoot = _getPubKeyRoot(publicKey);\\n StakingContractStorageLib.getWithdrawers().value[pubkeyRoot] = _withdrawer;\\n emit Deposit(msg.sender, _withdrawer, publicKey);\\n unchecked {\\n ++i;\\n }\\n }\\n\\n StakingContractStorageLib.setValidatorsFundingInfo(\\n _operatorIndex,\\n uint32(vfi.availableKeys - _validatorCount),\\n uint32(vfi.funded + _validatorCount)\\n );\\n }\\n\\n /// @notice Internal utility to deposit a public key, its signature and 32 ETH to the consensus layer\\n /// @param _publicKey The Public Key to deposit\\n /// @param _signature The Signature to deposit\\n /// @param _withdrawalCredentials The Withdrawal Credentials to deposit\\n function _depositValidator(\\n bytes memory _publicKey,\\n bytes memory _signature,\\n bytes32 _withdrawalCredentials\\n ) internal {\\n bytes32 pubkeyRoot = _getPubKeyRoot(_publicKey);\\n bytes32 signatureRoot = sha256(\\n abi.encodePacked(\\n sha256(BytesLib.slice(_signature, 0, 64)),\\n sha256(BytesLib.pad64(BytesLib.slice(_signature, 64, SIGNATURE_LENGTH - 64)))\\n )\\n );\\n\\n uint256 depositAmount = DEPOSIT_SIZE / 1000000000 wei;\\n assert(depositAmount * 1000000000 wei == DEPOSIT_SIZE);\\n\\n bytes32 depositDataRoot = sha256(\\n abi.encodePacked(\\n sha256(abi.encodePacked(pubkeyRoot, _withdrawalCredentials)),\\n sha256(abi.encodePacked(Uint256Lib.toLittleEndian64(depositAmount), signatureRoot))\\n )\\n );\\n\\n uint256 targetBalance = address(this).balance - DEPOSIT_SIZE;\\n\\n IDepositContract(StakingContractStorageLib.getDepositContract()).deposit{value: DEPOSIT_SIZE}(\\n _publicKey,\\n abi.encodePacked(_withdrawalCredentials),\\n _signature,\\n depositDataRoot\\n );\\n\\n if (address(this).balance != targetBalance) {\\n revert DepositFailure();\\n }\\n }\\n\\n function _depositOnOneOperator(\\n address _withdrawer,\\n uint256 _depositCount,\\n uint256 _totalAvailableValidators\\n ) internal {\\n _depositValidatorsOfOperator(0, _depositCount, _withdrawer);\\n StakingContractStorageLib.setTotalAvailableValidators(_totalAvailableValidators - _depositCount);\\n }\\n\\n function _depositOnTwoOperators(\\n address _withdrawer,\\n uint256 _depositCount,\\n uint256 _totalAvailableValidators\\n ) internal {\\n StakingContractStorageLib.ValidatorsFundingInfo memory oneOsi = StakingContractStorageLib\\n .getValidatorsFundingInfo(0);\\n StakingContractStorageLib.ValidatorsFundingInfo memory twoOsi = StakingContractStorageLib\\n .getValidatorsFundingInfo(1);\\n\\n uint256 oneDepositCount;\\n uint256 twoDepositCount;\\n\\n // using this tactic to prevent deposits of 1 validator to always go to operator 2\\n if (block.number % 2 == 0) {\\n oneDepositCount = _depositCount / 2;\\n twoDepositCount = _depositCount - oneDepositCount;\\n } else {\\n twoDepositCount = _depositCount / 2;\\n oneDepositCount = _depositCount - twoDepositCount;\\n }\\n\\n if (oneDepositCount > oneOsi.availableKeys) {\\n twoDepositCount = _depositCount - oneOsi.availableKeys;\\n oneDepositCount = oneOsi.availableKeys;\\n } else if (twoDepositCount > twoOsi.availableKeys) {\\n oneDepositCount = _depositCount - twoOsi.availableKeys;\\n twoDepositCount = twoOsi.availableKeys;\\n }\\n\\n if (oneDepositCount > 0) {\\n _depositValidatorsOfOperator(0, oneDepositCount, _withdrawer);\\n }\\n if (twoDepositCount > 0) {\\n _depositValidatorsOfOperator(1, twoDepositCount, _withdrawer);\\n }\\n StakingContractStorageLib.setTotalAvailableValidators(\\n _totalAvailableValidators - (oneDepositCount + twoDepositCount)\\n );\\n }\\n\\n function _getBaseSkip(\\n bytes32 blockHash,\\n uint256 index,\\n uint8 prime\\n ) internal pure returns (uint8 base, uint8 skip) {\\n base = uint8(blockHash[(index * 2) % 32]) % prime;\\n skip = (uint8(blockHash[((index * 2) + 1) % 32]) % (prime - 1)) + 1;\\n }\\n\\n function _getOperatorFundedCount(uint8 operatorIndex, ValidatorAllocationCache[] memory vd)\\n internal\\n view\\n returns (uint32)\\n {\\n if (operatorIndex >= vd.length) {\\n return 0;\\n }\\n if (vd[operatorIndex].used == false) {\\n StakingContractStorageLib.ValidatorsFundingInfo memory osi = StakingContractStorageLib\\n .getValidatorsFundingInfo(operatorIndex);\\n vd[operatorIndex].used = true;\\n vd[operatorIndex].funded = osi.funded;\\n vd[operatorIndex].available = osi.availableKeys;\\n }\\n return vd[operatorIndex].funded + vd[operatorIndex].toDeposit;\\n }\\n\\n function _getOperatorAvailableCount(uint8 operatorIndex, ValidatorAllocationCache[] memory vd)\\n internal\\n view\\n returns (uint32)\\n {\\n if (operatorIndex >= vd.length) {\\n return 0;\\n }\\n if (vd[operatorIndex].used == false) {\\n StakingContractStorageLib.ValidatorsFundingInfo memory osi = StakingContractStorageLib\\n .getValidatorsFundingInfo(operatorIndex);\\n vd[operatorIndex].used = true;\\n vd[operatorIndex].funded = osi.funded;\\n vd[operatorIndex].available = osi.availableKeys;\\n }\\n return vd[operatorIndex].available - vd[operatorIndex].toDeposit;\\n }\\n\\n function _assignTemporaryDeposit(uint8 operatorIndex, ValidatorAllocationCache[] memory vd) internal pure {\\n vd[operatorIndex].toDeposit += 1;\\n }\\n\\n function _getBestOperator(\\n uint8 alphaIndex,\\n uint8 betaIndex,\\n bytes32 blockHash,\\n ValidatorAllocationCache[] memory vd\\n ) internal view returns (uint8) {\\n uint256 alphaFundedCount = _getOperatorFundedCount(alphaIndex, vd);\\n uint256 betaFundedCount = _getOperatorFundedCount(betaIndex, vd);\\n if (alphaFundedCount < betaFundedCount) {\\n return alphaIndex;\\n } else if (alphaFundedCount > betaFundedCount) {\\n return betaIndex;\\n } else {\\n bool coinToss = (uint8(blockHash[(alphaIndex + betaIndex) % 32]) % 2) == 1;\\n if (coinToss == false) {\\n return betaIndex;\\n } else {\\n return alphaIndex;\\n }\\n }\\n }\\n\\n function _getElligibleOperators(\\n uint8 base,\\n uint8 skip,\\n uint8 prime,\\n ValidatorAllocationCache[] memory vd\\n ) internal view returns (uint8, uint8) {\\n int16 alphaIndex = -1;\\n int16 betaIndex = -1;\\n uint8 index = base;\\n while (alphaIndex == -1 || betaIndex == -1) {\\n if (_getOperatorAvailableCount(index, vd) > 0) {\\n if (alphaIndex == -1) {\\n alphaIndex = int8(index);\\n } else {\\n betaIndex = int8(index);\\n }\\n }\\n index = uint8((uint256(index) + skip) % prime);\\n if (index == base && betaIndex == -1) {\\n betaIndex = alphaIndex;\\n }\\n }\\n return (uint8(int8(alphaIndex)), uint8(int8(betaIndex)));\\n }\\n\\n function _depositOnThreeOrMoreOperators(\\n address _withdrawer,\\n uint256 _depositCount,\\n uint256 _totalAvailableValidators,\\n StakingContractStorageLib.OperatorsSlot storage _operators\\n ) internal {\\n uint256 operatorCount = _operators.value.length;\\n uint8 optimusPrime = _getClosestPrimeAbove(uint8(operatorCount));\\n bytes32 blockHash = blockhash(block.number - 1); // weak random number as it's not a security issue\\n\\n ValidatorAllocationCache[] memory vd = new ValidatorAllocationCache[](operatorCount);\\n\\n for (uint256 index; index < _depositCount; ) {\\n // Retrieve base index and skip value based on block hash and current loop index\\n (uint8 base, uint8 skip) = _getBaseSkip(blockHash, index, optimusPrime);\\n // Retrieve two operator indexes pointing to two (or the same) operator(s) that have at least one available\\n // validator key to be used for a deposit. This method takes into account possible pending deposits from\\n // previous loop rounds.\\n (uint8 alphaIndex, uint8 betaIndex) = _getElligibleOperators(base, skip, optimusPrime, vd);\\n\\n if (alphaIndex == betaIndex) {\\n // Assign the deposit to the only operator having available keys\\n _assignTemporaryDeposit(alphaIndex, vd);\\n } else {\\n // Assign the deposit to the operator having the lowest amount of funded keys\\n _assignTemporaryDeposit(_getBestOperator(alphaIndex, betaIndex, blockHash, vd), vd);\\n }\\n\\n unchecked {\\n ++index;\\n }\\n }\\n\\n // Loop through the cached operator values and deposit any pending deposits\\n for (uint256 index; index < vd.length; ) {\\n if (vd[index].toDeposit > 0) {\\n _depositValidatorsOfOperator(index, vd[index].toDeposit, _withdrawer);\\n }\\n unchecked {\\n ++index;\\n }\\n }\\n\\n StakingContractStorageLib.setTotalAvailableValidators(_totalAvailableValidators - _depositCount);\\n }\\n\\n function _deposit(address _withdrawer) internal {\\n if (msg.value == 0 || msg.value % DEPOSIT_SIZE != 0) {\\n revert InvalidDepositValue();\\n }\\n uint256 totalAvailableValidators = StakingContractStorageLib.getTotalAvailableValidators();\\n uint256 depositCount = msg.value / DEPOSIT_SIZE;\\n if (depositCount > totalAvailableValidators) {\\n revert NotEnoughValidators();\\n }\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n if (operators.value.length == 0) {\\n revert NoOperators();\\n } else if (operators.value.length == 1) {\\n _depositOnOneOperator(_withdrawer, depositCount, totalAvailableValidators);\\n } else if (operators.value.length == 2) {\\n _depositOnTwoOperators(_withdrawer, depositCount, totalAvailableValidators);\\n } else {\\n _depositOnThreeOrMoreOperators(_withdrawer, depositCount, totalAvailableValidators, operators);\\n }\\n }\\n\\n function _primes() internal pure returns (uint8[54] memory primes) {\\n primes = [\\n 2,\\n 3,\\n 5,\\n 7,\\n 11,\\n 13,\\n 17,\\n 19,\\n 23,\\n 29,\\n 31,\\n 37,\\n 41,\\n 43,\\n 47,\\n 53,\\n 59,\\n 61,\\n 67,\\n 71,\\n 73,\\n 79,\\n 83,\\n 89,\\n 97,\\n 101,\\n 103,\\n 107,\\n 109,\\n 113,\\n 127,\\n 131,\\n 137,\\n 139,\\n 149,\\n 151,\\n 157,\\n 163,\\n 167,\\n 173,\\n 179,\\n 181,\\n 191,\\n 193,\\n 197,\\n 199,\\n 211,\\n 223,\\n 227,\\n 229,\\n 233,\\n 239,\\n 241,\\n 251\\n ];\\n }\\n\\n function _getClosestPrimeAbove(uint8 _count) internal pure returns (uint8) {\\n uint8[54] memory primes = _primes();\\n for (uint256 i; i < primes.length; ) {\\n if (primes[i] >= _count) {\\n return primes[i];\\n }\\n unchecked {\\n ++i;\\n }\\n }\\n revert InvalidValidatorCount();\\n }\\n\\n function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n if (_a < _b) {\\n return _a;\\n }\\n return _b;\\n }\\n\\n /// @notice Internal utility to compute the receiver deterministic address\\n /// @param _publicKey Public Key assigned to the receiver\\n /// @param _prefix Prefix used to generate multiple receivers per public key\\n function _getDeterministicReceiver(bytes memory _publicKey, uint256 _prefix) internal view returns (address) {\\n bytes32 publicKeyRoot = _getPubKeyRoot(_publicKey);\\n bytes32 salt = sha256(abi.encodePacked(_prefix, publicKeyRoot));\\n address implementation = StakingContractStorageLib.getFeeRecipientImplementation();\\n return Clones.predictDeterministicAddress(implementation, salt);\\n }\\n\\n /// @notice Internal utility to deploy and withdraw the fees from a receiver\\n /// @param _publicKey Public Key assigned to the receiver\\n /// @param _prefix Prefix used to generate multiple receivers per public key\\n /// @param _dispatcher Address of the dispatcher contract\\n function _deployAndWithdraw(\\n bytes calldata _publicKey,\\n uint256 _prefix,\\n address _dispatcher\\n ) internal {\\n bytes32 publicKeyRoot = _getPubKeyRoot(_publicKey);\\n bytes32 feeRecipientSalt = sha256(abi.encodePacked(_prefix, publicKeyRoot));\\n address implementation = StakingContractStorageLib.getFeeRecipientImplementation();\\n address feeRecipientAddress = Clones.predictDeterministicAddress(implementation, feeRecipientSalt);\\n if (feeRecipientAddress.code.length == 0) {\\n Clones.cloneDeterministic(implementation, feeRecipientSalt);\\n IFeeRecipient(feeRecipientAddress).init(_dispatcher, publicKeyRoot);\\n }\\n IFeeRecipient(feeRecipientAddress).withdraw();\\n }\\n}\\n\",\"keccak256\":\"0x49cf8415037d64793cd4a0a9a53f57c214650f8954f7a5852ee1a918de7961bf\",\"license\":\"BUSL-1.1\"},\"src/contracts/interfaces/IDepositContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IDepositContract {\\n function deposit(\\n bytes calldata pubkey,\\n bytes calldata withdrawalCredentials,\\n bytes calldata signature,\\n bytes32 depositDataRoot\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x10ced526f2842c879ff63bf37a47d121d56898609456f98df1f3cff0a768b2c9\",\"license\":\"MIT\"},\"src/contracts/interfaces/IFeeRecipient.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IFeeRecipient {\\n function init(address _dispatcher, bytes32 _publicKeyRoot) external;\\n\\n function withdraw() external;\\n}\\n\",\"keccak256\":\"0x2448a6378aa26099508ce00bf1eff7ea293ae97eece97d931a6f500256a2c475\",\"license\":\"MIT\"},\"src/contracts/libs/BytesLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary BytesLib {\\n function pad64(bytes memory _b) internal pure returns (bytes memory) {\\n assert(_b.length >= 32 && _b.length <= 64);\\n if (64 == _b.length) return _b;\\n\\n bytes memory zero32 = new bytes(32);\\n assembly {\\n mstore(add(zero32, 0x20), 0)\\n }\\n\\n if (32 == _b.length) return BytesLib.concat(_b, zero32);\\n else return BytesLib.concat(_b, BytesLib.slice(zero32, 0, uint256(64) - _b.length));\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {\\n bytes memory tempBytes;\\n\\n assembly {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // Store the length of the first bytes array at the beginning of\\n // the memory for tempBytes.\\n let length := mload(_preBytes)\\n mstore(tempBytes, length)\\n\\n // Maintain a memory counter for the current write location in the\\n // temp bytes array by adding the 32 bytes for the array length to\\n // the starting location.\\n let mc := add(tempBytes, 0x20)\\n // Stop copying when the memory counter reaches the length of the\\n // first bytes array.\\n let end := add(mc, length)\\n\\n for {\\n // Initialize a copy counter to the start of the _preBytes data,\\n // 32 bytes into its memory.\\n let cc := add(_preBytes, 0x20)\\n } lt(mc, end) {\\n // Increase both counters by 32 bytes each iteration.\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // Write the _preBytes data into the tempBytes memory 32 bytes\\n // at a time.\\n mstore(mc, mload(cc))\\n }\\n\\n // Add the length of _postBytes to the current length of tempBytes\\n // and store it as the new length in the first 32 bytes of the\\n // tempBytes memory.\\n length := mload(_postBytes)\\n mstore(tempBytes, add(length, mload(tempBytes)))\\n\\n // Move the memory counter back from a multiple of 0x20 to the\\n // actual end of the _preBytes data.\\n mc := end\\n // Stop copying when the memory counter reaches the new combined\\n // length of the arrays.\\n end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n // Update the free-memory pointer by padding our last write location\\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\\n // next 32 byte block, then round down to the nearest multiple of\\n // 32. If the sum of the length of the two arrays is zero then add\\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\\n mstore(\\n 0x40,\\n and(\\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\\n not(31) // Round down to the nearest 32 bytes.\\n )\\n )\\n }\\n\\n return tempBytes;\\n }\\n\\n function slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes memory) {\\n require(_length + 31 >= _length, \\\"slice_overflow\\\");\\n require(_bytes.length >= _start + _length, \\\"slice_outOfBounds\\\");\\n\\n bytes memory tempBytes;\\n\\n assembly {\\n switch iszero(_length)\\n case 0 {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // The first word of the slice result is potentially a partial\\n // word read from the original array. To read it, we calculate\\n // the length of that partial word and start copying that many\\n // bytes into the array. The first word we copy will start with\\n // data we don't care about, but the last `lengthmod` bytes will\\n // land at the beginning of the contents of the new array. When\\n // we're done copying, we overwrite the full first word with\\n // the actual length of the slice.\\n let lengthmod := and(_length, 31)\\n\\n // The multiplication in the next line is necessary\\n // because when slicing multiples of 32 bytes (lengthmod == 0)\\n // the following copy loop was copying the origin's length\\n // and then ending prematurely not copying everything it should.\\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\\n let end := add(mc, _length)\\n\\n for {\\n // The multiplication in the next line has the same exact purpose\\n // as the one above.\\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n mstore(tempBytes, _length)\\n\\n //update free-memory pointer\\n //allocating the array padded to 32 bytes like the compiler does now\\n mstore(0x40, and(add(mc, 31), not(31)))\\n }\\n //if we want a zero-length slice let's just return a zero-length array\\n default {\\n tempBytes := mload(0x40)\\n //zero out the 32 bytes slice we are about to return\\n //we need to do it because Solidity does not garbage collect\\n mstore(tempBytes, 0)\\n\\n mstore(0x40, add(tempBytes, 0x20))\\n }\\n }\\n\\n return tempBytes;\\n }\\n}\\n\",\"keccak256\":\"0xec149de15f8150999a1881930747f7bc75138b84123e0547d1b4074ef0aef5cd\",\"license\":\"MIT\"},\"src/contracts/libs/StakingContractStorageLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary StakingContractStorageLib {\\n function getUint256(bytes32 position) internal view returns (uint256 data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setUint256(bytes32 position, uint256 data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n\\n function getAddress(bytes32 position) internal view returns (address data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setAddress(bytes32 position, address data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant VERSION_SLOT = keccak256(\\\"StakingContract.version\\\");\\n\\n function getVersion() internal view returns (uint256) {\\n return getUint256(VERSION_SLOT);\\n }\\n\\n function setVersion(uint256 _newVersion) internal {\\n setUint256(VERSION_SLOT, _newVersion);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant ADMIN_SLOT = keccak256(\\\"StakingContract.admin\\\");\\n bytes32 internal constant PENDING_ADMIN_SLOT = keccak256(\\\"StakingContract.pendingAdmin\\\");\\n\\n function getAdmin() internal view returns (address) {\\n return getAddress(ADMIN_SLOT);\\n }\\n\\n function setAdmin(address _newAdmin) internal {\\n setAddress(ADMIN_SLOT, _newAdmin);\\n }\\n\\n function getPendingAdmin() internal view returns (address) {\\n return getAddress(PENDING_ADMIN_SLOT);\\n }\\n\\n function setPendingAdmin(address _newPendingAdmin) internal {\\n setAddress(PENDING_ADMIN_SLOT, _newPendingAdmin);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant TREASURY_SLOT = keccak256(\\\"StakingContract.treasury\\\");\\n\\n function getTreasury() internal view returns (address) {\\n return getAddress(TREASURY_SLOT);\\n }\\n\\n function setTreasury(address _newTreasury) internal {\\n setAddress(TREASURY_SLOT, _newTreasury);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant DEPOSIT_CONTRACT_SLOT = keccak256(\\\"StakingContract.depositContract\\\");\\n\\n function getDepositContract() internal view returns (address) {\\n return getAddress(DEPOSIT_CONTRACT_SLOT);\\n }\\n\\n function setDepositContract(address _newDepositContract) internal {\\n setAddress(DEPOSIT_CONTRACT_SLOT, _newDepositContract);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant OPERATORS_SLOT = keccak256(\\\"StakingContract.operators\\\");\\n\\n struct OperatorInfo {\\n address operator;\\n address feeRecipient;\\n uint256 limit;\\n bytes[] publicKeys;\\n bytes[] signatures;\\n bool deactivated;\\n }\\n\\n struct OperatorsSlot {\\n OperatorInfo[] value;\\n }\\n\\n function getOperators() internal pure returns (OperatorsSlot storage p) {\\n bytes32 slot = OPERATORS_SLOT;\\n assembly {\\n p.slot := slot\\n }\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant VALIDATORS_FUNDING_INFO_SLOT = keccak256(\\\"StakingContract.validatorsFundingInfo\\\");\\n\\n struct ValidatorsFundingInfo {\\n uint32 availableKeys;\\n uint32 funded;\\n }\\n\\n struct UintToUintMappingSlot {\\n mapping(uint256 => uint256) value;\\n }\\n\\n function getValidatorsFundingInfo(uint256 _index) internal view returns (ValidatorsFundingInfo memory vfi) {\\n UintToUintMappingSlot storage p;\\n bytes32 slot = VALIDATORS_FUNDING_INFO_SLOT;\\n\\n assembly {\\n p.slot := slot\\n }\\n\\n uint256 slotIndex = _index >> 2;\\n uint256 innerIndex = (_index & 3) << 6;\\n uint256 value = p.value[slotIndex] >> innerIndex;\\n vfi.availableKeys = uint32(value);\\n vfi.funded = uint32(value >> 32);\\n }\\n\\n function setValidatorsFundingInfo(\\n uint256 _index,\\n uint32 _availableKeys,\\n uint32 _funded\\n ) internal {\\n UintToUintMappingSlot storage p;\\n bytes32 slot = VALIDATORS_FUNDING_INFO_SLOT;\\n\\n assembly {\\n p.slot := slot\\n }\\n\\n uint256 slotIndex = _index >> 2;\\n uint256 innerIndex = (_index & 3) << 6;\\n p.value[slotIndex] =\\n (p.value[slotIndex] & (~(uint256(0xFFFFFFFFFFFFFFFF) << innerIndex))) |\\n ((uint256(_availableKeys) | (uint256(_funded) << 32)) << innerIndex);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant TOTAL_AVAILABLE_VALIDATORS_SLOT = keccak256(\\\"StakingContract.totalAvailableValidators\\\");\\n\\n function getTotalAvailableValidators() internal view returns (uint256) {\\n return getUint256(TOTAL_AVAILABLE_VALIDATORS_SLOT);\\n }\\n\\n function setTotalAvailableValidators(uint256 _newTotal) internal {\\n setUint256(TOTAL_AVAILABLE_VALIDATORS_SLOT, _newTotal);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant WITHDRAWERS_SLOT = keccak256(\\\"StakingContract.withdrawers\\\");\\n\\n struct WithdrawersSlot {\\n mapping(bytes32 => address) value;\\n }\\n\\n function getWithdrawers() internal pure returns (WithdrawersSlot storage p) {\\n bytes32 slot = WITHDRAWERS_SLOT;\\n assembly {\\n p.slot := slot\\n }\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n struct OperatorIndex {\\n bool enabled;\\n uint32 operatorIndex;\\n }\\n\\n struct OperatorIndexPerValidatorSlot {\\n mapping(bytes32 => OperatorIndex) value;\\n }\\n\\n bytes32 internal constant OPERATOR_INDEX_PER_VALIDATOR_SLOT =\\n keccak256(\\\"StakingContract.operatorIndexPerValidator\\\");\\n\\n function getOperatorIndexPerValidator() internal pure returns (OperatorIndexPerValidatorSlot storage p) {\\n bytes32 slot = OPERATOR_INDEX_PER_VALIDATOR_SLOT;\\n assembly {\\n p.slot := slot\\n }\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant GLOBAL_FEE_SLOT = keccak256(\\\"StakingContract.globalFee\\\");\\n\\n function getGlobalFee() internal view returns (uint256) {\\n return getUint256(GLOBAL_FEE_SLOT);\\n }\\n\\n function setGlobalFee(uint256 _newTreasuryFee) internal {\\n setUint256(GLOBAL_FEE_SLOT, _newTreasuryFee);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant OPERATOR_FEE_SLOT = keccak256(\\\"StakingContract.operatorFee\\\");\\n\\n function getOperatorFee() internal view returns (uint256) {\\n return getUint256(OPERATOR_FEE_SLOT);\\n }\\n\\n function setOperatorFee(uint256 _newOperatorFee) internal {\\n setUint256(OPERATOR_FEE_SLOT, _newOperatorFee);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant EL_DISPATCHER_SLOT = keccak256(\\\"StakingContract.executionLayerDispatcher\\\");\\n\\n function getELDispatcher() internal view returns (address) {\\n return getAddress(EL_DISPATCHER_SLOT);\\n }\\n\\n function setELDispatcher(address _newElDispatcher) internal {\\n setAddress(EL_DISPATCHER_SLOT, _newElDispatcher);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant CL_DISPATCHER_SLOT = keccak256(\\\"StakingContract.consensusLayerDispatcher\\\");\\n\\n function getCLDispatcher() internal view returns (address) {\\n return getAddress(CL_DISPATCHER_SLOT);\\n }\\n\\n function setCLDispatcher(address _newClDispatcher) internal {\\n setAddress(CL_DISPATCHER_SLOT, _newClDispatcher);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant FEE_RECIPIENT_IMPLEMENTATION_SLOT =\\n keccak256(\\\"StakingContract.feeRecipientImplementation\\\");\\n\\n function getFeeRecipientImplementation() internal view returns (address) {\\n return getAddress(FEE_RECIPIENT_IMPLEMENTATION_SLOT);\\n }\\n\\n function setFeeRecipientImplementation(address _newFeeRecipientImplementation) internal {\\n setAddress(FEE_RECIPIENT_IMPLEMENTATION_SLOT, _newFeeRecipientImplementation);\\n }\\n}\\n\",\"keccak256\":\"0x65507a4dfda91a5dc48f4498753f8338a9039fd54f9e5487b6306b1bbd962807\",\"license\":\"MIT\"},\"src/contracts/libs/UintLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary Uint256Lib {\\n function toLittleEndian64(uint256 _value) internal pure returns (uint256 result) {\\n result = 0;\\n uint256 temp_value = _value;\\n for (uint256 i = 0; i < 8; ++i) {\\n result = (result << 8) | (temp_value & 0xFF);\\n temp_value >>= 8;\\n }\\n\\n assert(0 == temp_value); // fully converted\\n result <<= (24 * 8);\\n }\\n}\\n\",\"keccak256\":\"0x452fa01e7c7dbf60df6d9d12f79645183d66f5a8ca3d673742eb4960a1952b73\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b50614fb9806100206000396000f3fe6080604052600436106101fd5760003560e01c806379ba50971161010d578063bf509bd4116100a0578063d2a427471161006f578063d2a42747146105c5578063e00cb6ca146105e5578063e99454f514610605578063f0f4426014610625578063f2fde38b146106455761020d565b8063bf509bd414610568578063d046815614610588578063d0e30db01461059d578063d243d69d146105a55761020d565b8063a7400801116100dc578063a7400801146104fe578063b4336b841461051e578063b747e7dd14610533578063bf15af56146105535761020d565b806379ba5097146104895780638a1af4c41461049e5780639adf91ee146104be578063a4d8d2c4146104de5761020d565b806328696608116101905780633b19e84a1161015f5780633b19e84a146103fa578063540bc5ea1461040f57806363b4118f146104245780636e9960c314610454578063714b55b2146104695761020d565b80632869660814610388578063291206f61461039d5780632ba03a79146103bd57806336bf3325146103dd5761020d565b80631bcbfaba116101cc5780631bcbfaba146102ed5780631d095805146103105780631ee1334314610330578063227e80fa146103685761020d565b806305f63c8a1461022657806308b3a0731461028d5780630968f264146102ad5780631864636c146102cd5761020d565b3661020d5761020b33610665565b005b60405163574b16a760e11b815260040160405180910390fd5b34801561023257600080fd5b506102466102413660046147f8565b610755565b604080516001600160a01b039889168152979096166020880152948601939093526060850191909152608084015260a0830152151560c082015260e0015b60405180910390f35b34801561029957600080fd5b5061020b6102a836600461482d565b6109e5565b3480156102b957600080fd5b5061020b6102c83660046148ff565b610aba565b3480156102d957600080fd5b5061020b6102e8366004614941565b610ae1565b3480156102f957600080fd5b5061030261167d565b604051908152602001610284565b34801561031c57600080fd5b5061020b61032b3660046147f8565b61168c565b34801561033c57600080fd5b5061035061034b3660046148ff565b6116f3565b6040516001600160a01b039091168152602001610284565b34801561037457600080fd5b5061020b6103833660046149c0565b611740565b34801561039457600080fd5b50610302611816565b3480156103a957600080fd5b5061020b6103b83660046147f8565b611820565b3480156103c957600080fd5b5061020b6103d83660046148ff565b610ace565b3480156103e957600080fd5b506103026801bc16d674ec80000081565b34801561040657600080fd5b50610350611884565b34801561041b57600080fd5b50610302606081565b34801561043057600080fd5b5061044461043f3660046149ec565b61188e565b6040516102849493929190614a66565b34801561046057600080fd5b50610350611a72565b34801561047557600080fd5b5061020b6104843660046149ec565b611a7c565b34801561049557600080fd5b5061020b611b9e565b3480156104aa57600080fd5b506103026104b9366004614aad565b611bdb565b3480156104ca57600080fd5b506103506104d93660046147f8565b611d43565b3480156104ea57600080fd5b5061020b6104f9366004614ad7565b611dc1565b34801561050a57600080fd5b506103506105193660046147f8565b6120ee565b34801561052a57600080fd5b506103026120f9565b34801561053f57600080fd5b5061020b61054e366004614b13565b612103565b34801561055f57600080fd5b50610302603081565b34801561057457600080fd5b5061020b6105833660046148ff565b612438565b34801561059457600080fd5b50610350612447565b61020b612451565b3480156105b157600080fd5b506103506105c03660046148ff565b61245c565b3480156105d157600080fd5b5061020b6105e03660046149c0565b61249d565b3480156105f157600080fd5b506103506106003660046148ff565b6125a8565b34801561061157600080fd5b5061020b610620366004614b96565b6125ec565b34801561063157600080fd5b5061020b610640366004614be1565b612708565b34801561065157600080fd5b5061020b610660366004614be1565b612749565b34158061068357506106806801bc16d674ec80000034614c12565b15155b156106a15760405163214121f160e11b815260040160405180910390fd5b60006106ab61278a565b905060006106c26801bc16d674ec80000034614c3c565b9050818111156106e5576040516315caeb5160e31b815260040160405180910390fd5b600080516020614f6483398151915280546000036107165760405163ddf9d24560e01b815260040160405180910390fd5b805460010361072f5761072a8483856127b4565b61074f565b80546002036107435761072a8483856127d2565b61074f848385846128e0565b50505050565b600080808080808080600080516020614f6483398151915280549091508910156109d95760006107848a612a6d565b90506000826000018b8154811061079d5761079d614c50565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156108ac57838290600052602060002001805461081f90614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461084b90614c66565b80156108985780601f1061086d57610100808354040283529160200191610898565b820191906000526020600020905b81548152906001019060200180831161087b57829003601f168201915b505050505081526020019060010190610800565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156109855783829060005260206000200180546108f890614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461092490614c66565b80156109715780601f1061094657610100808354040283529160200191610971565b820191906000526020600020905b81548152906001019060200180831161095457829003601f168201915b5050505050815260200190600101906108d9565b505050908252506005919091015460ff161515602091820152815182820151604084015160608501515160a090950151938701519651929e50909c509a5091985063ffffffff938416975092169450909250505b50919395979092949650565b60016109ef612ad3565b6109fa906001614c9a565b8114610a185760405162dc149f60e41b815260040160405180910390fd5b610a2181612afd565b610a2a89612b26565b610a3388612b4f565b612710831115610a56576040516358d620b360e01b815260040160405180910390fd5b610a5f83612b78565b612710821115610a82576040516358d620b360e01b815260040160405180910390fd5b610a8b82612ba1565b610a9486612bca565b610a9d85612bf3565b610aa687612c1c565b610aaf84612c45565b505050505050505050565b610ace82826000610ac9612c6e565b612c98565b610add82826001610ac9612e4e565b5050565b82610aea612e78565b6001600160a01b031633036110b6576000829003610b1b5760405163a9cb9e0d60e01b815260040160405180910390fd5b6000610b2685612a6d565b6020810151909150600080516020614f648339815191529063ffffffff168585610b51600182614cb2565b818110610b6057610b60614c50565b905060200201351015610b86576040516334947ea160e01b815260040160405180910390fd5b60005b8481101561100557600081118015610bdb57508585610ba9600184614cb2565b818110610bb857610bb8614c50565b90506020020135868683818110610bd157610bd1614c50565b9050602002013510155b15610bf9576040516335061dff60e01b815260040160405180910390fd5b867f794aacb42d1ea2e7f72809b74e3ce124325a51c3715b873c36807d3ca37e4fd0836000018981548110610c3057610c30614c50565b9060005260206000209060060201600301888885818110610c5357610c53614c50565b9050602002013581548110610c6a57610c6a614c50565b90600052602060002001604051610c819190614cc9565b60405180910390a26001826000018881548110610ca057610ca0614c50565b906000526020600020906006020160030180549050610cbf9190614cb2565b868683818110610cd157610cd1614c50565b9050602002013503610d8857816000018781548110610cf257610cf2614c50565b9060005260206000209060060201600301805480610d1257610d12614d70565b600190038181906000526020600020016000610d2e9190614615565b9055816000018781548110610d4557610d45614c50565b9060005260206000209060060201600401805480610d6557610d65614d70565b600190038181906000526020600020016000610d819190614615565b9055610ffd565b816000018781548110610d9d57610d9d614c50565b90600052602060002090600602016003016001836000018981548110610dc557610dc5614c50565b906000526020600020906006020160030180549050610de49190614cb2565b81548110610df457610df4614c50565b90600052602060002001826000018881548110610e1357610e13614c50565b9060005260206000209060060201600301878784818110610e3657610e36614c50565b9050602002013581548110610e4d57610e4d614c50565b90600052602060002001908054610e6390614c66565b610e6e92919061464f565b50816000018781548110610e8457610e84614c50565b9060005260206000209060060201600301805480610ea457610ea4614d70565b600190038181906000526020600020016000610ec09190614615565b9055816000018781548110610ed757610ed7614c50565b90600052602060002090600602016004016001836000018981548110610eff57610eff614c50565b906000526020600020906006020160040180549050610f1e9190614cb2565b81548110610f2e57610f2e614c50565b90600052602060002001826000018881548110610f4d57610f4d614c50565b9060005260206000209060060201600401878784818110610f7057610f70614c50565b9050602002013581548110610f8757610f87614c50565b90600052602060002001908054610f9d90614c66565b610fa892919061464f565b50816000018781548110610fbe57610fbe614c50565b9060005260206000209060060201600401805480610fde57610fde614d70565b600190038181906000526020600020016000610ffa9190614615565b90555b600101610b89565b5080600001868154811061101b5761101b614c50565b6000918252602090912060026006909202010154858561103c600182614cb2565b81811061104b5761104b614c50565b9050602002013510156110a6578484611065600182614cb2565b81811061107457611074614c50565b9050602002013581600001878154811061109057611090614c50565b9060005260206000209060060201600201819055505b6110af86612ea2565b505061074f565b6110bf81612fae565b60008290036110e15760405163a9cb9e0d60e01b815260040160405180910390fd5b60006110ec85612a6d565b6020810151909150600080516020614f648339815191529063ffffffff168585611117600182614cb2565b81811061112657611126614c50565b90506020020135101561114c576040516334947ea160e01b815260040160405180910390fd5b60005b848110156115cb576000811180156111a15750858561116f600184614cb2565b81811061117e5761117e614c50565b9050602002013586868381811061119757611197614c50565b9050602002013510155b156111bf576040516335061dff60e01b815260040160405180910390fd5b867f794aacb42d1ea2e7f72809b74e3ce124325a51c3715b873c36807d3ca37e4fd08360000189815481106111f6576111f6614c50565b906000526020600020906006020160030188888581811061121957611219614c50565b905060200201358154811061123057611230614c50565b906000526020600020016040516112479190614cc9565b60405180910390a2600182600001888154811061126657611266614c50565b9060005260206000209060060201600301805490506112859190614cb2565b86868381811061129757611297614c50565b905060200201350361134e578160000187815481106112b8576112b8614c50565b90600052602060002090600602016003018054806112d8576112d8614d70565b6001900381819060005260206000200160006112f49190614615565b905581600001878154811061130b5761130b614c50565b906000526020600020906006020160040180548061132b5761132b614d70565b6001900381819060005260206000200160006113479190614615565b90556115c3565b81600001878154811061136357611363614c50565b9060005260206000209060060201600301600183600001898154811061138b5761138b614c50565b9060005260206000209060060201600301805490506113aa9190614cb2565b815481106113ba576113ba614c50565b906000526020600020018260000188815481106113d9576113d9614c50565b90600052602060002090600602016003018787848181106113fc576113fc614c50565b905060200201358154811061141357611413614c50565b9060005260206000200190805461142990614c66565b61143492919061464f565b5081600001878154811061144a5761144a614c50565b906000526020600020906006020160030180548061146a5761146a614d70565b6001900381819060005260206000200160006114869190614615565b905581600001878154811061149d5761149d614c50565b906000526020600020906006020160040160018360000189815481106114c5576114c5614c50565b9060005260206000209060060201600401805490506114e49190614cb2565b815481106114f4576114f4614c50565b9060005260206000200182600001888154811061151357611513614c50565b906000526020600020906006020160040187878481811061153657611536614c50565b905060200201358154811061154d5761154d614c50565b9060005260206000200190805461156390614c66565b61156e92919061464f565b5081600001878154811061158457611584614c50565b90600052602060002090600602016004018054806115a4576115a4614d70565b6001900381819060005260206000200160006115c09190614615565b90555b60010161114f565b508060000186815481106115e1576115e1614c50565b60009182526020909120600260069092020101548585611602600182614cb2565b81811061161157611611614c50565b90506020020135101561166c57848461162b600182614cb2565b81811061163a5761163a614c50565b9050602002013581600001878154811061165657611656614c50565b9060005260206000209060060201600201819055505b61167586612ea2565b505050505050565b6000611687613221565b905090565b611694612e78565b6001600160a01b0316336001600160a01b0316146116c4576040516282b42960e81b815260040160405180910390fd5b6127108111156116e7576040516358d620b360e01b815260040160405180910390fd5b6116f081612ba1565b50565b600061173783838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061324b915050565b90505b92915050565b611748612e78565b6001600160a01b0316336001600160a01b031614611778576040516282b42960e81b815260040160405180910390fd5b600080516020614f64833981519152805460009082908590811061179e5761179e614c50565b906000526020600020906006020160050160006101000a81548160ff021916908315150217905550818160000184815481106117dc576117dc614c50565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b60006116876132f5565b611828612e78565b6001600160a01b0316336001600160a01b031614611858576040516282b42960e81b815260040160405180910390fd5b61271081111561187b576040516358d620b360e01b815260040160405180910390fd5b6116f081612b78565b600061168761331f565b60608060008080600080516020614f6483398151915290508060000187815481106118bb576118bb614c50565b906000526020600020906006020160030186815481106118dd576118dd614c50565b9060005260206000200180546118f290614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461191e90614c66565b801561196b5780601f106119405761010080835404028352916020019161196b565b820191906000526020600020905b81548152906001019060200180831161194e57829003601f168201915b5050505050945080600001878154811061198757611987614c50565b906000526020600020906006020160040186815481106119a9576119a9614c50565b9060005260206000200180546119be90614c66565b80601f01602080910402602001604051908101604052809291908181526020018280546119ea90614c66565b8015611a375780601f10611a0c57610100808354040283529160200191611a37565b820191906000526020600020905b815481529060010190602001808311611a1a57829003601f168201915b50505050509350611a4f611a4a86613349565b6133a3565b9250611a5a87612a6d565b6020015163ffffffff16861091505092959194509250565b6000611687612e78565b611a84612e78565b6001600160a01b0316336001600160a01b031614611ab4576040516282b42960e81b815260040160405180910390fd5b600080516020614f648339815191528054819084908110611ad757611ad7614c50565b600091825260209091206005600690920201015460ff1615611b0c57604051630450a9a360e21b815260040160405180910390fd5b6000816000018481548110611b2357611b23614c50565b906000526020600020906006020160030180549050905082811015611b6a576040516362106cb360e01b815260048101849052602481018290526044015b60405180910390fd5b82826000018581548110611b8057611b80614c50565b90600052602060002090600602016002018190555061074f84612ea2565b6000611ba86133dd565b9050336001600160a01b03821614611bd2576040516282b42960e81b815260040160405180910390fd5b6116f081612b26565b6000611be5612e78565b6001600160a01b0316336001600160a01b031614611c15576040516282b42960e81b815260040160405180910390fd5b6040805160c0810182526000808252602082018190529181018290526060808201819052608082015260a0810191909152600080516020614f64833981519152805490919060fb03611c7a5760405163a20c741360e01b815260040160405180910390fd5b6001600160a01b03808616825284811660208084019182528454600181810187556000878152839020865160069093020180549286166001600160a01b0319938416178155935190840180549190951691161790925560408301516002820155606083015180518493611cf49260038501929101906146da565b5060808201518051611d109160048401916020909101906146da565b5060a091909101516005909101805460ff19169115159190911790558154611d3a90600190614cb2565b95945050505050565b60008181527fc58a51931c529c2a8796a8fad2ae789ee504643b4b567f2c0c97e809cec939026020526040812054600080516020614f6483398151915280549091610100900463ffffffff16908110611d9e57611d9e614c50565b60009182526020909120600160069092020101546001600160a01b031692915050565b826000600080516020614f64833981519152805483908110611de557611de5614c50565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b82821015611ef4578382906000526020600020018054611e6790614c66565b80601f0160208091040260200160405190810160405280929190818152602001828054611e9390614c66565b8015611ee05780601f10611eb557610100808354040283529160200191611ee0565b820191906000526020600020905b815481529060010190602001808311611ec357829003601f168201915b505050505081526020019060010190611e48565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b82821015611fcd578382906000526020600020018054611f4090614c66565b80601f0160208091040260200160405190810160405280929190818152602001828054611f6c90614c66565b8015611fb95780601f10611f8e57610100808354040283529160200191611fb9565b820191906000526020600020905b815481529060010190602001808311611f9c57829003601f168201915b505050505081526020019060010190611f21565b505050908252506005919091015460ff16151560209091015260a08101519091501561200c57604051630450a9a360e21b815260040160405180910390fd5b80602001516001600160a01b0316336001600160a01b031614612041576040516282b42960e81b815260040160405180910390fd5b600080516020614f648339815191528054859082908890811061206657612066614c50565b906000526020600020906006020160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160000187815481106120b1576120b1614c50565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050505050565b600061173a826133a3565b600061168761278a565b8561210d81612fae565b8560000361212e5760405163a9cb9e0d60e01b815260040160405180910390fd5b612139603085614c12565b15158061215057508561214d603086614c3c565b14155b1561216e5760405163337d0f4160e01b815260040160405180910390fd5b612179606083614c12565b15158061219057508561218d606084614c3c565b14155b156121ae5760405163274cf40160e01b815260040160405180910390fd5b600080516020614f648339815191527fc58a51931c529c2a8796a8fad2ae789ee504643b4b567f2c0c97e809cec9390260005b888110156123f457600061223989898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612232925060309150869050614d86565b6030613406565b9050600061228b88888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612284925060609150879050614d86565b6060613406565b9050846000018c815481106122a2576122a2614c50565b6000918252602080832060036006909302019190910180546001810182559083529181902084516122da939190910191850190614733565b50846000018c815481106122f0576122f0614c50565b600091825260208083206004600690930201919091018054600181018255908352918190208351612328939190910191840190614733565b50600061233483613349565b60008181526020879052604090205490915060ff16156123695782604051635a303adb60e01b8152600401611b619190614da5565b60405180604001604052806001151581526020018e63ffffffff1681525085600001600083815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548163ffffffff021916908363ffffffff1602179055509050508360010193505050506121e1565b50887f7f86e8c5bd6c77e028f6b5152f3429a262fc43bc0cc8a82432db9f1880d7c1e08888604051612427929190614db8565b60405180910390a2610aaf89612ea2565b610add82826000610ac9612c6e565b60006116876133dd565b61245a33610665565b565b600061173783838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250925061324b915050565b6124a5612e78565b6001600160a01b0316336001600160a01b0316146124d5576040516282b42960e81b815260040160405180910390fd5b600080516020614f6483398151915280546000908290859081106124fb576124fb614c50565b906000526020600020906006020160020181905550600181600001848154811061252757612527614c50565b906000526020600020906006020160050160006101000a81548160ff0219169083151502179055508181600001848154811061256557612565614c50565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506125a383612ea2565b505050565b6000611737611a4a84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061334992505050565b6000600261262f85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061351392505050565b60405161263c9190614de7565b602060405180830381855afa158015612659573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061267c9190614e03565b905060007f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e2656000838152602082905260409020549091506001600160a01b031633146126da576040516282b42960e81b815260040160405180910390fd5b60009182526020526040902080546001600160a01b0319166001600160a01b03929092169190911790555050565b612710612e78565b6001600160a01b0316336001600160a01b031614612740576040516282b42960e81b815260040160405180910390fd5b6116f081612b4f565b612751612e78565b6001600160a01b0316336001600160a01b031614612781576040516282b42960e81b815260040160405180910390fd5b6116f0816135ac565b60006116877f559ad51499ae00ca2e9d9d95aab46737c8904ab7da276613fefda282b2c2ac065490565b6127c0600083856135d4565b6125a36127cd8383614cb2565b613899565b60006127de6000612a6d565b905060006127ec6001612a6d565b90506000806127fc600243614c12565b6000036128215761280e600287614c3c565b915061281a8287614cb2565b905061283b565b61282c600287614c3c565b90506128388187614cb2565b91505b835163ffffffff1682111561286d57835161285c9063ffffffff1687614cb2565b845163ffffffff169250905061289c565b825163ffffffff1681111561289c57825161288e9063ffffffff1687614cb2565b835190925063ffffffff1690505b81156128ae576128ae600083896135d4565b80156128c0576128c0600182896135d4565b6128d76128cd8284614c9a565b6127cd9087614cb2565b50505050505050565b805460006128ed826138c2565b905060006128fc600143614cb2565b40905060008367ffffffffffffffff81111561291a5761291a614e1c565b60405190808252806020026020018201604052801561297357816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816129385790505b50905060005b878110156129e65760008061298f85848861393f565b915091506000806129a284848a896139d8565b915091508060ff168260ff16036129c2576129bd8287613a8a565b6129d7565b6129d76129d183838a8a613ac6565b87613a8a565b84600101945050505050612979565b5060005b8151811015612a55576000828281518110612a0757612a07614c50565b60200260200101516060015163ffffffff161115612a4d57612a4d81838381518110612a3557612a35614c50565b60200260200101516060015163ffffffff168b6135d4565b6001016129ea565b50612a636127cd8888614cb2565b5050505050505050565b60408051808201825260008082526020808301828152600286901c83527f37e2c371bbf1c7a1326d52e30855e9c8b6cac15eda4475320e427b948813a9f08252939091205463ffffffff60c060069690961b959095161c8481168352901c909216905290565b60006116877fd5c553085b8382c47128ae7612257fd5dc3b4fc4d3a108925604d3c8700c025b5490565b6116f07fd5c553085b8382c47128ae7612257fd5dc3b4fc4d3a108925604d3c8700c025b829055565b6116f07ffbeda9bc03875013b12a1ec161efb8e5bf7e58e3cec96a1ea9efd3e264d26e64829055565b6116f07f10c92bb459c0223bf996150f2fb702a8288fb8354a33d5b0212e8e6b8273f55e829055565b6116f07fb88142a0318e2b174876bceb4db9dc318011849c83fb8a8bb2997386d562324a829055565b6116f07f41118591c19026bdc7a484e34f80a8e7e632600aff1c72460e9c7dfe94a2dda6829055565b6116f07faa81344d5857c875349bc4a95d531a580c46bdd94c41b35b1e072e4d627079f8829055565b6116f07fb6d5e19fdd6cde5f03ed4f17c2670deffa47975541fd270b0b17e803297d7608829055565b6116f07fbc8b9852d17d50256bb221fdf6ee12d78dd493d807e907f7d223c40d65abd6b9829055565b6116f07fd1c64973da70267569571a091966834c1a36bdba47f2a112b6a95bf41fc9c24e829055565b60006116877faa81344d5857c875349bc4a95d531a580c46bdd94c41b35b1e072e4d627079f85490565b6000612cd985858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061334992505050565b9050600060028483604051602001612cfb929190918252602082015260400190565b60408051601f1981840301815290829052612d1591614de7565b602060405180830381855afa158015612d32573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612d559190614e03565b90506000612d61613b7b565b90506000612d6f8284613ba5565b9050806001600160a01b03163b600003612df157612d8d8284613c0b565b50604051630b302c9560e21b81526001600160a01b03868116600483015260248201869052821690632cc0b25490604401600060405180830381600087803b158015612dd857600080fd5b505af1158015612dec573d6000803e3d6000fd5b505050505b806001600160a01b0316633ccfd60b6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612e2c57600080fd5b505af1158015612e40573d6000803e3d6000fd5b505050505050505050505050565b60006116877fb6d5e19fdd6cde5f03ed4f17c2670deffa47975541fd270b0b17e803297d76085490565b60006116877ffbeda9bc03875013b12a1ec161efb8e5bf7e58e3cec96a1ea9efd3e264d26e645490565b6000612ead82612a6d565b8051600080516020614f648339815191528054929350916000908190612f2090859088908110612edf57612edf614c50565b906000526020600020906006020160020154856000018881548110612f0657612f06614c50565b906000526020600020906006020160030180549050613cab565b9050846020015163ffffffff168111612f4857612f438660008760200151613cbc565b612f6e565b6020850151612f5d9063ffffffff1682614cb2565b9150612f6e86838760200151613cbc565b8163ffffffff168363ffffffff1614611675576116758263ffffffff168463ffffffff16612f9a61278a565b612fa49190614cb2565b6127cd9190614c9a565b6000600080516020614f64833981519152805483908110612fd157612fd1614c50565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156130e057838290600052602060002001805461305390614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461307f90614c66565b80156130cc5780601f106130a1576101008083540402835291602001916130cc565b820191906000526020600020905b8154815290600101906020018083116130af57829003601f168201915b505050505081526020019060010190613034565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156131b957838290600052602060002001805461312c90614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461315890614c66565b80156131a55780601f1061317a576101008083540402835291602001916131a5565b820191906000526020600020905b81548152906001019060200180831161318857829003601f168201915b50505050508152602001906001019061310d565b505050908252506005919091015460ff16151560209091015260a0810151909150156131f857604051630450a9a360e21b815260040160405180910390fd5b80516001600160a01b03163314610add576040516282b42960e81b815260040160405180910390fd5b60006116877fb88142a0318e2b174876bceb4db9dc318011849c83fb8a8bb2997386d562324a5490565b60008061325784613349565b9050600060028483604051602001613279929190918252602082015260400190565b60408051601f198184030181529082905261329391614de7565b602060405180830381855afa1580156132b0573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906132d39190614e03565b905060006132df613b7b565b90506132eb8183613ba5565b9695505050505050565b60006116877f41118591c19026bdc7a484e34f80a8e7e632600aff1c72460e9c7dfe94a2dda65490565b60006116877f10c92bb459c0223bf996150f2fb702a8288fb8354a33d5b0212e8e6b8273f55e5490565b6000600261335683613513565b6040516133639190614de7565b602060405180830381855afa158015613380573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061173a9190614e03565b60009081527f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e26560205260409020546001600160a01b031690565b60006116877e595eca1f8b39945ff4c404827bfa5fd1e295ef3f7d59d120a8ce3bae4e37a05490565b60608161341481601f614c9a565b10156134535760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401611b61565b61345d8284614c9a565b845110156134a15760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401611b61565b6060821580156134c0576040519150600082526020820160405261350a565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156134f95780518352602092830192016134e1565b5050858452601f01601f1916604052505b50949350505050565b6060602082511015801561352957506040825111155b61353557613535614e32565b8151604003613542575090565b6040805160208082528183019092526000916020820181803683370190505090506000602082015282516020036135845761357d8382613d30565b9392505050565b61357d836135a18360008751604061359c9190614cb2565b613406565b613d30565b50919050565b6116f07e595eca1f8b39945ff4c404827bfa5fd1e295ef3f7d59d120a8ce3bae4e37a0829055565b600080516020614f6483398151915280546000908290869081106135fa576135fa614c50565b90600052602060002090600602019050600061361586612a6d565b602081015190915063ffffffff165b85826020015163ffffffff1661363a9190614c9a565b81101561386357600083600301828154811061365857613658614c50565b90600052602060002001805461366d90614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461369990614c66565b80156136e65780601f106136bb576101008083540402835291602001916136e6565b820191906000526020600020905b8154815290600101906020018083116136c957829003601f168201915b50505050509050600084600401838154811061370457613704614c50565b90600052602060002001805461371990614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461374590614c66565b80156137925780601f1061376757610100808354040283529160200191613792565b820191906000526020600020905b81548152906001019060200180831161377557829003601f168201915b5050505050905060006137a683600161324b565b905060006137b382613dad565b90506137c0848483613dc6565b60006137cb85613349565b60008181527f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e26560205260409081902080546001600160a01b0319166001600160a01b038e1690811790915590519192509033907f223e9969a6dc671e5bb38a0e0eb5c4e5a9d80c2cc5951b886895965069a421a29061384b908990614da5565b60405180910390a38560010195505050505050613624565b506116758686836000015163ffffffff1661387e9190614cb2565b87846020015163ffffffff166138949190614c9a565b613cbc565b6116f07f559ad51499ae00ca2e9d9d95aab46737c8904ab7da276613fefda282b2c2ac06829055565b6000806138cd614177565b905060005b6036811015613925578360ff168282603681106138f1576138f1614c50565b602002015160ff161061391d5781816036811061391057613910614c50565b6020020151949350505050565b6001016138d2565b50604051631470905f60e01b815260040160405180910390fd5b60008082856020613951876002614d86565b61395b9190614c12565b6020811061396b5761396b614c50565b6139779291901a614e48565b9150613984600184614e6a565b856020613992876002614d86565b61399d906001614c9a565b6139a79190614c12565b602081106139b7576139b7614c50565b6139c39291901a614e48565b6139ce906001614e8d565b9050935093915050565b60008060001980875b8260010b60001914806139f857508160010b600019145b15613a7c576000613a098288614335565b63ffffffff161115613a33578260010b60001903613a2c578060000b9250613a33565b8060000b91505b8660ff168860ff168260ff16613a499190614c9a565b613a539190614c12565b90508860ff168160ff16148015613a6e57508160010b600019145b15613a77578291505b6139e1565b509097909650945050505050565b6001818360ff1681518110613aa157613aa1614c50565b6020026020010151606001818151613ab99190614eb2565b63ffffffff169052505050565b600080613ad3868461446d565b63ffffffff1690506000613ae7868561446d565b63ffffffff16905080821015613b01578692505050613b73565b80821115613b13578592505050613b73565b60006002866020613b248a8c614e8d565b613b2e9190614e48565b60ff1660208110613b4157613b41614c50565b613b4d9291901a614e48565b60ff1660011490508015156000151503613b6c57869350505050613b73565b8793505050505b949350505050565b60006116877fd1c64973da70267569571a091966834c1a36bdba47f2a112b6a95bf41fc9c24e5490565b6000611737838330604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b03811661173a5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401611b61565b6000818310156135a657508161173a565b600283901c60009081527f37e2c371bbf1c7a1326d52e30855e9c8b6cac15eda4475320e427b948813a9f060209081526040909120805467ffffffffffffffff60c060069790971b9690961695861b191663ffffffff9490941667ffffffff000000009390921b929092161790921b179055565b6060806040519050835180825260208201818101602087015b81831015613d61578051835260209283019201613d49565b50855184518101855292509050808201602086015b81831015613d8e578051835260209283019201613d76565b508651929092011591909101601f01601f191660405250905092915050565b600061173a6001600160a01b038316600160f81b614c9a565b6000613dd184613349565b90506000600280613de58660006040613406565b604051613df29190614de7565b602060405180830381855afa158015613e0f573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190613e329190614e03565b6002613e4d613e4888604061359c816060614cb2565b613513565b604051613e5a9190614de7565b602060405180830381855afa158015613e77573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190613e9a9190614e03565b60408051602081019390935282015260600160408051601f1981840301815290829052613ec691614de7565b602060405180830381855afa158015613ee3573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190613f069190614e03565b90506000613f21633b9aca006801bc16d674ec800000614c3c565b90506801bc16d674ec800000613f3b82633b9aca00614d86565b14613f4857613f48614e32565b60006002808587604051602001613f69929190918252602082015260400190565b60408051601f1981840301815290829052613f8391614de7565b602060405180830381855afa158015613fa0573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190613fc39190614e03565b6002613fce856145a5565b604080516020810192909252810187905260600160408051601f1981840301815290829052613ffc91614de7565b602060405180830381855afa158015614019573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061403c9190614e03565b60408051602081019390935282015260600160408051601f198184030181529082905261406891614de7565b602060405180830381855afa158015614085573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906140a89190614e03565b905060006140bf6801bc16d674ec80000047614cb2565b90506140c96145eb565b6001600160a01b031663228951186801bc16d674ec8000008a896040516020016140f591815260200190565b6040516020818303038152906040528b876040518663ffffffff1660e01b81526004016141259493929190614eda565b6000604051808303818588803b15801561413e57600080fd5b505af1158015614152573d6000803e3d6000fd5b5050505050804714612a6357604051636596d2b760e01b815260040160405180910390fd5b61417f6147a7565b50604080516106c081018252600281526003602082015260059181019190915260076060820152600b6080820152600d60a0820152601160c0820152601360e08201526017610100820152601d610120820152601f61014082015260256101608201526029610180820152602b6101a0820152602f6101c082015260356101e0820152603b610200820152603d610220820152604361024082015260476102608201526049610280820152604f6102a082015260536102c082015260596102e0820152606161030082015260656103208201526067610340820152606b610360820152606d61038082015260716103a0820152607f6103c082015260836103e08201526089610400820152608b61042082015260956104408201526097610460820152609d61048082015260a36104a082015260a76104c082015260ad6104e082015260b361050082015260b561052082015260bf61054082015260c161056082015260c561058082015260c76105a082015260d36105c082015260df6105e082015260e361060082015260e561062082015260e961064082015260ef61066082015260f161068082015260fb6106a082015290565b600081518360ff161061434a5750600061173a565b818360ff168151811061435f5761435f614c50565b602002602001015160000151151560001515036144215760006143848460ff16612a6d565b90506001838560ff168151811061439d5761439d614c50565b6020908102919091018101519115159091528101518351849060ff87169081106143c9576143c9614c50565b60200260200101516040019063ffffffff16908163ffffffff16815250508060000151838560ff168151811061440157614401614c50565b60200260200101516080019063ffffffff16908163ffffffff1681525050505b818360ff168151811061443657614436614c50565b602002602001015160600151828460ff168151811061445757614457614c50565b6020026020010151608001516117379190614f25565b600081518360ff16106144825750600061173a565b818360ff168151811061449757614497614c50565b602002602001015160000151151560001515036145595760006144bc8460ff16612a6d565b90506001838560ff16815181106144d5576144d5614c50565b6020908102919091018101519115159091528101518351849060ff871690811061450157614501614c50565b60200260200101516040019063ffffffff16908163ffffffff16815250508060000151838560ff168151811061453957614539614c50565b60200260200101516080019063ffffffff16908163ffffffff1681525050505b818360ff168151811061456e5761456e614c50565b602002602001015160600151828460ff168151811061458f5761458f614c50565b6020026020010151604001516117379190614eb2565b600081815b60088110156145d357600892831b60ff831617929190911c906145cc81614f4a565b90506145aa565b5080156145e2576145e2614e32565b5060c01b919050565b60006116877fbc8b9852d17d50256bb221fdf6ee12d78dd493d807e907f7d223c40d65abd6b95490565b50805461462190614c66565b6000825580601f10614631575050565b601f0160209004906000526020600020908101906116f091906147c6565b82805461465b90614c66565b90600052602060002090601f01602090048101928261467d57600085556146ca565b82601f1061468e57805485556146ca565b828001600101855582156146ca57600052602060002091601f016020900482015b828111156146ca5782548255916001019190600101906146af565b506146d69291506147c6565b5090565b828054828255906000526020600020908101928215614727579160200282015b828111156147275782518051614717918491602090910190614733565b50916020019190600101906146fa565b506146d69291506147db565b82805461473f90614c66565b90600052602060002090601f01602090048101928261476157600085556146ca565b82601f1061477a57805160ff19168380011785556146ca565b828001600101855582156146ca579182015b828111156146ca57825182559160200191906001019061478c565b604051806106c001604052806036906020820280368337509192915050565b5b808211156146d657600081556001016147c7565b808211156146d65760006147ef8282614615565b506001016147db565b60006020828403121561480a57600080fd5b5035919050565b80356001600160a01b038116811461482857600080fd5b919050565b600080600080600080600080610100898b03121561484a57600080fd5b61485389614811565b975061486160208a01614811565b965061486f60408a01614811565b955061487d60608a01614811565b945061488b60808a01614811565b935061489960a08a01614811565b925060c0890135915060e089013590509295985092959890939650565b60008083601f8401126148c857600080fd5b50813567ffffffffffffffff8111156148e057600080fd5b6020830191508360208285010111156148f857600080fd5b9250929050565b6000806020838503121561491257600080fd5b823567ffffffffffffffff81111561492957600080fd5b614935858286016148b6565b90969095509350505050565b60008060006040848603121561495657600080fd5b83359250602084013567ffffffffffffffff8082111561497557600080fd5b818601915086601f83011261498957600080fd5b81358181111561499857600080fd5b8760208260051b85010111156149ad57600080fd5b6020830194508093505050509250925092565b600080604083850312156149d357600080fd5b823591506149e360208401614811565b90509250929050565b600080604083850312156149ff57600080fd5b50508035926020909101359150565b60005b83811015614a29578181015183820152602001614a11565b8381111561074f5750506000910152565b60008151808452614a52816020860160208601614a0e565b601f01601f19169290920160200192915050565b608081526000614a796080830187614a3a565b8281036020840152614a8b8187614a3a565b6001600160a01b03959095166040840152505090151560609091015292915050565b60008060408385031215614ac057600080fd5b614ac983614811565b91506149e360208401614811565b600080600060608486031215614aec57600080fd5b83359250614afc60208501614811565b9150614b0a60408501614811565b90509250925092565b60008060008060008060808789031215614b2c57600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115614b5257600080fd5b614b5e8a838b016148b6565b90965094506060890135915080821115614b7757600080fd5b50614b8489828a016148b6565b979a9699509497509295939492505050565b600080600060408486031215614bab57600080fd5b833567ffffffffffffffff811115614bc257600080fd5b614bce868287016148b6565b9094509250614b0a905060208501614811565b600060208284031215614bf357600080fd5b61173782614811565b634e487b7160e01b600052601260045260246000fd5b600082614c2157614c21614bfc565b500690565b634e487b7160e01b600052601160045260246000fd5b600082614c4b57614c4b614bfc565b500490565b634e487b7160e01b600052603260045260246000fd5b600181811c90821680614c7a57607f821691505b6020821081036135a657634e487b7160e01b600052602260045260246000fd5b60008219821115614cad57614cad614c26565b500190565b600082821015614cc457614cc4614c26565b500390565b600060208083526000845481600182811c915080831680614ceb57607f831692505b8583108103614d0857634e487b7160e01b85526022600452602485fd5b878601838152602001818015614d255760018114614d3657614d61565b60ff19861682528782019650614d61565b60008b81526020902060005b86811015614d5b57815484820152908501908901614d42565b83019750505b50949998505050505050505050565b634e487b7160e01b600052603160045260246000fd5b6000816000190483118215151615614da057614da0614c26565b500290565b6020815260006117376020830184614a3a565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60008251614df9818460208701614a0e565b9190910192915050565b600060208284031215614e1557600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052600160045260246000fd5b600060ff831680614e5b57614e5b614bfc565b8060ff84160691505092915050565b600060ff821660ff841680821015614e8457614e84614c26565b90039392505050565b600060ff821660ff84168060ff03821115614eaa57614eaa614c26565b019392505050565b600063ffffffff808316818516808303821115614ed157614ed1614c26565b01949350505050565b608081526000614eed6080830187614a3a565b8281036020840152614eff8187614a3a565b90508281036040840152614f138186614a3a565b91505082606083015295945050505050565b600063ffffffff83811690831681811015614f4257614f42614c26565b039392505050565b600060018201614f5c57614f5c614c26565b506001019056fed2a2f1f08ad325daf72af0169949ae210065d6916750ff03abd83510331b7b39a26469706673582212204f754125bd6774b3c7a13c07999e4753f87ab8b58df9a7fbc2e893e0656a6cea64736f6c634300080d0033", - "deployedBytecode": "0x6080604052600436106101fd5760003560e01c806379ba50971161010d578063bf509bd4116100a0578063d2a427471161006f578063d2a42747146105c5578063e00cb6ca146105e5578063e99454f514610605578063f0f4426014610625578063f2fde38b146106455761020d565b8063bf509bd414610568578063d046815614610588578063d0e30db01461059d578063d243d69d146105a55761020d565b8063a7400801116100dc578063a7400801146104fe578063b4336b841461051e578063b747e7dd14610533578063bf15af56146105535761020d565b806379ba5097146104895780638a1af4c41461049e5780639adf91ee146104be578063a4d8d2c4146104de5761020d565b806328696608116101905780633b19e84a1161015f5780633b19e84a146103fa578063540bc5ea1461040f57806363b4118f146104245780636e9960c314610454578063714b55b2146104695761020d565b80632869660814610388578063291206f61461039d5780632ba03a79146103bd57806336bf3325146103dd5761020d565b80631bcbfaba116101cc5780631bcbfaba146102ed5780631d095805146103105780631ee1334314610330578063227e80fa146103685761020d565b806305f63c8a1461022657806308b3a0731461028d5780630968f264146102ad5780631864636c146102cd5761020d565b3661020d5761020b33610665565b005b60405163574b16a760e11b815260040160405180910390fd5b34801561023257600080fd5b506102466102413660046147f8565b610755565b604080516001600160a01b039889168152979096166020880152948601939093526060850191909152608084015260a0830152151560c082015260e0015b60405180910390f35b34801561029957600080fd5b5061020b6102a836600461482d565b6109e5565b3480156102b957600080fd5b5061020b6102c83660046148ff565b610aba565b3480156102d957600080fd5b5061020b6102e8366004614941565b610ae1565b3480156102f957600080fd5b5061030261167d565b604051908152602001610284565b34801561031c57600080fd5b5061020b61032b3660046147f8565b61168c565b34801561033c57600080fd5b5061035061034b3660046148ff565b6116f3565b6040516001600160a01b039091168152602001610284565b34801561037457600080fd5b5061020b6103833660046149c0565b611740565b34801561039457600080fd5b50610302611816565b3480156103a957600080fd5b5061020b6103b83660046147f8565b611820565b3480156103c957600080fd5b5061020b6103d83660046148ff565b610ace565b3480156103e957600080fd5b506103026801bc16d674ec80000081565b34801561040657600080fd5b50610350611884565b34801561041b57600080fd5b50610302606081565b34801561043057600080fd5b5061044461043f3660046149ec565b61188e565b6040516102849493929190614a66565b34801561046057600080fd5b50610350611a72565b34801561047557600080fd5b5061020b6104843660046149ec565b611a7c565b34801561049557600080fd5b5061020b611b9e565b3480156104aa57600080fd5b506103026104b9366004614aad565b611bdb565b3480156104ca57600080fd5b506103506104d93660046147f8565b611d43565b3480156104ea57600080fd5b5061020b6104f9366004614ad7565b611dc1565b34801561050a57600080fd5b506103506105193660046147f8565b6120ee565b34801561052a57600080fd5b506103026120f9565b34801561053f57600080fd5b5061020b61054e366004614b13565b612103565b34801561055f57600080fd5b50610302603081565b34801561057457600080fd5b5061020b6105833660046148ff565b612438565b34801561059457600080fd5b50610350612447565b61020b612451565b3480156105b157600080fd5b506103506105c03660046148ff565b61245c565b3480156105d157600080fd5b5061020b6105e03660046149c0565b61249d565b3480156105f157600080fd5b506103506106003660046148ff565b6125a8565b34801561061157600080fd5b5061020b610620366004614b96565b6125ec565b34801561063157600080fd5b5061020b610640366004614be1565b612708565b34801561065157600080fd5b5061020b610660366004614be1565b612749565b34158061068357506106806801bc16d674ec80000034614c12565b15155b156106a15760405163214121f160e11b815260040160405180910390fd5b60006106ab61278a565b905060006106c26801bc16d674ec80000034614c3c565b9050818111156106e5576040516315caeb5160e31b815260040160405180910390fd5b600080516020614f6483398151915280546000036107165760405163ddf9d24560e01b815260040160405180910390fd5b805460010361072f5761072a8483856127b4565b61074f565b80546002036107435761072a8483856127d2565b61074f848385846128e0565b50505050565b600080808080808080600080516020614f6483398151915280549091508910156109d95760006107848a612a6d565b90506000826000018b8154811061079d5761079d614c50565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156108ac57838290600052602060002001805461081f90614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461084b90614c66565b80156108985780601f1061086d57610100808354040283529160200191610898565b820191906000526020600020905b81548152906001019060200180831161087b57829003601f168201915b505050505081526020019060010190610800565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156109855783829060005260206000200180546108f890614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461092490614c66565b80156109715780601f1061094657610100808354040283529160200191610971565b820191906000526020600020905b81548152906001019060200180831161095457829003601f168201915b5050505050815260200190600101906108d9565b505050908252506005919091015460ff161515602091820152815182820151604084015160608501515160a090950151938701519651929e50909c509a5091985063ffffffff938416975092169450909250505b50919395979092949650565b60016109ef612ad3565b6109fa906001614c9a565b8114610a185760405162dc149f60e41b815260040160405180910390fd5b610a2181612afd565b610a2a89612b26565b610a3388612b4f565b612710831115610a56576040516358d620b360e01b815260040160405180910390fd5b610a5f83612b78565b612710821115610a82576040516358d620b360e01b815260040160405180910390fd5b610a8b82612ba1565b610a9486612bca565b610a9d85612bf3565b610aa687612c1c565b610aaf84612c45565b505050505050505050565b610ace82826000610ac9612c6e565b612c98565b610add82826001610ac9612e4e565b5050565b82610aea612e78565b6001600160a01b031633036110b6576000829003610b1b5760405163a9cb9e0d60e01b815260040160405180910390fd5b6000610b2685612a6d565b6020810151909150600080516020614f648339815191529063ffffffff168585610b51600182614cb2565b818110610b6057610b60614c50565b905060200201351015610b86576040516334947ea160e01b815260040160405180910390fd5b60005b8481101561100557600081118015610bdb57508585610ba9600184614cb2565b818110610bb857610bb8614c50565b90506020020135868683818110610bd157610bd1614c50565b9050602002013510155b15610bf9576040516335061dff60e01b815260040160405180910390fd5b867f794aacb42d1ea2e7f72809b74e3ce124325a51c3715b873c36807d3ca37e4fd0836000018981548110610c3057610c30614c50565b9060005260206000209060060201600301888885818110610c5357610c53614c50565b9050602002013581548110610c6a57610c6a614c50565b90600052602060002001604051610c819190614cc9565b60405180910390a26001826000018881548110610ca057610ca0614c50565b906000526020600020906006020160030180549050610cbf9190614cb2565b868683818110610cd157610cd1614c50565b9050602002013503610d8857816000018781548110610cf257610cf2614c50565b9060005260206000209060060201600301805480610d1257610d12614d70565b600190038181906000526020600020016000610d2e9190614615565b9055816000018781548110610d4557610d45614c50565b9060005260206000209060060201600401805480610d6557610d65614d70565b600190038181906000526020600020016000610d819190614615565b9055610ffd565b816000018781548110610d9d57610d9d614c50565b90600052602060002090600602016003016001836000018981548110610dc557610dc5614c50565b906000526020600020906006020160030180549050610de49190614cb2565b81548110610df457610df4614c50565b90600052602060002001826000018881548110610e1357610e13614c50565b9060005260206000209060060201600301878784818110610e3657610e36614c50565b9050602002013581548110610e4d57610e4d614c50565b90600052602060002001908054610e6390614c66565b610e6e92919061464f565b50816000018781548110610e8457610e84614c50565b9060005260206000209060060201600301805480610ea457610ea4614d70565b600190038181906000526020600020016000610ec09190614615565b9055816000018781548110610ed757610ed7614c50565b90600052602060002090600602016004016001836000018981548110610eff57610eff614c50565b906000526020600020906006020160040180549050610f1e9190614cb2565b81548110610f2e57610f2e614c50565b90600052602060002001826000018881548110610f4d57610f4d614c50565b9060005260206000209060060201600401878784818110610f7057610f70614c50565b9050602002013581548110610f8757610f87614c50565b90600052602060002001908054610f9d90614c66565b610fa892919061464f565b50816000018781548110610fbe57610fbe614c50565b9060005260206000209060060201600401805480610fde57610fde614d70565b600190038181906000526020600020016000610ffa9190614615565b90555b600101610b89565b5080600001868154811061101b5761101b614c50565b6000918252602090912060026006909202010154858561103c600182614cb2565b81811061104b5761104b614c50565b9050602002013510156110a6578484611065600182614cb2565b81811061107457611074614c50565b9050602002013581600001878154811061109057611090614c50565b9060005260206000209060060201600201819055505b6110af86612ea2565b505061074f565b6110bf81612fae565b60008290036110e15760405163a9cb9e0d60e01b815260040160405180910390fd5b60006110ec85612a6d565b6020810151909150600080516020614f648339815191529063ffffffff168585611117600182614cb2565b81811061112657611126614c50565b90506020020135101561114c576040516334947ea160e01b815260040160405180910390fd5b60005b848110156115cb576000811180156111a15750858561116f600184614cb2565b81811061117e5761117e614c50565b9050602002013586868381811061119757611197614c50565b9050602002013510155b156111bf576040516335061dff60e01b815260040160405180910390fd5b867f794aacb42d1ea2e7f72809b74e3ce124325a51c3715b873c36807d3ca37e4fd08360000189815481106111f6576111f6614c50565b906000526020600020906006020160030188888581811061121957611219614c50565b905060200201358154811061123057611230614c50565b906000526020600020016040516112479190614cc9565b60405180910390a2600182600001888154811061126657611266614c50565b9060005260206000209060060201600301805490506112859190614cb2565b86868381811061129757611297614c50565b905060200201350361134e578160000187815481106112b8576112b8614c50565b90600052602060002090600602016003018054806112d8576112d8614d70565b6001900381819060005260206000200160006112f49190614615565b905581600001878154811061130b5761130b614c50565b906000526020600020906006020160040180548061132b5761132b614d70565b6001900381819060005260206000200160006113479190614615565b90556115c3565b81600001878154811061136357611363614c50565b9060005260206000209060060201600301600183600001898154811061138b5761138b614c50565b9060005260206000209060060201600301805490506113aa9190614cb2565b815481106113ba576113ba614c50565b906000526020600020018260000188815481106113d9576113d9614c50565b90600052602060002090600602016003018787848181106113fc576113fc614c50565b905060200201358154811061141357611413614c50565b9060005260206000200190805461142990614c66565b61143492919061464f565b5081600001878154811061144a5761144a614c50565b906000526020600020906006020160030180548061146a5761146a614d70565b6001900381819060005260206000200160006114869190614615565b905581600001878154811061149d5761149d614c50565b906000526020600020906006020160040160018360000189815481106114c5576114c5614c50565b9060005260206000209060060201600401805490506114e49190614cb2565b815481106114f4576114f4614c50565b9060005260206000200182600001888154811061151357611513614c50565b906000526020600020906006020160040187878481811061153657611536614c50565b905060200201358154811061154d5761154d614c50565b9060005260206000200190805461156390614c66565b61156e92919061464f565b5081600001878154811061158457611584614c50565b90600052602060002090600602016004018054806115a4576115a4614d70565b6001900381819060005260206000200160006115c09190614615565b90555b60010161114f565b508060000186815481106115e1576115e1614c50565b60009182526020909120600260069092020101548585611602600182614cb2565b81811061161157611611614c50565b90506020020135101561166c57848461162b600182614cb2565b81811061163a5761163a614c50565b9050602002013581600001878154811061165657611656614c50565b9060005260206000209060060201600201819055505b61167586612ea2565b505050505050565b6000611687613221565b905090565b611694612e78565b6001600160a01b0316336001600160a01b0316146116c4576040516282b42960e81b815260040160405180910390fd5b6127108111156116e7576040516358d620b360e01b815260040160405180910390fd5b6116f081612ba1565b50565b600061173783838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061324b915050565b90505b92915050565b611748612e78565b6001600160a01b0316336001600160a01b031614611778576040516282b42960e81b815260040160405180910390fd5b600080516020614f64833981519152805460009082908590811061179e5761179e614c50565b906000526020600020906006020160050160006101000a81548160ff021916908315150217905550818160000184815481106117dc576117dc614c50565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b60006116876132f5565b611828612e78565b6001600160a01b0316336001600160a01b031614611858576040516282b42960e81b815260040160405180910390fd5b61271081111561187b576040516358d620b360e01b815260040160405180910390fd5b6116f081612b78565b600061168761331f565b60608060008080600080516020614f6483398151915290508060000187815481106118bb576118bb614c50565b906000526020600020906006020160030186815481106118dd576118dd614c50565b9060005260206000200180546118f290614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461191e90614c66565b801561196b5780601f106119405761010080835404028352916020019161196b565b820191906000526020600020905b81548152906001019060200180831161194e57829003601f168201915b5050505050945080600001878154811061198757611987614c50565b906000526020600020906006020160040186815481106119a9576119a9614c50565b9060005260206000200180546119be90614c66565b80601f01602080910402602001604051908101604052809291908181526020018280546119ea90614c66565b8015611a375780601f10611a0c57610100808354040283529160200191611a37565b820191906000526020600020905b815481529060010190602001808311611a1a57829003601f168201915b50505050509350611a4f611a4a86613349565b6133a3565b9250611a5a87612a6d565b6020015163ffffffff16861091505092959194509250565b6000611687612e78565b611a84612e78565b6001600160a01b0316336001600160a01b031614611ab4576040516282b42960e81b815260040160405180910390fd5b600080516020614f648339815191528054819084908110611ad757611ad7614c50565b600091825260209091206005600690920201015460ff1615611b0c57604051630450a9a360e21b815260040160405180910390fd5b6000816000018481548110611b2357611b23614c50565b906000526020600020906006020160030180549050905082811015611b6a576040516362106cb360e01b815260048101849052602481018290526044015b60405180910390fd5b82826000018581548110611b8057611b80614c50565b90600052602060002090600602016002018190555061074f84612ea2565b6000611ba86133dd565b9050336001600160a01b03821614611bd2576040516282b42960e81b815260040160405180910390fd5b6116f081612b26565b6000611be5612e78565b6001600160a01b0316336001600160a01b031614611c15576040516282b42960e81b815260040160405180910390fd5b6040805160c0810182526000808252602082018190529181018290526060808201819052608082015260a0810191909152600080516020614f64833981519152805490919060fb03611c7a5760405163a20c741360e01b815260040160405180910390fd5b6001600160a01b03808616825284811660208084019182528454600181810187556000878152839020865160069093020180549286166001600160a01b0319938416178155935190840180549190951691161790925560408301516002820155606083015180518493611cf49260038501929101906146da565b5060808201518051611d109160048401916020909101906146da565b5060a091909101516005909101805460ff19169115159190911790558154611d3a90600190614cb2565b95945050505050565b60008181527fc58a51931c529c2a8796a8fad2ae789ee504643b4b567f2c0c97e809cec939026020526040812054600080516020614f6483398151915280549091610100900463ffffffff16908110611d9e57611d9e614c50565b60009182526020909120600160069092020101546001600160a01b031692915050565b826000600080516020614f64833981519152805483908110611de557611de5614c50565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b82821015611ef4578382906000526020600020018054611e6790614c66565b80601f0160208091040260200160405190810160405280929190818152602001828054611e9390614c66565b8015611ee05780601f10611eb557610100808354040283529160200191611ee0565b820191906000526020600020905b815481529060010190602001808311611ec357829003601f168201915b505050505081526020019060010190611e48565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b82821015611fcd578382906000526020600020018054611f4090614c66565b80601f0160208091040260200160405190810160405280929190818152602001828054611f6c90614c66565b8015611fb95780601f10611f8e57610100808354040283529160200191611fb9565b820191906000526020600020905b815481529060010190602001808311611f9c57829003601f168201915b505050505081526020019060010190611f21565b505050908252506005919091015460ff16151560209091015260a08101519091501561200c57604051630450a9a360e21b815260040160405180910390fd5b80602001516001600160a01b0316336001600160a01b031614612041576040516282b42960e81b815260040160405180910390fd5b600080516020614f648339815191528054859082908890811061206657612066614c50565b906000526020600020906006020160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160000187815481106120b1576120b1614c50565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050505050565b600061173a826133a3565b600061168761278a565b8561210d81612fae565b8560000361212e5760405163a9cb9e0d60e01b815260040160405180910390fd5b612139603085614c12565b15158061215057508561214d603086614c3c565b14155b1561216e5760405163337d0f4160e01b815260040160405180910390fd5b612179606083614c12565b15158061219057508561218d606084614c3c565b14155b156121ae5760405163274cf40160e01b815260040160405180910390fd5b600080516020614f648339815191527fc58a51931c529c2a8796a8fad2ae789ee504643b4b567f2c0c97e809cec9390260005b888110156123f457600061223989898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612232925060309150869050614d86565b6030613406565b9050600061228b88888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612284925060609150879050614d86565b6060613406565b9050846000018c815481106122a2576122a2614c50565b6000918252602080832060036006909302019190910180546001810182559083529181902084516122da939190910191850190614733565b50846000018c815481106122f0576122f0614c50565b600091825260208083206004600690930201919091018054600181018255908352918190208351612328939190910191840190614733565b50600061233483613349565b60008181526020879052604090205490915060ff16156123695782604051635a303adb60e01b8152600401611b619190614da5565b60405180604001604052806001151581526020018e63ffffffff1681525085600001600083815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548163ffffffff021916908363ffffffff1602179055509050508360010193505050506121e1565b50887f7f86e8c5bd6c77e028f6b5152f3429a262fc43bc0cc8a82432db9f1880d7c1e08888604051612427929190614db8565b60405180910390a2610aaf89612ea2565b610add82826000610ac9612c6e565b60006116876133dd565b61245a33610665565b565b600061173783838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250925061324b915050565b6124a5612e78565b6001600160a01b0316336001600160a01b0316146124d5576040516282b42960e81b815260040160405180910390fd5b600080516020614f6483398151915280546000908290859081106124fb576124fb614c50565b906000526020600020906006020160020181905550600181600001848154811061252757612527614c50565b906000526020600020906006020160050160006101000a81548160ff0219169083151502179055508181600001848154811061256557612565614c50565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506125a383612ea2565b505050565b6000611737611a4a84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061334992505050565b6000600261262f85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061351392505050565b60405161263c9190614de7565b602060405180830381855afa158015612659573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061267c9190614e03565b905060007f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e2656000838152602082905260409020549091506001600160a01b031633146126da576040516282b42960e81b815260040160405180910390fd5b60009182526020526040902080546001600160a01b0319166001600160a01b03929092169190911790555050565b612710612e78565b6001600160a01b0316336001600160a01b031614612740576040516282b42960e81b815260040160405180910390fd5b6116f081612b4f565b612751612e78565b6001600160a01b0316336001600160a01b031614612781576040516282b42960e81b815260040160405180910390fd5b6116f0816135ac565b60006116877f559ad51499ae00ca2e9d9d95aab46737c8904ab7da276613fefda282b2c2ac065490565b6127c0600083856135d4565b6125a36127cd8383614cb2565b613899565b60006127de6000612a6d565b905060006127ec6001612a6d565b90506000806127fc600243614c12565b6000036128215761280e600287614c3c565b915061281a8287614cb2565b905061283b565b61282c600287614c3c565b90506128388187614cb2565b91505b835163ffffffff1682111561286d57835161285c9063ffffffff1687614cb2565b845163ffffffff169250905061289c565b825163ffffffff1681111561289c57825161288e9063ffffffff1687614cb2565b835190925063ffffffff1690505b81156128ae576128ae600083896135d4565b80156128c0576128c0600182896135d4565b6128d76128cd8284614c9a565b6127cd9087614cb2565b50505050505050565b805460006128ed826138c2565b905060006128fc600143614cb2565b40905060008367ffffffffffffffff81111561291a5761291a614e1c565b60405190808252806020026020018201604052801561297357816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816129385790505b50905060005b878110156129e65760008061298f85848861393f565b915091506000806129a284848a896139d8565b915091508060ff168260ff16036129c2576129bd8287613a8a565b6129d7565b6129d76129d183838a8a613ac6565b87613a8a565b84600101945050505050612979565b5060005b8151811015612a55576000828281518110612a0757612a07614c50565b60200260200101516060015163ffffffff161115612a4d57612a4d81838381518110612a3557612a35614c50565b60200260200101516060015163ffffffff168b6135d4565b6001016129ea565b50612a636127cd8888614cb2565b5050505050505050565b60408051808201825260008082526020808301828152600286901c83527f37e2c371bbf1c7a1326d52e30855e9c8b6cac15eda4475320e427b948813a9f08252939091205463ffffffff60c060069690961b959095161c8481168352901c909216905290565b60006116877fd5c553085b8382c47128ae7612257fd5dc3b4fc4d3a108925604d3c8700c025b5490565b6116f07fd5c553085b8382c47128ae7612257fd5dc3b4fc4d3a108925604d3c8700c025b829055565b6116f07ffbeda9bc03875013b12a1ec161efb8e5bf7e58e3cec96a1ea9efd3e264d26e64829055565b6116f07f10c92bb459c0223bf996150f2fb702a8288fb8354a33d5b0212e8e6b8273f55e829055565b6116f07fb88142a0318e2b174876bceb4db9dc318011849c83fb8a8bb2997386d562324a829055565b6116f07f41118591c19026bdc7a484e34f80a8e7e632600aff1c72460e9c7dfe94a2dda6829055565b6116f07faa81344d5857c875349bc4a95d531a580c46bdd94c41b35b1e072e4d627079f8829055565b6116f07fb6d5e19fdd6cde5f03ed4f17c2670deffa47975541fd270b0b17e803297d7608829055565b6116f07fbc8b9852d17d50256bb221fdf6ee12d78dd493d807e907f7d223c40d65abd6b9829055565b6116f07fd1c64973da70267569571a091966834c1a36bdba47f2a112b6a95bf41fc9c24e829055565b60006116877faa81344d5857c875349bc4a95d531a580c46bdd94c41b35b1e072e4d627079f85490565b6000612cd985858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061334992505050565b9050600060028483604051602001612cfb929190918252602082015260400190565b60408051601f1981840301815290829052612d1591614de7565b602060405180830381855afa158015612d32573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612d559190614e03565b90506000612d61613b7b565b90506000612d6f8284613ba5565b9050806001600160a01b03163b600003612df157612d8d8284613c0b565b50604051630b302c9560e21b81526001600160a01b03868116600483015260248201869052821690632cc0b25490604401600060405180830381600087803b158015612dd857600080fd5b505af1158015612dec573d6000803e3d6000fd5b505050505b806001600160a01b0316633ccfd60b6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612e2c57600080fd5b505af1158015612e40573d6000803e3d6000fd5b505050505050505050505050565b60006116877fb6d5e19fdd6cde5f03ed4f17c2670deffa47975541fd270b0b17e803297d76085490565b60006116877ffbeda9bc03875013b12a1ec161efb8e5bf7e58e3cec96a1ea9efd3e264d26e645490565b6000612ead82612a6d565b8051600080516020614f648339815191528054929350916000908190612f2090859088908110612edf57612edf614c50565b906000526020600020906006020160020154856000018881548110612f0657612f06614c50565b906000526020600020906006020160030180549050613cab565b9050846020015163ffffffff168111612f4857612f438660008760200151613cbc565b612f6e565b6020850151612f5d9063ffffffff1682614cb2565b9150612f6e86838760200151613cbc565b8163ffffffff168363ffffffff1614611675576116758263ffffffff168463ffffffff16612f9a61278a565b612fa49190614cb2565b6127cd9190614c9a565b6000600080516020614f64833981519152805483908110612fd157612fd1614c50565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156130e057838290600052602060002001805461305390614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461307f90614c66565b80156130cc5780601f106130a1576101008083540402835291602001916130cc565b820191906000526020600020905b8154815290600101906020018083116130af57829003601f168201915b505050505081526020019060010190613034565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156131b957838290600052602060002001805461312c90614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461315890614c66565b80156131a55780601f1061317a576101008083540402835291602001916131a5565b820191906000526020600020905b81548152906001019060200180831161318857829003601f168201915b50505050508152602001906001019061310d565b505050908252506005919091015460ff16151560209091015260a0810151909150156131f857604051630450a9a360e21b815260040160405180910390fd5b80516001600160a01b03163314610add576040516282b42960e81b815260040160405180910390fd5b60006116877fb88142a0318e2b174876bceb4db9dc318011849c83fb8a8bb2997386d562324a5490565b60008061325784613349565b9050600060028483604051602001613279929190918252602082015260400190565b60408051601f198184030181529082905261329391614de7565b602060405180830381855afa1580156132b0573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906132d39190614e03565b905060006132df613b7b565b90506132eb8183613ba5565b9695505050505050565b60006116877f41118591c19026bdc7a484e34f80a8e7e632600aff1c72460e9c7dfe94a2dda65490565b60006116877f10c92bb459c0223bf996150f2fb702a8288fb8354a33d5b0212e8e6b8273f55e5490565b6000600261335683613513565b6040516133639190614de7565b602060405180830381855afa158015613380573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061173a9190614e03565b60009081527f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e26560205260409020546001600160a01b031690565b60006116877e595eca1f8b39945ff4c404827bfa5fd1e295ef3f7d59d120a8ce3bae4e37a05490565b60608161341481601f614c9a565b10156134535760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401611b61565b61345d8284614c9a565b845110156134a15760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401611b61565b6060821580156134c0576040519150600082526020820160405261350a565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156134f95780518352602092830192016134e1565b5050858452601f01601f1916604052505b50949350505050565b6060602082511015801561352957506040825111155b61353557613535614e32565b8151604003613542575090565b6040805160208082528183019092526000916020820181803683370190505090506000602082015282516020036135845761357d8382613d30565b9392505050565b61357d836135a18360008751604061359c9190614cb2565b613406565b613d30565b50919050565b6116f07e595eca1f8b39945ff4c404827bfa5fd1e295ef3f7d59d120a8ce3bae4e37a0829055565b600080516020614f6483398151915280546000908290869081106135fa576135fa614c50565b90600052602060002090600602019050600061361586612a6d565b602081015190915063ffffffff165b85826020015163ffffffff1661363a9190614c9a565b81101561386357600083600301828154811061365857613658614c50565b90600052602060002001805461366d90614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461369990614c66565b80156136e65780601f106136bb576101008083540402835291602001916136e6565b820191906000526020600020905b8154815290600101906020018083116136c957829003601f168201915b50505050509050600084600401838154811061370457613704614c50565b90600052602060002001805461371990614c66565b80601f016020809104026020016040519081016040528092919081815260200182805461374590614c66565b80156137925780601f1061376757610100808354040283529160200191613792565b820191906000526020600020905b81548152906001019060200180831161377557829003601f168201915b5050505050905060006137a683600161324b565b905060006137b382613dad565b90506137c0848483613dc6565b60006137cb85613349565b60008181527f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e26560205260409081902080546001600160a01b0319166001600160a01b038e1690811790915590519192509033907f223e9969a6dc671e5bb38a0e0eb5c4e5a9d80c2cc5951b886895965069a421a29061384b908990614da5565b60405180910390a38560010195505050505050613624565b506116758686836000015163ffffffff1661387e9190614cb2565b87846020015163ffffffff166138949190614c9a565b613cbc565b6116f07f559ad51499ae00ca2e9d9d95aab46737c8904ab7da276613fefda282b2c2ac06829055565b6000806138cd614177565b905060005b6036811015613925578360ff168282603681106138f1576138f1614c50565b602002015160ff161061391d5781816036811061391057613910614c50565b6020020151949350505050565b6001016138d2565b50604051631470905f60e01b815260040160405180910390fd5b60008082856020613951876002614d86565b61395b9190614c12565b6020811061396b5761396b614c50565b6139779291901a614e48565b9150613984600184614e6a565b856020613992876002614d86565b61399d906001614c9a565b6139a79190614c12565b602081106139b7576139b7614c50565b6139c39291901a614e48565b6139ce906001614e8d565b9050935093915050565b60008060001980875b8260010b60001914806139f857508160010b600019145b15613a7c576000613a098288614335565b63ffffffff161115613a33578260010b60001903613a2c578060000b9250613a33565b8060000b91505b8660ff168860ff168260ff16613a499190614c9a565b613a539190614c12565b90508860ff168160ff16148015613a6e57508160010b600019145b15613a77578291505b6139e1565b509097909650945050505050565b6001818360ff1681518110613aa157613aa1614c50565b6020026020010151606001818151613ab99190614eb2565b63ffffffff169052505050565b600080613ad3868461446d565b63ffffffff1690506000613ae7868561446d565b63ffffffff16905080821015613b01578692505050613b73565b80821115613b13578592505050613b73565b60006002866020613b248a8c614e8d565b613b2e9190614e48565b60ff1660208110613b4157613b41614c50565b613b4d9291901a614e48565b60ff1660011490508015156000151503613b6c57869350505050613b73565b8793505050505b949350505050565b60006116877fd1c64973da70267569571a091966834c1a36bdba47f2a112b6a95bf41fc9c24e5490565b6000611737838330604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b03811661173a5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401611b61565b6000818310156135a657508161173a565b600283901c60009081527f37e2c371bbf1c7a1326d52e30855e9c8b6cac15eda4475320e427b948813a9f060209081526040909120805467ffffffffffffffff60c060069790971b9690961695861b191663ffffffff9490941667ffffffff000000009390921b929092161790921b179055565b6060806040519050835180825260208201818101602087015b81831015613d61578051835260209283019201613d49565b50855184518101855292509050808201602086015b81831015613d8e578051835260209283019201613d76565b508651929092011591909101601f01601f191660405250905092915050565b600061173a6001600160a01b038316600160f81b614c9a565b6000613dd184613349565b90506000600280613de58660006040613406565b604051613df29190614de7565b602060405180830381855afa158015613e0f573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190613e329190614e03565b6002613e4d613e4888604061359c816060614cb2565b613513565b604051613e5a9190614de7565b602060405180830381855afa158015613e77573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190613e9a9190614e03565b60408051602081019390935282015260600160408051601f1981840301815290829052613ec691614de7565b602060405180830381855afa158015613ee3573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190613f069190614e03565b90506000613f21633b9aca006801bc16d674ec800000614c3c565b90506801bc16d674ec800000613f3b82633b9aca00614d86565b14613f4857613f48614e32565b60006002808587604051602001613f69929190918252602082015260400190565b60408051601f1981840301815290829052613f8391614de7565b602060405180830381855afa158015613fa0573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190613fc39190614e03565b6002613fce856145a5565b604080516020810192909252810187905260600160408051601f1981840301815290829052613ffc91614de7565b602060405180830381855afa158015614019573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061403c9190614e03565b60408051602081019390935282015260600160408051601f198184030181529082905261406891614de7565b602060405180830381855afa158015614085573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906140a89190614e03565b905060006140bf6801bc16d674ec80000047614cb2565b90506140c96145eb565b6001600160a01b031663228951186801bc16d674ec8000008a896040516020016140f591815260200190565b6040516020818303038152906040528b876040518663ffffffff1660e01b81526004016141259493929190614eda565b6000604051808303818588803b15801561413e57600080fd5b505af1158015614152573d6000803e3d6000fd5b5050505050804714612a6357604051636596d2b760e01b815260040160405180910390fd5b61417f6147a7565b50604080516106c081018252600281526003602082015260059181019190915260076060820152600b6080820152600d60a0820152601160c0820152601360e08201526017610100820152601d610120820152601f61014082015260256101608201526029610180820152602b6101a0820152602f6101c082015260356101e0820152603b610200820152603d610220820152604361024082015260476102608201526049610280820152604f6102a082015260536102c082015260596102e0820152606161030082015260656103208201526067610340820152606b610360820152606d61038082015260716103a0820152607f6103c082015260836103e08201526089610400820152608b61042082015260956104408201526097610460820152609d61048082015260a36104a082015260a76104c082015260ad6104e082015260b361050082015260b561052082015260bf61054082015260c161056082015260c561058082015260c76105a082015260d36105c082015260df6105e082015260e361060082015260e561062082015260e961064082015260ef61066082015260f161068082015260fb6106a082015290565b600081518360ff161061434a5750600061173a565b818360ff168151811061435f5761435f614c50565b602002602001015160000151151560001515036144215760006143848460ff16612a6d565b90506001838560ff168151811061439d5761439d614c50565b6020908102919091018101519115159091528101518351849060ff87169081106143c9576143c9614c50565b60200260200101516040019063ffffffff16908163ffffffff16815250508060000151838560ff168151811061440157614401614c50565b60200260200101516080019063ffffffff16908163ffffffff1681525050505b818360ff168151811061443657614436614c50565b602002602001015160600151828460ff168151811061445757614457614c50565b6020026020010151608001516117379190614f25565b600081518360ff16106144825750600061173a565b818360ff168151811061449757614497614c50565b602002602001015160000151151560001515036145595760006144bc8460ff16612a6d565b90506001838560ff16815181106144d5576144d5614c50565b6020908102919091018101519115159091528101518351849060ff871690811061450157614501614c50565b60200260200101516040019063ffffffff16908163ffffffff16815250508060000151838560ff168151811061453957614539614c50565b60200260200101516080019063ffffffff16908163ffffffff1681525050505b818360ff168151811061456e5761456e614c50565b602002602001015160600151828460ff168151811061458f5761458f614c50565b6020026020010151604001516117379190614eb2565b600081815b60088110156145d357600892831b60ff831617929190911c906145cc81614f4a565b90506145aa565b5080156145e2576145e2614e32565b5060c01b919050565b60006116877fbc8b9852d17d50256bb221fdf6ee12d78dd493d807e907f7d223c40d65abd6b95490565b50805461462190614c66565b6000825580601f10614631575050565b601f0160209004906000526020600020908101906116f091906147c6565b82805461465b90614c66565b90600052602060002090601f01602090048101928261467d57600085556146ca565b82601f1061468e57805485556146ca565b828001600101855582156146ca57600052602060002091601f016020900482015b828111156146ca5782548255916001019190600101906146af565b506146d69291506147c6565b5090565b828054828255906000526020600020908101928215614727579160200282015b828111156147275782518051614717918491602090910190614733565b50916020019190600101906146fa565b506146d69291506147db565b82805461473f90614c66565b90600052602060002090601f01602090048101928261476157600085556146ca565b82601f1061477a57805160ff19168380011785556146ca565b828001600101855582156146ca579182015b828111156146ca57825182559160200191906001019061478c565b604051806106c001604052806036906020820280368337509192915050565b5b808211156146d657600081556001016147c7565b808211156146d65760006147ef8282614615565b506001016147db565b60006020828403121561480a57600080fd5b5035919050565b80356001600160a01b038116811461482857600080fd5b919050565b600080600080600080600080610100898b03121561484a57600080fd5b61485389614811565b975061486160208a01614811565b965061486f60408a01614811565b955061487d60608a01614811565b945061488b60808a01614811565b935061489960a08a01614811565b925060c0890135915060e089013590509295985092959890939650565b60008083601f8401126148c857600080fd5b50813567ffffffffffffffff8111156148e057600080fd5b6020830191508360208285010111156148f857600080fd5b9250929050565b6000806020838503121561491257600080fd5b823567ffffffffffffffff81111561492957600080fd5b614935858286016148b6565b90969095509350505050565b60008060006040848603121561495657600080fd5b83359250602084013567ffffffffffffffff8082111561497557600080fd5b818601915086601f83011261498957600080fd5b81358181111561499857600080fd5b8760208260051b85010111156149ad57600080fd5b6020830194508093505050509250925092565b600080604083850312156149d357600080fd5b823591506149e360208401614811565b90509250929050565b600080604083850312156149ff57600080fd5b50508035926020909101359150565b60005b83811015614a29578181015183820152602001614a11565b8381111561074f5750506000910152565b60008151808452614a52816020860160208601614a0e565b601f01601f19169290920160200192915050565b608081526000614a796080830187614a3a565b8281036020840152614a8b8187614a3a565b6001600160a01b03959095166040840152505090151560609091015292915050565b60008060408385031215614ac057600080fd5b614ac983614811565b91506149e360208401614811565b600080600060608486031215614aec57600080fd5b83359250614afc60208501614811565b9150614b0a60408501614811565b90509250925092565b60008060008060008060808789031215614b2c57600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115614b5257600080fd5b614b5e8a838b016148b6565b90965094506060890135915080821115614b7757600080fd5b50614b8489828a016148b6565b979a9699509497509295939492505050565b600080600060408486031215614bab57600080fd5b833567ffffffffffffffff811115614bc257600080fd5b614bce868287016148b6565b9094509250614b0a905060208501614811565b600060208284031215614bf357600080fd5b61173782614811565b634e487b7160e01b600052601260045260246000fd5b600082614c2157614c21614bfc565b500690565b634e487b7160e01b600052601160045260246000fd5b600082614c4b57614c4b614bfc565b500490565b634e487b7160e01b600052603260045260246000fd5b600181811c90821680614c7a57607f821691505b6020821081036135a657634e487b7160e01b600052602260045260246000fd5b60008219821115614cad57614cad614c26565b500190565b600082821015614cc457614cc4614c26565b500390565b600060208083526000845481600182811c915080831680614ceb57607f831692505b8583108103614d0857634e487b7160e01b85526022600452602485fd5b878601838152602001818015614d255760018114614d3657614d61565b60ff19861682528782019650614d61565b60008b81526020902060005b86811015614d5b57815484820152908501908901614d42565b83019750505b50949998505050505050505050565b634e487b7160e01b600052603160045260246000fd5b6000816000190483118215151615614da057614da0614c26565b500290565b6020815260006117376020830184614a3a565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60008251614df9818460208701614a0e565b9190910192915050565b600060208284031215614e1557600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052600160045260246000fd5b600060ff831680614e5b57614e5b614bfc565b8060ff84160691505092915050565b600060ff821660ff841680821015614e8457614e84614c26565b90039392505050565b600060ff821660ff84168060ff03821115614eaa57614eaa614c26565b019392505050565b600063ffffffff808316818516808303821115614ed157614ed1614c26565b01949350505050565b608081526000614eed6080830187614a3a565b8281036020840152614eff8187614a3a565b90508281036040840152614f138186614a3a565b91505082606083015295945050505050565b600063ffffffff83811690831681811015614f4257614f42614c26565b039392505050565b600060018201614f5c57614f5c614c26565b506001019056fed2a2f1f08ad325daf72af0169949ae210065d6916750ff03abd83510331b7b39a26469706673582212204f754125bd6774b3c7a13c07999e4753f87ab8b58df9a7fbc2e893e0656a6cea64736f6c634300080d0033", + "solcInputHash": "ba9e63c4d731596ae86ac9b18992133c", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Deactivated\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DepositFailure\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"DuplicateValidatorKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Forbidden\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FundedValidatorDeletionAttempt\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidArgument\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDepositValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPublicKeys\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidValidatorCount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaximumOperatorCountAlreadyReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoOperators\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEnoughValidators\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"limit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"keyCount\",\"type\":\"uint256\"}],\"name\":\"OperatorLimitTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsortedIndexes\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"}],\"name\":\"ActivatedOperator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"ChangedAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newGlobalFee\",\"type\":\"uint256\"}],\"name\":\"ChangedGlobalFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"operatorIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"operatorAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"feeRecipientAddress\",\"type\":\"address\"}],\"name\":\"ChangedOperatorAddresses\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newOperatorFee\",\"type\":\"uint256\"}],\"name\":\"ChangedOperatorFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"operatorIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"limit\",\"type\":\"uint256\"}],\"name\":\"ChangedOperatorLimit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newTreasury\",\"type\":\"address\"}],\"name\":\"ChangedTreasury\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newWithdrawer\",\"type\":\"address\"}],\"name\":\"ChangedWithdrawer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"}],\"name\":\"DeactivatedOperator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"operatorAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"feeRecipientAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"NewOperator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"SetWithdrawerCustomizationStatus\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"operatorIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"name\":\"ValidatorKeyRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"operatorIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"publicKeys\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"}],\"name\":\"ValidatorKeysAdded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"DEPOSIT_SIZE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PUBLIC_KEY_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SIGNATURE_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_newFeeRecipient\",\"type\":\"address\"}],\"name\":\"activateOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_operatorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeRecipientAddress\",\"type\":\"address\"}],\"name\":\"addOperator\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_keyCount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_publicKeys\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_signatures\",\"type\":\"bytes\"}],\"name\":\"addValidators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_temporaryFeeRecipient\",\"type\":\"address\"}],\"name\":\"deactivateOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAvailableValidatorCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"getCLFeeRecipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"getELFeeRecipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGlobalFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"}],\"name\":\"getOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"operatorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeRecipientAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"limit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"keys\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"funded\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"deactivated\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOperatorFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"pubKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"getOperatorFeeRecipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPendingAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTreasury\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_validatorIndex\",\"type\":\"uint256\"}],\"name\":\"getValidator\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"funded\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"getWithdrawer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_publicKeyRoot\",\"type\":\"bytes32\"}],\"name\":\"getWithdrawerFromPublicKeyRoot\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_admin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_treasury\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_depositContract\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_elDispatcher\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_clDispatcher\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeRecipientImplementation\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_globalFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_operatorFee\",\"type\":\"uint256\"}],\"name\":\"initialize_1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_indexes\",\"type\":\"uint256[]\"}],\"name\":\"removeValidators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_globalFee\",\"type\":\"uint256\"}],\"name\":\"setGlobalFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_operatorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_feeRecipientAddress\",\"type\":\"address\"}],\"name\":\"setOperatorAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorFee\",\"type\":\"uint256\"}],\"name\":\"setOperatorFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_operatorIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_limit\",\"type\":\"uint256\"}],\"name\":\"setOperatorLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newTreasury\",\"type\":\"address\"}],\"name\":\"setTreasury\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"_newWithdrawer\",\"type\":\"address\"}],\"name\":\"setWithdrawer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_enabled\",\"type\":\"bool\"}],\"name\":\"setWithdrawerCustomizationEnabled\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newAdmin\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"withdrawCLFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_publicKey\",\"type\":\"bytes\"}],\"name\":\"withdrawELFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Kiln\",\"kind\":\"dev\",\"methods\":{\"acceptOwnership()\":{\"details\":\"Only callable by new admin\"},\"activateOperator(uint256,address)\":{\"params\":{\"_newFeeRecipient\":\"Sets the fee recipient address\",\"_operatorIndex\":\"Operator Index\"}},\"addOperator(address,address)\":{\"details\":\"Only callable by admin\",\"params\":{\"_feeRecipientAddress\":\"Operator address used to manage rewards\",\"_operatorAddress\":\"Operator address allowed to add / remove validators\"}},\"addValidators(uint256,uint256,bytes,bytes)\":{\"details\":\"Only callable by operator\",\"params\":{\"_keyCount\":\"Number of keys added\",\"_operatorIndex\":\"Operator Index\",\"_publicKeys\":\"Concatenated _keyCount public keys\",\"_signatures\":\"Concatenated _keyCount signatures\"}},\"deactivateOperator(uint256,address)\":{\"params\":{\"_operatorIndex\":\"Operator Index\",\"_temporaryFeeRecipient\":\"Temporary address to receive funds decided by the system admin\"}},\"deposit()\":{\"details\":\"A multiple of 32 ETH should be sent\"},\"getCLFeeRecipient(bytes)\":{\"params\":{\"_publicKey\":\"Validator to get the recipient\"}},\"getELFeeRecipient(bytes)\":{\"params\":{\"_publicKey\":\"Validator to get the recipient\"}},\"getOperator(uint256)\":{\"params\":{\"_operatorIndex\":\"Operator index\"}},\"getValidator(uint256,uint256)\":{\"params\":{\"_operatorIndex\":\"Index of the operator running the validator\",\"_validatorIndex\":\"Index of the validator\"}},\"getWithdrawer(bytes)\":{\"params\":{\"_publicKey\":\"Public Key to check\"}},\"getWithdrawerFromPublicKeyRoot(bytes32)\":{\"params\":{\"_publicKeyRoot\":\"Hash of the public key\"}},\"removeValidators(uint256,uint256[])\":{\"details\":\"Only callable by operatorIndexes should be provided in decreasing orderThe limit will be set to the lowest removed operator index to ensure all changes above the lowest removed validator key are verified by the system administrator\",\"params\":{\"_indexes\":\"List of indexes to delete, in decreasing order\",\"_operatorIndex\":\"Operator Index\"}},\"setGlobalFee(uint256)\":{\"params\":{\"_globalFee\":\"Fee in Basis Point\"}},\"setOperatorAddresses(uint256,address,address)\":{\"details\":\"Only callable by fee recipient address manager\",\"params\":{\"_feeRecipientAddress\":\"New operator address for reward management\",\"_operatorAddress\":\"New operator address for operations management\",\"_operatorIndex\":\"Index of the operator to update\"}},\"setOperatorFee(uint256)\":{\"params\":{\"_operatorFee\":\"Fee in Basis Point\"}},\"setOperatorLimit(uint256,uint256)\":{\"details\":\"Only callable by adminLimit should not exceed the validator key count of the operatorKeys should be registered before limit is increasedAllows all keys to be verified by the system admin before limit is increased\",\"params\":{\"_limit\":\"New staking limit\",\"_operatorIndex\":\"Operator Index\"}},\"setTreasury(address)\":{\"details\":\"Only callable by admin\",\"params\":{\"_newTreasury\":\"New Treasury address\"}},\"setWithdrawer(bytes,address)\":{\"details\":\"Only callable by current public key withdrawer\",\"params\":{\"_newWithdrawer\":\"New withdrawer address\",\"_publicKey\":\"Public key to change withdrawer\"}},\"setWithdrawerCustomizationEnabled(bool)\":{\"params\":{\"_enabled\":\"True to allow users to customize the withdrawer\"}},\"transferOwnership(address)\":{\"details\":\"Only callable by admin\",\"params\":{\"_newAdmin\":\"New Administrator address\"}},\"withdraw(bytes)\":{\"details\":\"Reverts if any is null\",\"params\":{\"_publicKey\":\"Validator to withdraw Execution and Consensus Layer Fees from\"}},\"withdrawCLFee(bytes)\":{\"details\":\"Funds are sent to the withdrawer accountThis method is public on purpose\",\"params\":{\"_publicKey\":\"Validator to withdraw Consensus Layer Fees from\"}},\"withdrawELFee(bytes)\":{\"details\":\"Funds are sent to the withdrawer accountThis method is public on purpose\",\"params\":{\"_publicKey\":\"Validator to withdraw Execution Layer Fees from\"}}},\"title\":\"Ethereum Staking Contract\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"acceptOwnership()\":{\"notice\":\"New admin must accept its role by calling this method\"},\"activateOperator(uint256,address)\":{\"notice\":\"Activates an operator, without changing its 0 staking limit\"},\"addOperator(address,address)\":{\"notice\":\"Add new operator\"},\"addValidators(uint256,uint256,bytes,bytes)\":{\"notice\":\"Add new validator public keys and signatures\"},\"deactivateOperator(uint256,address)\":{\"notice\":\"Deactivates an operator and changes the fee recipient address and the staking limit\"},\"deposit()\":{\"notice\":\"Explicit deposit method using msg.sender\"},\"getAdmin()\":{\"notice\":\"Retrieve system admin\"},\"getAvailableValidatorCount()\":{\"notice\":\"Get the total available keys that are ready to be used for deposits\"},\"getCLFeeRecipient(bytes)\":{\"notice\":\"Compute the Consensus Layer Fee recipient address for a given validator public key\"},\"getELFeeRecipient(bytes)\":{\"notice\":\"Compute the Execution Layer Fee recipient address for a given validator public key\"},\"getGlobalFee()\":{\"notice\":\"Retrieve the global fee\"},\"getOperator(uint256)\":{\"notice\":\"Retrieve operator details\"},\"getOperatorFee()\":{\"notice\":\"Retrieve the operator fee\"},\"getOperatorFeeRecipient(bytes32)\":{\"notice\":\"Retrieve the Execution & Consensus Layer Fee operator recipient for a given public key\"},\"getPendingAdmin()\":{\"notice\":\"Get the new admin's address previously set for an ownership transfer\"},\"getTreasury()\":{\"notice\":\"Retrieve system treasury\"},\"getValidator(uint256,uint256)\":{\"notice\":\"Get details about a validator\"},\"getWithdrawer(bytes)\":{\"notice\":\"Retrieve withdrawer of public key\"},\"getWithdrawerFromPublicKeyRoot(bytes32)\":{\"notice\":\"Retrieve withdrawer of public key root\"},\"removeValidators(uint256,uint256[])\":{\"notice\":\"Remove unfunded validators\"},\"setGlobalFee(uint256)\":{\"notice\":\"Change the Global fee\"},\"setOperatorAddresses(uint256,address,address)\":{\"notice\":\"Set new operator addresses (operations and reward management)\"},\"setOperatorFee(uint256)\":{\"notice\":\"Change the Operator fee\"},\"setOperatorLimit(uint256,uint256)\":{\"notice\":\"Set operator staking limits\"},\"setTreasury(address)\":{\"notice\":\"Set new treasury\"},\"setWithdrawer(bytes,address)\":{\"notice\":\"Set withdrawer for public key\"},\"setWithdrawerCustomizationEnabled(bool)\":{\"notice\":\"Changes the behavior of the withdrawer customization logic\"},\"transferOwnership(address)\":{\"notice\":\"Set new admin\"},\"withdraw(bytes)\":{\"notice\":\"Withdraw both Consensus and Execution Layer Fee for a given validator public key\"},\"withdrawCLFee(bytes)\":{\"notice\":\"Withdraw the Consensus Layer Fee for a given validator public key\"},\"withdrawELFee(bytes)\":{\"notice\":\"Withdraw the Execution Layer Fee for a given validator public key\"}},\"notice\":\"You can use this contract to store validator keys and have users fund them and trigger deposits.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/contracts/StakingContract.sol\":\"StakingContract\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/proxy/Clones.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\\n * deploying minimal proxy contracts, also known as \\\"clones\\\".\\n *\\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\\n *\\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\\n * deterministic method.\\n *\\n * _Available since v3.4._\\n */\\nlibrary Clones {\\n /**\\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\\n *\\n * This function uses the create opcode, which should never revert.\\n */\\n function clone(address implementation) internal returns (address instance) {\\n assembly {\\n let ptr := mload(0x40)\\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\\n mstore(add(ptr, 0x14), shl(0x60, implementation))\\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\\n instance := create(0, ptr, 0x37)\\n }\\n require(instance != address(0), \\\"ERC1167: create failed\\\");\\n }\\n\\n /**\\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\\n *\\n * This function uses the create2 opcode and a `salt` to deterministically deploy\\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\\n * the clones cannot be deployed twice at the same address.\\n */\\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\\n assembly {\\n let ptr := mload(0x40)\\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\\n mstore(add(ptr, 0x14), shl(0x60, implementation))\\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\\n instance := create2(0, ptr, 0x37, salt)\\n }\\n require(instance != address(0), \\\"ERC1167: create2 failed\\\");\\n }\\n\\n /**\\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\\n */\\n function predictDeterministicAddress(\\n address implementation,\\n bytes32 salt,\\n address deployer\\n ) internal pure returns (address predicted) {\\n assembly {\\n let ptr := mload(0x40)\\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\\n mstore(add(ptr, 0x14), shl(0x60, implementation))\\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\\n mstore(add(ptr, 0x38), shl(0x60, deployer))\\n mstore(add(ptr, 0x4c), salt)\\n mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\\n predicted := keccak256(add(ptr, 0x37), 0x55)\\n }\\n }\\n\\n /**\\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\\n */\\n function predictDeterministicAddress(address implementation, bytes32 salt)\\n internal\\n view\\n returns (address predicted)\\n {\\n return predictDeterministicAddress(implementation, salt, address(this));\\n }\\n}\\n\",\"keccak256\":\"0x1cc0efb01cbf008b768fd7b334786a6e358809198bb7e67f1c530af4957c6a21\",\"license\":\"MIT\"},\"src/contracts/StakingContract.sol\":{\"content\":\"//SPDX-License-Identifier: BUSL-1.1\\npragma solidity >=0.8.10;\\n\\nimport \\\"./libs/UintLib.sol\\\";\\nimport \\\"./libs/BytesLib.sol\\\";\\nimport \\\"./interfaces/IFeeRecipient.sol\\\";\\nimport \\\"./interfaces/IDepositContract.sol\\\";\\nimport \\\"./libs/StakingContractStorageLib.sol\\\";\\nimport \\\"@openzeppelin/contracts/proxy/Clones.sol\\\";\\n\\n/// @title Ethereum Staking Contract\\n/// @author Kiln\\n/// @notice You can use this contract to store validator keys and have users fund them and trigger deposits.\\ncontract StakingContract {\\n using StakingContractStorageLib for bytes32;\\n\\n uint256 internal constant EXECUTION_LAYER_SALT_PREFIX = 0;\\n uint256 internal constant CONSENSUS_LAYER_SALT_PREFIX = 1;\\n uint256 public constant SIGNATURE_LENGTH = 96;\\n uint256 public constant PUBLIC_KEY_LENGTH = 48;\\n uint256 public constant DEPOSIT_SIZE = 32 ether;\\n uint256 internal constant BASIS_POINTS = 10_000;\\n\\n error Forbidden();\\n error InvalidFee();\\n error Deactivated();\\n error NoOperators();\\n error InvalidCall();\\n error Unauthorized();\\n error DepositFailure();\\n error InvalidArgument();\\n error UnsortedIndexes();\\n error InvalidPublicKeys();\\n error InvalidSignatures();\\n error AlreadyInitialized();\\n error InvalidDepositValue();\\n error NotEnoughValidators();\\n error InvalidValidatorCount();\\n error DuplicateValidatorKey(bytes);\\n error FundedValidatorDeletionAttempt();\\n error OperatorLimitTooHigh(uint256 limit, uint256 keyCount);\\n error MaximumOperatorCountAlreadyReached();\\n\\n struct ValidatorAllocationCache {\\n bool used;\\n uint8 operatorIndex;\\n uint32 funded;\\n uint32 toDeposit;\\n uint32 available;\\n }\\n\\n event Deposit(address indexed caller, address indexed withdrawer, bytes publicKey, bytes signature);\\n event ValidatorKeysAdded(uint256 indexed operatorIndex, bytes publicKeys, bytes signatures);\\n event ValidatorKeyRemoved(uint256 indexed operatorIndex, bytes publicKey);\\n event ChangedWithdrawer(bytes publicKey, address newWithdrawer);\\n event ChangedOperatorLimit(uint256 operatorIndex, uint256 limit);\\n event ChangedTreasury(address newTreasury);\\n event ChangedGlobalFee(uint256 newGlobalFee);\\n event ChangedOperatorFee(uint256 newOperatorFee);\\n event ChangedAdmin(address newAdmin);\\n event NewOperator(address operatorAddress, address feeRecipientAddress, uint256 index);\\n event ChangedOperatorAddresses(uint256 operatorIndex, address operatorAddress, address feeRecipientAddress);\\n event DeactivatedOperator(uint256 _operatorIndex);\\n event ActivatedOperator(uint256 _operatorIndex);\\n event SetWithdrawerCustomizationStatus(bool _status);\\n\\n /// @notice Ensures an initialisation call has been called only once per _version value\\n /// @param _version The current initialisation value\\n modifier init(uint256 _version) {\\n if (_version != StakingContractStorageLib.getVersion() + 1) {\\n revert AlreadyInitialized();\\n }\\n\\n StakingContractStorageLib.setVersion(_version);\\n _;\\n }\\n\\n /// @notice Ensures that the caller is the admin\\n modifier onlyAdmin() {\\n if (msg.sender != StakingContractStorageLib.getAdmin()) {\\n revert Unauthorized();\\n }\\n\\n _;\\n }\\n\\n /// @notice Ensures that the caller is the admin or the operator\\n modifier onlyActiveOperatorOrAdmin(uint256 _operatorIndex) {\\n if (msg.sender == StakingContractStorageLib.getAdmin()) {\\n _;\\n } else {\\n _onlyActiveOperator(_operatorIndex);\\n _;\\n }\\n }\\n\\n /// @notice Ensures that the caller is the admin\\n modifier onlyActiveOperator(uint256 _operatorIndex) {\\n _onlyActiveOperator(_operatorIndex);\\n _;\\n }\\n\\n /// @notice Ensures that the caller is the operator fee recipient\\n modifier onlyOperatorFeeRecipient(uint256 _operatorIndex) {\\n StakingContractStorageLib.OperatorInfo memory operatorInfo = StakingContractStorageLib.getOperators().value[\\n _operatorIndex\\n ];\\n\\n if (operatorInfo.deactivated) {\\n revert Deactivated();\\n }\\n\\n if (msg.sender != operatorInfo.feeRecipient) {\\n revert Unauthorized();\\n }\\n\\n _;\\n }\\n\\n /// @notice Explicit deposit method using msg.sender\\n /// @dev A multiple of 32 ETH should be sent\\n function deposit() external payable {\\n _deposit(msg.sender);\\n }\\n\\n /// @notice Implicit deposit method\\n /// @dev A multiple of 32 ETH should be sent\\n /// @dev The withdrawer is set to the message sender address\\n receive() external payable {\\n _deposit(msg.sender);\\n }\\n\\n /// @notice Fallback detection\\n /// @dev Fails on any call that fallbacks\\n fallback() external payable {\\n revert InvalidCall();\\n }\\n\\n function initialize_1(\\n address _admin,\\n address _treasury,\\n address _depositContract,\\n address _elDispatcher,\\n address _clDispatcher,\\n address _feeRecipientImplementation,\\n uint256 _globalFee,\\n uint256 _operatorFee\\n ) external init(1) {\\n StakingContractStorageLib.setAdmin(_admin);\\n StakingContractStorageLib.setTreasury(_treasury);\\n\\n if (_globalFee > BASIS_POINTS) {\\n revert InvalidFee();\\n }\\n StakingContractStorageLib.setGlobalFee(_globalFee);\\n if (_operatorFee > BASIS_POINTS) {\\n revert InvalidFee();\\n }\\n StakingContractStorageLib.setOperatorFee(_operatorFee);\\n\\n StakingContractStorageLib.setELDispatcher(_elDispatcher);\\n StakingContractStorageLib.setCLDispatcher(_clDispatcher);\\n StakingContractStorageLib.setDepositContract(_depositContract);\\n StakingContractStorageLib.setFeeRecipientImplementation(_feeRecipientImplementation);\\n }\\n\\n /// @notice Changes the behavior of the withdrawer customization logic\\n /// @param _enabled True to allow users to customize the withdrawer\\n function setWithdrawerCustomizationEnabled(bool _enabled) external onlyAdmin {\\n StakingContractStorageLib.setWithdrawerCustomizationEnabled(_enabled);\\n emit SetWithdrawerCustomizationStatus(_enabled);\\n }\\n\\n /// @notice Retrieve system admin\\n function getAdmin() external view returns (address) {\\n return StakingContractStorageLib.getAdmin();\\n }\\n\\n /// @notice Set new treasury\\n /// @dev Only callable by admin\\n /// @param _newTreasury New Treasury address\\n function setTreasury(address _newTreasury) external onlyAdmin {\\n emit ChangedTreasury(_newTreasury);\\n StakingContractStorageLib.setTreasury(_newTreasury);\\n }\\n\\n /// @notice Retrieve system treasury\\n function getTreasury() external view returns (address) {\\n return StakingContractStorageLib.getTreasury();\\n }\\n\\n /// @notice Retrieve the global fee\\n function getGlobalFee() external view returns (uint256) {\\n return StakingContractStorageLib.getGlobalFee();\\n }\\n\\n /// @notice Retrieve the operator fee\\n function getOperatorFee() external view returns (uint256) {\\n return StakingContractStorageLib.getOperatorFee();\\n }\\n\\n /// @notice Compute the Execution Layer Fee recipient address for a given validator public key\\n /// @param _publicKey Validator to get the recipient\\n function getELFeeRecipient(bytes calldata _publicKey) external view returns (address) {\\n return _getDeterministicReceiver(_publicKey, EXECUTION_LAYER_SALT_PREFIX);\\n }\\n\\n /// @notice Compute the Consensus Layer Fee recipient address for a given validator public key\\n /// @param _publicKey Validator to get the recipient\\n function getCLFeeRecipient(bytes calldata _publicKey) external view returns (address) {\\n return _getDeterministicReceiver(_publicKey, CONSENSUS_LAYER_SALT_PREFIX);\\n }\\n\\n /// @notice Retrieve the Execution & Consensus Layer Fee operator recipient for a given public key\\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address) {\\n return\\n StakingContractStorageLib\\n .getOperators()\\n .value[StakingContractStorageLib.getOperatorIndexPerValidator().value[pubKeyRoot].operatorIndex]\\n .feeRecipient;\\n }\\n\\n /// @notice Retrieve withdrawer of public key\\n /// @param _publicKey Public Key to check\\n function getWithdrawer(bytes calldata _publicKey) external view returns (address) {\\n return _getWithdrawer(_getPubKeyRoot(_publicKey));\\n }\\n\\n /// @notice Retrieve withdrawer of public key root\\n /// @param _publicKeyRoot Hash of the public key\\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address) {\\n return _getWithdrawer(_publicKeyRoot);\\n }\\n\\n /// @notice Retrieve operator details\\n /// @param _operatorIndex Operator index\\n function getOperator(uint256 _operatorIndex)\\n external\\n view\\n returns (\\n address operatorAddress,\\n address feeRecipientAddress,\\n uint256 limit,\\n uint256 keys,\\n uint256 funded,\\n uint256 available,\\n bool deactivated\\n )\\n {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n if (_operatorIndex < operators.value.length) {\\n StakingContractStorageLib.ValidatorsFundingInfo memory _operatorInfo = StakingContractStorageLib\\n .getValidatorsFundingInfo(_operatorIndex);\\n StakingContractStorageLib.OperatorInfo memory _operator = operators.value[_operatorIndex];\\n\\n (operatorAddress, feeRecipientAddress, limit, keys, deactivated) = (\\n _operator.operator,\\n _operator.feeRecipient,\\n _operator.limit,\\n _operator.publicKeys.length,\\n _operator.deactivated\\n );\\n (funded, available) = (_operatorInfo.funded, _operatorInfo.availableKeys);\\n }\\n }\\n\\n /// @notice Get details about a validator\\n /// @param _operatorIndex Index of the operator running the validator\\n /// @param _validatorIndex Index of the validator\\n function getValidator(uint256 _operatorIndex, uint256 _validatorIndex)\\n external\\n view\\n returns (\\n bytes memory publicKey,\\n bytes memory signature,\\n address withdrawer,\\n bool funded\\n )\\n {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n publicKey = operators.value[_operatorIndex].publicKeys[_validatorIndex];\\n signature = operators.value[_operatorIndex].signatures[_validatorIndex];\\n withdrawer = _getWithdrawer(_getPubKeyRoot(publicKey));\\n funded = _validatorIndex < StakingContractStorageLib.getValidatorsFundingInfo(_operatorIndex).funded;\\n }\\n\\n /// @notice Get the total available keys that are ready to be used for deposits\\n function getAvailableValidatorCount() external view returns (uint256) {\\n return StakingContractStorageLib.getTotalAvailableValidators();\\n }\\n\\n /// @notice Set new admin\\n /// @dev Only callable by admin\\n /// @param _newAdmin New Administrator address\\n function transferOwnership(address _newAdmin) external onlyAdmin {\\n StakingContractStorageLib.setPendingAdmin(_newAdmin);\\n }\\n\\n /// @notice New admin must accept its role by calling this method\\n /// @dev Only callable by new admin\\n function acceptOwnership() external {\\n address newAdmin = StakingContractStorageLib.getPendingAdmin();\\n\\n if (msg.sender != newAdmin) {\\n revert Unauthorized();\\n }\\n StakingContractStorageLib.setAdmin(newAdmin);\\n emit ChangedAdmin(newAdmin);\\n }\\n\\n /// @notice Get the new admin's address previously set for an ownership transfer\\n function getPendingAdmin() external view returns (address) {\\n return StakingContractStorageLib.getPendingAdmin();\\n }\\n\\n /// @notice Add new operator\\n /// @dev Only callable by admin\\n /// @param _operatorAddress Operator address allowed to add / remove validators\\n /// @param _feeRecipientAddress Operator address used to manage rewards\\n function addOperator(address _operatorAddress, address _feeRecipientAddress) external onlyAdmin returns (uint256) {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n StakingContractStorageLib.OperatorInfo memory newOperator;\\n\\n if (operators.value.length == 251) {\\n revert MaximumOperatorCountAlreadyReached();\\n }\\n newOperator.operator = _operatorAddress;\\n newOperator.feeRecipient = _feeRecipientAddress;\\n operators.value.push(newOperator);\\n uint256 operatorIndex = operators.value.length - 1;\\n emit NewOperator(_operatorAddress, _feeRecipientAddress, operatorIndex);\\n return operatorIndex;\\n }\\n\\n /// @notice Set new operator addresses (operations and reward management)\\n /// @dev Only callable by fee recipient address manager\\n /// @param _operatorIndex Index of the operator to update\\n /// @param _operatorAddress New operator address for operations management\\n /// @param _feeRecipientAddress New operator address for reward management\\n function setOperatorAddresses(\\n uint256 _operatorIndex,\\n address _operatorAddress,\\n address _feeRecipientAddress\\n ) external onlyOperatorFeeRecipient(_operatorIndex) {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n\\n operators.value[_operatorIndex].operator = _operatorAddress;\\n operators.value[_operatorIndex].feeRecipient = _feeRecipientAddress;\\n emit ChangedOperatorAddresses(_operatorIndex, _operatorAddress, _feeRecipientAddress);\\n }\\n\\n /// @notice Set withdrawer for public key\\n /// @dev Only callable by current public key withdrawer\\n /// @param _publicKey Public key to change withdrawer\\n /// @param _newWithdrawer New withdrawer address\\n function setWithdrawer(bytes calldata _publicKey, address _newWithdrawer) external {\\n if (!StakingContractStorageLib.getWithdrawerCustomizationEnabled()) {\\n revert Forbidden();\\n }\\n bytes32 pubkeyRoot = sha256(BytesLib.pad64(_publicKey));\\n StakingContractStorageLib.WithdrawersSlot storage withdrawers = StakingContractStorageLib.getWithdrawers();\\n\\n if (withdrawers.value[pubkeyRoot] != msg.sender) {\\n revert Unauthorized();\\n }\\n\\n emit ChangedWithdrawer(_publicKey, _newWithdrawer);\\n\\n withdrawers.value[pubkeyRoot] = _newWithdrawer;\\n }\\n\\n /// @notice Set operator staking limits\\n /// @dev Only callable by admin\\n /// @dev Limit should not exceed the validator key count of the operator\\n /// @dev Keys should be registered before limit is increased\\n /// @dev Allows all keys to be verified by the system admin before limit is increased\\n /// @param _operatorIndex Operator Index\\n /// @param _limit New staking limit\\n function setOperatorLimit(uint256 _operatorIndex, uint256 _limit) external onlyAdmin {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n if (operators.value[_operatorIndex].deactivated) {\\n revert Deactivated();\\n }\\n uint256 publicKeyCount = operators.value[_operatorIndex].publicKeys.length;\\n if (publicKeyCount < _limit) {\\n revert OperatorLimitTooHigh(_limit, publicKeyCount);\\n }\\n operators.value[_operatorIndex].limit = _limit;\\n _updateAvailableValidatorCount(_operatorIndex);\\n emit ChangedOperatorLimit(_operatorIndex, _limit);\\n }\\n\\n /// @notice Deactivates an operator and changes the fee recipient address and the staking limit\\n /// @param _operatorIndex Operator Index\\n /// @param _temporaryFeeRecipient Temporary address to receive funds decided by the system admin\\n function deactivateOperator(uint256 _operatorIndex, address _temporaryFeeRecipient) external onlyAdmin {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n operators.value[_operatorIndex].limit = 0;\\n emit ChangedOperatorLimit(_operatorIndex, 0);\\n operators.value[_operatorIndex].deactivated = true;\\n emit DeactivatedOperator(_operatorIndex);\\n operators.value[_operatorIndex].feeRecipient = _temporaryFeeRecipient;\\n emit ChangedOperatorAddresses(_operatorIndex, operators.value[_operatorIndex].operator, _temporaryFeeRecipient);\\n _updateAvailableValidatorCount(_operatorIndex);\\n }\\n\\n /// @notice Activates an operator, without changing its 0 staking limit\\n /// @param _operatorIndex Operator Index\\n /// @param _newFeeRecipient Sets the fee recipient address\\n function activateOperator(uint256 _operatorIndex, address _newFeeRecipient) external onlyAdmin {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n operators.value[_operatorIndex].deactivated = false;\\n emit ActivatedOperator(_operatorIndex);\\n operators.value[_operatorIndex].feeRecipient = _newFeeRecipient;\\n emit ChangedOperatorAddresses(_operatorIndex, operators.value[_operatorIndex].operator, _newFeeRecipient);\\n }\\n\\n /// @notice Change the Operator fee\\n /// @param _operatorFee Fee in Basis Point\\n function setOperatorFee(uint256 _operatorFee) external onlyAdmin {\\n if (_operatorFee > BASIS_POINTS) {\\n revert InvalidFee();\\n }\\n StakingContractStorageLib.setOperatorFee(_operatorFee);\\n emit ChangedOperatorFee(_operatorFee);\\n }\\n\\n /// @notice Change the Global fee\\n /// @param _globalFee Fee in Basis Point\\n function setGlobalFee(uint256 _globalFee) external onlyAdmin {\\n if (_globalFee > BASIS_POINTS) {\\n revert InvalidFee();\\n }\\n StakingContractStorageLib.setGlobalFee(_globalFee);\\n emit ChangedGlobalFee(_globalFee);\\n }\\n\\n /// @notice Add new validator public keys and signatures\\n /// @dev Only callable by operator\\n /// @param _operatorIndex Operator Index\\n /// @param _keyCount Number of keys added\\n /// @param _publicKeys Concatenated _keyCount public keys\\n /// @param _signatures Concatenated _keyCount signatures\\n function addValidators(\\n uint256 _operatorIndex,\\n uint256 _keyCount,\\n bytes calldata _publicKeys,\\n bytes calldata _signatures\\n ) external onlyActiveOperator(_operatorIndex) {\\n if (_keyCount == 0) {\\n revert InvalidArgument();\\n }\\n\\n if (_publicKeys.length % PUBLIC_KEY_LENGTH != 0 || _publicKeys.length / PUBLIC_KEY_LENGTH != _keyCount) {\\n revert InvalidPublicKeys();\\n }\\n\\n if (_signatures.length % SIGNATURE_LENGTH != 0 || _signatures.length / SIGNATURE_LENGTH != _keyCount) {\\n revert InvalidSignatures();\\n }\\n\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n StakingContractStorageLib.OperatorIndexPerValidatorSlot\\n storage operatorIndexPerValidator = StakingContractStorageLib.getOperatorIndexPerValidator();\\n\\n for (uint256 i; i < _keyCount; ) {\\n bytes memory publicKey = BytesLib.slice(_publicKeys, i * PUBLIC_KEY_LENGTH, PUBLIC_KEY_LENGTH);\\n bytes memory signature = BytesLib.slice(_signatures, i * SIGNATURE_LENGTH, SIGNATURE_LENGTH);\\n\\n operators.value[_operatorIndex].publicKeys.push(publicKey);\\n operators.value[_operatorIndex].signatures.push(signature);\\n\\n bytes32 pubKeyRoot = _getPubKeyRoot(publicKey);\\n\\n if (operatorIndexPerValidator.value[pubKeyRoot].enabled) {\\n revert DuplicateValidatorKey(publicKey);\\n }\\n\\n operatorIndexPerValidator.value[pubKeyRoot] = StakingContractStorageLib.OperatorIndex({\\n enabled: true,\\n operatorIndex: uint32(_operatorIndex)\\n });\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n emit ValidatorKeysAdded(_operatorIndex, _publicKeys, _signatures);\\n\\n _updateAvailableValidatorCount(_operatorIndex);\\n }\\n\\n /// @notice Remove unfunded validators\\n /// @dev Only callable by operator\\n /// @dev Indexes should be provided in decreasing order\\n /// @dev The limit will be set to the lowest removed operator index to ensure all changes above the\\n /// lowest removed validator key are verified by the system administrator\\n /// @param _operatorIndex Operator Index\\n /// @param _indexes List of indexes to delete, in decreasing order\\n function removeValidators(uint256 _operatorIndex, uint256[] calldata _indexes)\\n external\\n onlyActiveOperatorOrAdmin(_operatorIndex)\\n {\\n if (_indexes.length == 0) {\\n revert InvalidArgument();\\n }\\n\\n StakingContractStorageLib.ValidatorsFundingInfo memory operatorInfo = StakingContractStorageLib\\n .getValidatorsFundingInfo(_operatorIndex);\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n\\n if (_indexes[_indexes.length - 1] < operatorInfo.funded) {\\n revert FundedValidatorDeletionAttempt();\\n }\\n for (uint256 i; i < _indexes.length; ) {\\n if (i > 0 && _indexes[i] >= _indexes[i - 1]) {\\n revert UnsortedIndexes();\\n }\\n\\n emit ValidatorKeyRemoved(_operatorIndex, operators.value[_operatorIndex].publicKeys[_indexes[i]]);\\n if (_indexes[i] == operators.value[_operatorIndex].publicKeys.length - 1) {\\n operators.value[_operatorIndex].publicKeys.pop();\\n operators.value[_operatorIndex].signatures.pop();\\n } else {\\n operators.value[_operatorIndex].publicKeys[_indexes[i]] = operators.value[_operatorIndex].publicKeys[\\n operators.value[_operatorIndex].publicKeys.length - 1\\n ];\\n operators.value[_operatorIndex].publicKeys.pop();\\n operators.value[_operatorIndex].signatures[_indexes[i]] = operators.value[_operatorIndex].signatures[\\n operators.value[_operatorIndex].signatures.length - 1\\n ];\\n operators.value[_operatorIndex].signatures.pop();\\n }\\n\\n unchecked {\\n ++i;\\n }\\n }\\n\\n if (_indexes[_indexes.length - 1] < operators.value[_operatorIndex].limit) {\\n operators.value[_operatorIndex].limit = _indexes[_indexes.length - 1];\\n emit ChangedOperatorLimit(_operatorIndex, _indexes[_indexes.length - 1]);\\n }\\n\\n _updateAvailableValidatorCount(_operatorIndex);\\n }\\n\\n /// @notice Withdraw the Execution Layer Fee for a given validator public key\\n /// @dev Funds are sent to the withdrawer account\\n /// @dev This method is public on purpose\\n /// @param _publicKey Validator to withdraw Execution Layer Fees from\\n function withdrawELFee(bytes calldata _publicKey) external {\\n _deployAndWithdraw(_publicKey, EXECUTION_LAYER_SALT_PREFIX, StakingContractStorageLib.getELDispatcher());\\n }\\n\\n /// @notice Withdraw the Consensus Layer Fee for a given validator public key\\n /// @dev Funds are sent to the withdrawer account\\n /// @dev This method is public on purpose\\n /// @param _publicKey Validator to withdraw Consensus Layer Fees from\\n function withdrawCLFee(bytes calldata _publicKey) external {\\n _deployAndWithdraw(_publicKey, CONSENSUS_LAYER_SALT_PREFIX, StakingContractStorageLib.getCLDispatcher());\\n }\\n\\n /// @notice Withdraw both Consensus and Execution Layer Fee for a given validator public key\\n /// @dev Reverts if any is null\\n /// @param _publicKey Validator to withdraw Execution and Consensus Layer Fees from\\n function withdraw(bytes calldata _publicKey) external {\\n _deployAndWithdraw(_publicKey, EXECUTION_LAYER_SALT_PREFIX, StakingContractStorageLib.getELDispatcher());\\n _deployAndWithdraw(_publicKey, CONSENSUS_LAYER_SALT_PREFIX, StakingContractStorageLib.getCLDispatcher());\\n }\\n\\n /// \\u2588\\u2588 \\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\n /// \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\n /// \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588\\n /// \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\n /// \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\n\\n function _onlyActiveOperator(uint256 _operatorIndex) internal view {\\n StakingContractStorageLib.OperatorInfo memory operatorInfo = StakingContractStorageLib.getOperators().value[\\n _operatorIndex\\n ];\\n\\n if (operatorInfo.deactivated) {\\n revert Deactivated();\\n }\\n\\n if (msg.sender != operatorInfo.operator) {\\n revert Unauthorized();\\n }\\n }\\n\\n function _getPubKeyRoot(bytes memory _publicKey) internal pure returns (bytes32) {\\n return sha256(BytesLib.pad64(_publicKey));\\n }\\n\\n function _getWithdrawer(bytes32 _publicKeyRoot) internal view returns (address) {\\n return StakingContractStorageLib.getWithdrawers().value[_publicKeyRoot];\\n }\\n\\n function _updateAvailableValidatorCount(uint256 _operatorIndex) internal {\\n StakingContractStorageLib.ValidatorsFundingInfo memory validatorFundingInfo = StakingContractStorageLib\\n .getValidatorsFundingInfo(_operatorIndex);\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n\\n uint32 oldAvailableCount = validatorFundingInfo.availableKeys;\\n uint32 newAvailableCount = 0;\\n uint256 cap = _min(operators.value[_operatorIndex].limit, operators.value[_operatorIndex].publicKeys.length);\\n\\n if (cap <= validatorFundingInfo.funded) {\\n StakingContractStorageLib.setValidatorsFundingInfo(_operatorIndex, 0, validatorFundingInfo.funded);\\n } else {\\n newAvailableCount = uint32(cap - validatorFundingInfo.funded);\\n StakingContractStorageLib.setValidatorsFundingInfo(\\n _operatorIndex,\\n newAvailableCount,\\n validatorFundingInfo.funded\\n );\\n }\\n\\n if (oldAvailableCount != newAvailableCount) {\\n StakingContractStorageLib.setTotalAvailableValidators(\\n (StakingContractStorageLib.getTotalAvailableValidators() - oldAvailableCount) + newAvailableCount\\n );\\n }\\n }\\n\\n function _addressToWithdrawalCredentials(address _recipient) internal pure returns (bytes32) {\\n return\\n bytes32(uint256(uint160(_recipient)) + 0x0100000000000000000000000000000000000000000000000000000000000000);\\n }\\n\\n function _depositValidatorsOfOperator(\\n uint256 _operatorIndex,\\n uint256 _validatorCount,\\n address _withdrawer\\n ) internal {\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n StakingContractStorageLib.OperatorInfo storage operator = operators.value[_operatorIndex];\\n StakingContractStorageLib.ValidatorsFundingInfo memory vfi = StakingContractStorageLib.getValidatorsFundingInfo(\\n _operatorIndex\\n );\\n\\n for (uint256 i = vfi.funded; i < vfi.funded + _validatorCount; ) {\\n bytes memory publicKey = operator.publicKeys[i];\\n bytes memory signature = operator.signatures[i];\\n address consensusLayerRecipient = _getDeterministicReceiver(publicKey, CONSENSUS_LAYER_SALT_PREFIX);\\n bytes32 withdrawalCredentials = _addressToWithdrawalCredentials(consensusLayerRecipient);\\n _depositValidator(publicKey, signature, withdrawalCredentials);\\n bytes32 pubkeyRoot = _getPubKeyRoot(publicKey);\\n StakingContractStorageLib.getWithdrawers().value[pubkeyRoot] = _withdrawer;\\n emit Deposit(msg.sender, _withdrawer, publicKey, signature);\\n unchecked {\\n ++i;\\n }\\n }\\n\\n StakingContractStorageLib.setValidatorsFundingInfo(\\n _operatorIndex,\\n uint32(vfi.availableKeys - _validatorCount),\\n uint32(vfi.funded + _validatorCount)\\n );\\n }\\n\\n /// @notice Internal utility to deposit a public key, its signature and 32 ETH to the consensus layer\\n /// @param _publicKey The Public Key to deposit\\n /// @param _signature The Signature to deposit\\n /// @param _withdrawalCredentials The Withdrawal Credentials to deposit\\n function _depositValidator(\\n bytes memory _publicKey,\\n bytes memory _signature,\\n bytes32 _withdrawalCredentials\\n ) internal {\\n bytes32 pubkeyRoot = _getPubKeyRoot(_publicKey);\\n bytes32 signatureRoot = sha256(\\n abi.encodePacked(\\n sha256(BytesLib.slice(_signature, 0, 64)),\\n sha256(BytesLib.pad64(BytesLib.slice(_signature, 64, SIGNATURE_LENGTH - 64)))\\n )\\n );\\n\\n uint256 depositAmount = DEPOSIT_SIZE / 1000000000 wei;\\n assert(depositAmount * 1000000000 wei == DEPOSIT_SIZE);\\n\\n bytes32 depositDataRoot = sha256(\\n abi.encodePacked(\\n sha256(abi.encodePacked(pubkeyRoot, _withdrawalCredentials)),\\n sha256(abi.encodePacked(Uint256Lib.toLittleEndian64(depositAmount), signatureRoot))\\n )\\n );\\n\\n uint256 targetBalance = address(this).balance - DEPOSIT_SIZE;\\n\\n IDepositContract(StakingContractStorageLib.getDepositContract()).deposit{value: DEPOSIT_SIZE}(\\n _publicKey,\\n abi.encodePacked(_withdrawalCredentials),\\n _signature,\\n depositDataRoot\\n );\\n\\n if (address(this).balance != targetBalance) {\\n revert DepositFailure();\\n }\\n }\\n\\n function _depositOnOneOperator(\\n address _withdrawer,\\n uint256 _depositCount,\\n uint256 _totalAvailableValidators\\n ) internal {\\n _depositValidatorsOfOperator(0, _depositCount, _withdrawer);\\n StakingContractStorageLib.setTotalAvailableValidators(_totalAvailableValidators - _depositCount);\\n }\\n\\n function _depositOnTwoOperators(\\n address _withdrawer,\\n uint256 _depositCount,\\n uint256 _totalAvailableValidators\\n ) internal {\\n StakingContractStorageLib.ValidatorsFundingInfo memory oneOsi = StakingContractStorageLib\\n .getValidatorsFundingInfo(0);\\n StakingContractStorageLib.ValidatorsFundingInfo memory twoOsi = StakingContractStorageLib\\n .getValidatorsFundingInfo(1);\\n\\n uint256 oneDepositCount;\\n uint256 twoDepositCount;\\n\\n // using this tactic to prevent deposits of 1 validator to always go to operator 2\\n if (block.number % 2 == 0) {\\n oneDepositCount = _depositCount / 2;\\n twoDepositCount = _depositCount - oneDepositCount;\\n } else {\\n twoDepositCount = _depositCount / 2;\\n oneDepositCount = _depositCount - twoDepositCount;\\n }\\n\\n if (oneDepositCount > oneOsi.availableKeys) {\\n twoDepositCount = _depositCount - oneOsi.availableKeys;\\n oneDepositCount = oneOsi.availableKeys;\\n } else if (twoDepositCount > twoOsi.availableKeys) {\\n oneDepositCount = _depositCount - twoOsi.availableKeys;\\n twoDepositCount = twoOsi.availableKeys;\\n }\\n\\n if (oneDepositCount > 0) {\\n _depositValidatorsOfOperator(0, oneDepositCount, _withdrawer);\\n }\\n if (twoDepositCount > 0) {\\n _depositValidatorsOfOperator(1, twoDepositCount, _withdrawer);\\n }\\n StakingContractStorageLib.setTotalAvailableValidators(\\n _totalAvailableValidators - (oneDepositCount + twoDepositCount)\\n );\\n }\\n\\n function _getBaseSkip(\\n bytes32 blockHash,\\n uint256 index,\\n uint8 prime\\n ) internal pure returns (uint8 base, uint8 skip) {\\n base = uint8(blockHash[(index * 2) % 32]) % prime;\\n skip = (uint8(blockHash[((index * 2) + 1) % 32]) % (prime - 1)) + 1;\\n }\\n\\n function _getOperatorFundedCount(uint8 operatorIndex, ValidatorAllocationCache[] memory vd)\\n internal\\n view\\n returns (uint32)\\n {\\n if (operatorIndex >= vd.length) {\\n return 0;\\n }\\n if (vd[operatorIndex].used == false) {\\n StakingContractStorageLib.ValidatorsFundingInfo memory osi = StakingContractStorageLib\\n .getValidatorsFundingInfo(operatorIndex);\\n vd[operatorIndex].used = true;\\n vd[operatorIndex].funded = osi.funded;\\n vd[operatorIndex].available = osi.availableKeys;\\n }\\n return vd[operatorIndex].funded + vd[operatorIndex].toDeposit;\\n }\\n\\n function _getOperatorAvailableCount(uint8 operatorIndex, ValidatorAllocationCache[] memory vd)\\n internal\\n view\\n returns (uint32)\\n {\\n if (operatorIndex >= vd.length) {\\n return 0;\\n }\\n if (vd[operatorIndex].used == false) {\\n StakingContractStorageLib.ValidatorsFundingInfo memory osi = StakingContractStorageLib\\n .getValidatorsFundingInfo(operatorIndex);\\n vd[operatorIndex].used = true;\\n vd[operatorIndex].funded = osi.funded;\\n vd[operatorIndex].available = osi.availableKeys;\\n }\\n return vd[operatorIndex].available - vd[operatorIndex].toDeposit;\\n }\\n\\n function _assignTemporaryDeposit(uint8 operatorIndex, ValidatorAllocationCache[] memory vd) internal pure {\\n vd[operatorIndex].toDeposit += 1;\\n }\\n\\n function _getBestOperator(\\n uint8 alphaIndex,\\n uint8 betaIndex,\\n bytes32 blockHash,\\n ValidatorAllocationCache[] memory vd\\n ) internal view returns (uint8) {\\n uint256 alphaFundedCount = _getOperatorFundedCount(alphaIndex, vd);\\n uint256 betaFundedCount = _getOperatorFundedCount(betaIndex, vd);\\n if (alphaFundedCount < betaFundedCount) {\\n return alphaIndex;\\n } else if (alphaFundedCount > betaFundedCount) {\\n return betaIndex;\\n } else {\\n bool coinToss = (uint8(blockHash[(alphaIndex + betaIndex) % 32]) % 2) == 1;\\n if (coinToss == false) {\\n return betaIndex;\\n } else {\\n return alphaIndex;\\n }\\n }\\n }\\n\\n function _getElligibleOperators(\\n uint8 base,\\n uint8 skip,\\n uint8 prime,\\n ValidatorAllocationCache[] memory vd\\n ) internal view returns (uint8, uint8) {\\n int16 alphaIndex = -1;\\n int16 betaIndex = -1;\\n uint8 index = base;\\n while (alphaIndex == -1 || betaIndex == -1) {\\n if (_getOperatorAvailableCount(index, vd) > 0) {\\n if (alphaIndex == -1) {\\n alphaIndex = int8(index);\\n } else {\\n betaIndex = int8(index);\\n }\\n }\\n index = uint8((uint256(index) + skip) % prime);\\n if (index == base && betaIndex == -1) {\\n betaIndex = alphaIndex;\\n }\\n }\\n return (uint8(int8(alphaIndex)), uint8(int8(betaIndex)));\\n }\\n\\n function _depositOnThreeOrMoreOperators(\\n address _withdrawer,\\n uint256 _depositCount,\\n uint256 _totalAvailableValidators,\\n StakingContractStorageLib.OperatorsSlot storage _operators\\n ) internal {\\n uint256 operatorCount = _operators.value.length;\\n uint8 optimusPrime = _getClosestPrimeAbove(uint8(operatorCount));\\n bytes32 blockHash = blockhash(block.number - 1); // weak random number as it's not a security issue\\n\\n ValidatorAllocationCache[] memory vd = new ValidatorAllocationCache[](operatorCount);\\n\\n for (uint256 index; index < _depositCount; ) {\\n // Retrieve base index and skip value based on block hash and current loop index\\n (uint8 base, uint8 skip) = _getBaseSkip(blockHash, index, optimusPrime);\\n // Retrieve two operator indexes pointing to two (or the same) operator(s) that have at least one available\\n // validator key to be used for a deposit. This method takes into account possible pending deposits from\\n // previous loop rounds.\\n (uint8 alphaIndex, uint8 betaIndex) = _getElligibleOperators(base, skip, optimusPrime, vd);\\n\\n if (alphaIndex == betaIndex) {\\n // Assign the deposit to the only operator having available keys\\n _assignTemporaryDeposit(alphaIndex, vd);\\n } else {\\n // Assign the deposit to the operator having the lowest amount of funded keys\\n _assignTemporaryDeposit(_getBestOperator(alphaIndex, betaIndex, blockHash, vd), vd);\\n }\\n\\n unchecked {\\n ++index;\\n }\\n }\\n\\n // Loop through the cached operator values and deposit any pending deposits\\n for (uint256 index; index < vd.length; ) {\\n if (vd[index].toDeposit > 0) {\\n _depositValidatorsOfOperator(index, vd[index].toDeposit, _withdrawer);\\n }\\n unchecked {\\n ++index;\\n }\\n }\\n\\n StakingContractStorageLib.setTotalAvailableValidators(_totalAvailableValidators - _depositCount);\\n }\\n\\n function _deposit(address _withdrawer) internal {\\n if (msg.value == 0 || msg.value % DEPOSIT_SIZE != 0) {\\n revert InvalidDepositValue();\\n }\\n uint256 totalAvailableValidators = StakingContractStorageLib.getTotalAvailableValidators();\\n uint256 depositCount = msg.value / DEPOSIT_SIZE;\\n if (depositCount > totalAvailableValidators) {\\n revert NotEnoughValidators();\\n }\\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\\n if (operators.value.length == 0) {\\n revert NoOperators();\\n } else if (operators.value.length == 1) {\\n _depositOnOneOperator(_withdrawer, depositCount, totalAvailableValidators);\\n } else if (operators.value.length == 2) {\\n _depositOnTwoOperators(_withdrawer, depositCount, totalAvailableValidators);\\n } else {\\n _depositOnThreeOrMoreOperators(_withdrawer, depositCount, totalAvailableValidators, operators);\\n }\\n }\\n\\n function _primes() internal pure returns (uint8[54] memory primes) {\\n primes = [\\n 2,\\n 3,\\n 5,\\n 7,\\n 11,\\n 13,\\n 17,\\n 19,\\n 23,\\n 29,\\n 31,\\n 37,\\n 41,\\n 43,\\n 47,\\n 53,\\n 59,\\n 61,\\n 67,\\n 71,\\n 73,\\n 79,\\n 83,\\n 89,\\n 97,\\n 101,\\n 103,\\n 107,\\n 109,\\n 113,\\n 127,\\n 131,\\n 137,\\n 139,\\n 149,\\n 151,\\n 157,\\n 163,\\n 167,\\n 173,\\n 179,\\n 181,\\n 191,\\n 193,\\n 197,\\n 199,\\n 211,\\n 223,\\n 227,\\n 229,\\n 233,\\n 239,\\n 241,\\n 251\\n ];\\n }\\n\\n function _getClosestPrimeAbove(uint8 _count) internal pure returns (uint8) {\\n uint8[54] memory primes = _primes();\\n for (uint256 i; i < primes.length; ) {\\n if (primes[i] >= _count) {\\n return primes[i];\\n }\\n unchecked {\\n ++i;\\n }\\n }\\n revert InvalidValidatorCount();\\n }\\n\\n function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n if (_a < _b) {\\n return _a;\\n }\\n return _b;\\n }\\n\\n /// @notice Internal utility to compute the receiver deterministic address\\n /// @param _publicKey Public Key assigned to the receiver\\n /// @param _prefix Prefix used to generate multiple receivers per public key\\n function _getDeterministicReceiver(bytes memory _publicKey, uint256 _prefix) internal view returns (address) {\\n bytes32 publicKeyRoot = _getPubKeyRoot(_publicKey);\\n bytes32 salt = sha256(abi.encodePacked(_prefix, publicKeyRoot));\\n address implementation = StakingContractStorageLib.getFeeRecipientImplementation();\\n return Clones.predictDeterministicAddress(implementation, salt);\\n }\\n\\n /// @notice Internal utility to deploy and withdraw the fees from a receiver\\n /// @param _publicKey Public Key assigned to the receiver\\n /// @param _prefix Prefix used to generate multiple receivers per public key\\n /// @param _dispatcher Address of the dispatcher contract\\n function _deployAndWithdraw(\\n bytes calldata _publicKey,\\n uint256 _prefix,\\n address _dispatcher\\n ) internal {\\n bytes32 publicKeyRoot = _getPubKeyRoot(_publicKey);\\n bytes32 feeRecipientSalt = sha256(abi.encodePacked(_prefix, publicKeyRoot));\\n address implementation = StakingContractStorageLib.getFeeRecipientImplementation();\\n address feeRecipientAddress = Clones.predictDeterministicAddress(implementation, feeRecipientSalt);\\n if (feeRecipientAddress.code.length == 0) {\\n Clones.cloneDeterministic(implementation, feeRecipientSalt);\\n IFeeRecipient(feeRecipientAddress).init(_dispatcher, publicKeyRoot);\\n }\\n IFeeRecipient(feeRecipientAddress).withdraw();\\n }\\n}\\n\",\"keccak256\":\"0x9fd13dfc400b392c0254c64598a7d37685a8c3f2e006f8e35ed6cb59c7059bac\",\"license\":\"BUSL-1.1\"},\"src/contracts/interfaces/IDepositContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IDepositContract {\\n function deposit(\\n bytes calldata pubkey,\\n bytes calldata withdrawalCredentials,\\n bytes calldata signature,\\n bytes32 depositDataRoot\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x10ced526f2842c879ff63bf37a47d121d56898609456f98df1f3cff0a768b2c9\",\"license\":\"MIT\"},\"src/contracts/interfaces/IFeeRecipient.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\ninterface IFeeRecipient {\\n function init(address _dispatcher, bytes32 _publicKeyRoot) external;\\n\\n function withdraw() external;\\n}\\n\",\"keccak256\":\"0x2448a6378aa26099508ce00bf1eff7ea293ae97eece97d931a6f500256a2c475\",\"license\":\"MIT\"},\"src/contracts/libs/BytesLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary BytesLib {\\n function pad64(bytes memory _b) internal pure returns (bytes memory) {\\n assert(_b.length >= 32 && _b.length <= 64);\\n if (64 == _b.length) {\\n return _b;\\n }\\n\\n bytes memory zero32 = new bytes(32);\\n assembly {\\n mstore(add(zero32, 0x20), 0)\\n }\\n\\n if (32 == _b.length) {\\n return BytesLib.concat(_b, zero32);\\n } else {\\n return BytesLib.concat(_b, BytesLib.slice(zero32, 0, uint256(64) - _b.length));\\n }\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {\\n bytes memory tempBytes;\\n\\n assembly {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // Store the length of the first bytes array at the beginning of\\n // the memory for tempBytes.\\n let length := mload(_preBytes)\\n mstore(tempBytes, length)\\n\\n // Maintain a memory counter for the current write location in the\\n // temp bytes array by adding the 32 bytes for the array length to\\n // the starting location.\\n let mc := add(tempBytes, 0x20)\\n // Stop copying when the memory counter reaches the length of the\\n // first bytes array.\\n let end := add(mc, length)\\n\\n for {\\n // Initialize a copy counter to the start of the _preBytes data,\\n // 32 bytes into its memory.\\n let cc := add(_preBytes, 0x20)\\n } lt(mc, end) {\\n // Increase both counters by 32 bytes each iteration.\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // Write the _preBytes data into the tempBytes memory 32 bytes\\n // at a time.\\n mstore(mc, mload(cc))\\n }\\n\\n // Add the length of _postBytes to the current length of tempBytes\\n // and store it as the new length in the first 32 bytes of the\\n // tempBytes memory.\\n length := mload(_postBytes)\\n mstore(tempBytes, add(length, mload(tempBytes)))\\n\\n // Move the memory counter back from a multiple of 0x20 to the\\n // actual end of the _preBytes data.\\n mc := end\\n // Stop copying when the memory counter reaches the new combined\\n // length of the arrays.\\n end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n // Update the free-memory pointer by padding our last write location\\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\\n // next 32 byte block, then round down to the nearest multiple of\\n // 32. If the sum of the length of the two arrays is zero then add\\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\\n mstore(\\n 0x40,\\n and(\\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\\n not(31) // Round down to the nearest 32 bytes.\\n )\\n )\\n }\\n\\n return tempBytes;\\n }\\n\\n function slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes memory) {\\n require(_length + 31 >= _length, \\\"slice_overflow\\\");\\n require(_bytes.length >= _start + _length, \\\"slice_outOfBounds\\\");\\n\\n bytes memory tempBytes;\\n\\n assembly {\\n switch iszero(_length)\\n case 0 {\\n // Get a location of some free memory and store it in tempBytes as\\n // Solidity does for memory variables.\\n tempBytes := mload(0x40)\\n\\n // The first word of the slice result is potentially a partial\\n // word read from the original array. To read it, we calculate\\n // the length of that partial word and start copying that many\\n // bytes into the array. The first word we copy will start with\\n // data we don't care about, but the last `lengthmod` bytes will\\n // land at the beginning of the contents of the new array. When\\n // we're done copying, we overwrite the full first word with\\n // the actual length of the slice.\\n let lengthmod := and(_length, 31)\\n\\n // The multiplication in the next line is necessary\\n // because when slicing multiples of 32 bytes (lengthmod == 0)\\n // the following copy loop was copying the origin's length\\n // and then ending prematurely not copying everything it should.\\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\\n let end := add(mc, _length)\\n\\n for {\\n // The multiplication in the next line has the same exact purpose\\n // as the one above.\\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\\n } lt(mc, end) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n mstore(mc, mload(cc))\\n }\\n\\n mstore(tempBytes, _length)\\n\\n //update free-memory pointer\\n //allocating the array padded to 32 bytes like the compiler does now\\n mstore(0x40, and(add(mc, 31), not(31)))\\n }\\n //if we want a zero-length slice let's just return a zero-length array\\n default {\\n tempBytes := mload(0x40)\\n //zero out the 32 bytes slice we are about to return\\n //we need to do it because Solidity does not garbage collect\\n mstore(tempBytes, 0)\\n\\n mstore(0x40, add(tempBytes, 0x20))\\n }\\n }\\n\\n return tempBytes;\\n }\\n}\\n\",\"keccak256\":\"0x39916de22a26a29e6381a046e29a409fbc779a508563c872fc09f0c3dae07d88\",\"license\":\"MIT\"},\"src/contracts/libs/StakingContractStorageLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary StakingContractStorageLib {\\n function getUint256(bytes32 position) internal view returns (uint256 data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setUint256(bytes32 position, uint256 data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n\\n function getAddress(bytes32 position) internal view returns (address data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setAddress(bytes32 position, address data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n\\n function getBool(bytes32 position) internal view returns (bool data) {\\n assembly {\\n data := sload(position)\\n }\\n }\\n\\n function setBool(bytes32 position, bool data) internal {\\n assembly {\\n sstore(position, data)\\n }\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant VERSION_SLOT = keccak256(\\\"StakingContract.version\\\");\\n\\n function getVersion() internal view returns (uint256) {\\n return getUint256(VERSION_SLOT);\\n }\\n\\n function setVersion(uint256 _newVersion) internal {\\n setUint256(VERSION_SLOT, _newVersion);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant ADMIN_SLOT = keccak256(\\\"StakingContract.admin\\\");\\n bytes32 internal constant PENDING_ADMIN_SLOT = keccak256(\\\"StakingContract.pendingAdmin\\\");\\n\\n function getAdmin() internal view returns (address) {\\n return getAddress(ADMIN_SLOT);\\n }\\n\\n function setAdmin(address _newAdmin) internal {\\n setAddress(ADMIN_SLOT, _newAdmin);\\n }\\n\\n function getPendingAdmin() internal view returns (address) {\\n return getAddress(PENDING_ADMIN_SLOT);\\n }\\n\\n function setPendingAdmin(address _newPendingAdmin) internal {\\n setAddress(PENDING_ADMIN_SLOT, _newPendingAdmin);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant TREASURY_SLOT = keccak256(\\\"StakingContract.treasury\\\");\\n\\n function getTreasury() internal view returns (address) {\\n return getAddress(TREASURY_SLOT);\\n }\\n\\n function setTreasury(address _newTreasury) internal {\\n setAddress(TREASURY_SLOT, _newTreasury);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant DEPOSIT_CONTRACT_SLOT = keccak256(\\\"StakingContract.depositContract\\\");\\n\\n function getDepositContract() internal view returns (address) {\\n return getAddress(DEPOSIT_CONTRACT_SLOT);\\n }\\n\\n function setDepositContract(address _newDepositContract) internal {\\n setAddress(DEPOSIT_CONTRACT_SLOT, _newDepositContract);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant OPERATORS_SLOT = keccak256(\\\"StakingContract.operators\\\");\\n\\n struct OperatorInfo {\\n address operator;\\n address feeRecipient;\\n uint256 limit;\\n bytes[] publicKeys;\\n bytes[] signatures;\\n bool deactivated;\\n }\\n\\n struct OperatorsSlot {\\n OperatorInfo[] value;\\n }\\n\\n function getOperators() internal pure returns (OperatorsSlot storage p) {\\n bytes32 slot = OPERATORS_SLOT;\\n assembly {\\n p.slot := slot\\n }\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant VALIDATORS_FUNDING_INFO_SLOT = keccak256(\\\"StakingContract.validatorsFundingInfo\\\");\\n\\n struct ValidatorsFundingInfo {\\n uint32 availableKeys;\\n uint32 funded;\\n }\\n\\n struct UintToUintMappingSlot {\\n mapping(uint256 => uint256) value;\\n }\\n\\n function getValidatorsFundingInfo(uint256 _index) internal view returns (ValidatorsFundingInfo memory vfi) {\\n UintToUintMappingSlot storage p;\\n bytes32 slot = VALIDATORS_FUNDING_INFO_SLOT;\\n\\n assembly {\\n p.slot := slot\\n }\\n\\n uint256 slotIndex = _index >> 2;\\n uint256 innerIndex = (_index & 3) << 6;\\n uint256 value = p.value[slotIndex] >> innerIndex;\\n vfi.availableKeys = uint32(value);\\n vfi.funded = uint32(value >> 32);\\n }\\n\\n function setValidatorsFundingInfo(\\n uint256 _index,\\n uint32 _availableKeys,\\n uint32 _funded\\n ) internal {\\n UintToUintMappingSlot storage p;\\n bytes32 slot = VALIDATORS_FUNDING_INFO_SLOT;\\n\\n assembly {\\n p.slot := slot\\n }\\n\\n uint256 slotIndex = _index >> 2;\\n uint256 innerIndex = (_index & 3) << 6;\\n p.value[slotIndex] =\\n (p.value[slotIndex] & (~(uint256(0xFFFFFFFFFFFFFFFF) << innerIndex))) |\\n ((uint256(_availableKeys) | (uint256(_funded) << 32)) << innerIndex);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant TOTAL_AVAILABLE_VALIDATORS_SLOT = keccak256(\\\"StakingContract.totalAvailableValidators\\\");\\n\\n function getTotalAvailableValidators() internal view returns (uint256) {\\n return getUint256(TOTAL_AVAILABLE_VALIDATORS_SLOT);\\n }\\n\\n function setTotalAvailableValidators(uint256 _newTotal) internal {\\n setUint256(TOTAL_AVAILABLE_VALIDATORS_SLOT, _newTotal);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant WITHDRAWERS_SLOT = keccak256(\\\"StakingContract.withdrawers\\\");\\n\\n struct WithdrawersSlot {\\n mapping(bytes32 => address) value;\\n }\\n\\n function getWithdrawers() internal pure returns (WithdrawersSlot storage p) {\\n bytes32 slot = WITHDRAWERS_SLOT;\\n assembly {\\n p.slot := slot\\n }\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n struct OperatorIndex {\\n bool enabled;\\n uint32 operatorIndex;\\n }\\n\\n struct OperatorIndexPerValidatorSlot {\\n mapping(bytes32 => OperatorIndex) value;\\n }\\n\\n bytes32 internal constant OPERATOR_INDEX_PER_VALIDATOR_SLOT =\\n keccak256(\\\"StakingContract.operatorIndexPerValidator\\\");\\n\\n function getOperatorIndexPerValidator() internal pure returns (OperatorIndexPerValidatorSlot storage p) {\\n bytes32 slot = OPERATOR_INDEX_PER_VALIDATOR_SLOT;\\n assembly {\\n p.slot := slot\\n }\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant GLOBAL_FEE_SLOT = keccak256(\\\"StakingContract.globalFee\\\");\\n\\n function getGlobalFee() internal view returns (uint256) {\\n return getUint256(GLOBAL_FEE_SLOT);\\n }\\n\\n function setGlobalFee(uint256 _newTreasuryFee) internal {\\n setUint256(GLOBAL_FEE_SLOT, _newTreasuryFee);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant OPERATOR_FEE_SLOT = keccak256(\\\"StakingContract.operatorFee\\\");\\n\\n function getOperatorFee() internal view returns (uint256) {\\n return getUint256(OPERATOR_FEE_SLOT);\\n }\\n\\n function setOperatorFee(uint256 _newOperatorFee) internal {\\n setUint256(OPERATOR_FEE_SLOT, _newOperatorFee);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant EL_DISPATCHER_SLOT = keccak256(\\\"StakingContract.executionLayerDispatcher\\\");\\n\\n function getELDispatcher() internal view returns (address) {\\n return getAddress(EL_DISPATCHER_SLOT);\\n }\\n\\n function setELDispatcher(address _newElDispatcher) internal {\\n setAddress(EL_DISPATCHER_SLOT, _newElDispatcher);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant CL_DISPATCHER_SLOT = keccak256(\\\"StakingContract.consensusLayerDispatcher\\\");\\n\\n function getCLDispatcher() internal view returns (address) {\\n return getAddress(CL_DISPATCHER_SLOT);\\n }\\n\\n function setCLDispatcher(address _newClDispatcher) internal {\\n setAddress(CL_DISPATCHER_SLOT, _newClDispatcher);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant FEE_RECIPIENT_IMPLEMENTATION_SLOT =\\n keccak256(\\\"StakingContract.feeRecipientImplementation\\\");\\n\\n function getFeeRecipientImplementation() internal view returns (address) {\\n return getAddress(FEE_RECIPIENT_IMPLEMENTATION_SLOT);\\n }\\n\\n function setFeeRecipientImplementation(address _newFeeRecipientImplementation) internal {\\n setAddress(FEE_RECIPIENT_IMPLEMENTATION_SLOT, _newFeeRecipientImplementation);\\n }\\n\\n /* ========================================\\n ===========================================\\n =========================================*/\\n\\n bytes32 internal constant WITHDRAWER_CUSTOMIZATION_ENABLED_SLOT =\\n keccak256(\\\"StakingContract.withdrawerCustomizationEnabled\\\");\\n\\n function getWithdrawerCustomizationEnabled() internal view returns (bool) {\\n return getBool(WITHDRAWER_CUSTOMIZATION_ENABLED_SLOT);\\n }\\n\\n function setWithdrawerCustomizationEnabled(bool _enabled) internal {\\n setBool(WITHDRAWER_CUSTOMIZATION_ENABLED_SLOT, _enabled);\\n }\\n}\\n\",\"keccak256\":\"0x065668e865542aecc64aaf4b94b05cbd1e70deb4439ade08916782997e14745d\",\"license\":\"MIT\"},\"src/contracts/libs/UintLib.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.10;\\n\\nlibrary Uint256Lib {\\n function toLittleEndian64(uint256 _value) internal pure returns (uint256 result) {\\n result = 0;\\n uint256 temp_value = _value;\\n for (uint256 i = 0; i < 8; ++i) {\\n result = (result << 8) | (temp_value & 0xFF);\\n temp_value >>= 8;\\n }\\n\\n assert(0 == temp_value); // fully converted\\n result <<= (24 * 8);\\n }\\n}\\n\",\"keccak256\":\"0x452fa01e7c7dbf60df6d9d12f79645183d66f5a8ca3d673742eb4960a1952b73\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50615586806100206000396000f3fe6080604052600436106102085760003560e01c806379ba509711610118578063bf509bd4116100a0578063d2a427471161006f578063d2a42747146105f0578063e00cb6ca14610610578063e99454f514610630578063f0f4426014610650578063f2fde38b1461067057610218565b8063bf509bd414610593578063d0468156146105b3578063d0e30db0146105c8578063d243d69d146105d057610218565b8063a4d8d2c4116100e7578063a4d8d2c414610509578063a740080114610529578063b4336b8414610549578063b747e7dd1461055e578063bf15af561461057e57610218565b806379ba5097146104945780638a1af4c4146104a95780638df4e474146104c95780639adf91ee146104e957610218565b8063286966081161019b5780633b19e84a1161016a5780633b19e84a14610405578063540bc5ea1461041a57806363b4118f1461042f5780636e9960c31461045f578063714b55b21461047457610218565b80632869660814610393578063291206f6146103a85780632ba03a79146103c857806336bf3325146103e857610218565b80631bcbfaba116101d75780631bcbfaba146102f85780631d0958051461031b5780631ee133431461033b578063227e80fa1461037357610218565b806305f63c8a1461023157806308b3a073146102985780630968f264146102b85780631864636c146102d857610218565b366102185761021633610690565b005b60405163574b16a760e11b815260040160405180910390fd5b34801561023d57600080fd5b5061025161024c366004614cfd565b610780565b604080516001600160a01b039889168152979096166020880152948601939093526060850191909152608084015260a0830152151560c082015260e0015b60405180910390f35b3480156102a457600080fd5b506102166102b3366004614d32565b610a10565b3480156102c457600080fd5b506102166102d3366004614e04565b610ae5565b3480156102e457600080fd5b506102166102f3366004614e46565b610b0c565b34801561030457600080fd5b5061030d61174a565b60405190815260200161028f565b34801561032757600080fd5b50610216610336366004614cfd565b611759565b34801561034757600080fd5b5061035b610356366004614e04565b6117f4565b6040516001600160a01b03909116815260200161028f565b34801561037f57600080fd5b5061021661038e366004614ec5565b611841565b34801561039f57600080fd5b5061030d6119b8565b3480156103b457600080fd5b506102166103c3366004614cfd565b6119c2565b3480156103d457600080fd5b506102166103e3366004614e04565b610af9565b3480156103f457600080fd5b5061030d6801bc16d674ec80000081565b34801561041157600080fd5b5061035b611a56565b34801561042657600080fd5b5061030d606081565b34801561043b57600080fd5b5061044f61044a366004614ef1565b611a60565b60405161028f9493929190614f6b565b34801561046b57600080fd5b5061035b611c44565b34801561048057600080fd5b5061021661048f366004614ef1565b611c4e565b3480156104a057600080fd5b50610216611d9d565b3480156104b557600080fd5b5061030d6104c4366004614fb2565b611e13565b3480156104d557600080fd5b506102166104e4366004614fdc565b611fcc565b3480156104f557600080fd5b5061035b610504366004614cfd565b61203f565b34801561051557600080fd5b50610216610524366004614ffe565b6120bd565b34801561053557600080fd5b5061035b610544366004614cfd565b612429565b34801561055557600080fd5b5061030d612434565b34801561056a57600080fd5b5061021661057936600461503a565b61243e565b34801561058a57600080fd5b5061030d603081565b34801561059f57600080fd5b506102166105ae366004614e04565b612777565b3480156105bf57600080fd5b5061035b612786565b610216612790565b3480156105dc57600080fd5b5061035b6105eb366004614e04565b61279b565b3480156105fc57600080fd5b5061021661060b366004614ec5565b6127dc565b34801561061c57600080fd5b5061035b61062b366004614e04565b6129b9565b34801561063c57600080fd5b5061021661064b3660046150bd565b6129fd565b34801561065c57600080fd5b5061021661066b366004615108565b612b79565b34801561067c57600080fd5b5061021661068b366004615108565b612bf9565b3415806106ae57506106ab6801bc16d674ec80000034615139565b15155b156106cc5760405163214121f160e11b815260040160405180910390fd5b60006106d6612c3a565b905060006106ed6801bc16d674ec80000034615163565b905081811115610710576040516315caeb5160e31b815260040160405180910390fd5b60008051602061551183398151915280546000036107415760405163ddf9d24560e01b815260040160405180910390fd5b805460010361075a57610755848385612c64565b61077a565b805460020361076e57610755848385612c82565b61077a84838584612d90565b50505050565b6000808080808080806000805160206155118339815191528054909150891015610a045760006107af8a612f1d565b90506000826000018b815481106107c8576107c8615177565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156108d757838290600052602060002001805461084a9061518d565b80601f01602080910402602001604051908101604052809291908181526020018280546108769061518d565b80156108c35780601f10610898576101008083540402835291602001916108c3565b820191906000526020600020905b8154815290600101906020018083116108a657829003601f168201915b50505050508152602001906001019061082b565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156109b05783829060005260206000200180546109239061518d565b80601f016020809104026020016040519081016040528092919081815260200182805461094f9061518d565b801561099c5780601f106109715761010080835404028352916020019161099c565b820191906000526020600020905b81548152906001019060200180831161097f57829003601f168201915b505050505081526020019060010190610904565b505050908252506005919091015460ff161515602091820152815182820151604084015160608501515160a090950151938701519651929e50909c509a5091985063ffffffff938416975092169450909250505b50919395979092949650565b6001610a1a612f83565b610a259060016151c1565b8114610a435760405162dc149f60e41b815260040160405180910390fd5b610a4c81612fad565b610a5589612fd6565b610a5e88612fff565b612710831115610a81576040516358d620b360e01b815260040160405180910390fd5b610a8a83613028565b612710821115610aad576040516358d620b360e01b815260040160405180910390fd5b610ab682613051565b610abf8661307a565b610ac8856130a3565b610ad1876130cc565b610ada846130f5565b505050505050505050565b610af982826000610af461311e565b613148565b610b0882826001610af46132fe565b5050565b82610b15613328565b6001600160a01b03163303611132576000829003610b465760405163a9cb9e0d60e01b815260040160405180910390fd5b6000610b5185612f1d565b60208101519091506000805160206155118339815191529063ffffffff168585610b7c6001826151d9565b818110610b8b57610b8b615177565b905060200201351015610bb1576040516334947ea160e01b815260040160405180910390fd5b60005b8481101561103057600081118015610c0657508585610bd46001846151d9565b818110610be357610be3615177565b90506020020135868683818110610bfc57610bfc615177565b9050602002013510155b15610c24576040516335061dff60e01b815260040160405180910390fd5b867f794aacb42d1ea2e7f72809b74e3ce124325a51c3715b873c36807d3ca37e4fd0836000018981548110610c5b57610c5b615177565b9060005260206000209060060201600301888885818110610c7e57610c7e615177565b9050602002013581548110610c9557610c95615177565b90600052602060002001604051610cac91906151f0565b60405180910390a26001826000018881548110610ccb57610ccb615177565b906000526020600020906006020160030180549050610cea91906151d9565b868683818110610cfc57610cfc615177565b9050602002013503610db357816000018781548110610d1d57610d1d615177565b9060005260206000209060060201600301805480610d3d57610d3d615297565b600190038181906000526020600020016000610d599190614b1a565b9055816000018781548110610d7057610d70615177565b9060005260206000209060060201600401805480610d9057610d90615297565b600190038181906000526020600020016000610dac9190614b1a565b9055611028565b816000018781548110610dc857610dc8615177565b90600052602060002090600602016003016001836000018981548110610df057610df0615177565b906000526020600020906006020160030180549050610e0f91906151d9565b81548110610e1f57610e1f615177565b90600052602060002001826000018881548110610e3e57610e3e615177565b9060005260206000209060060201600301878784818110610e6157610e61615177565b9050602002013581548110610e7857610e78615177565b90600052602060002001908054610e8e9061518d565b610e99929190614b54565b50816000018781548110610eaf57610eaf615177565b9060005260206000209060060201600301805480610ecf57610ecf615297565b600190038181906000526020600020016000610eeb9190614b1a565b9055816000018781548110610f0257610f02615177565b90600052602060002090600602016004016001836000018981548110610f2a57610f2a615177565b906000526020600020906006020160040180549050610f4991906151d9565b81548110610f5957610f59615177565b90600052602060002001826000018881548110610f7857610f78615177565b9060005260206000209060060201600401878784818110610f9b57610f9b615177565b9050602002013581548110610fb257610fb2615177565b90600052602060002001908054610fc89061518d565b610fd3929190614b54565b50816000018781548110610fe957610fe9615177565b906000526020600020906006020160040180548061100957611009615297565b6001900381819060005260206000200160006110259190614b1a565b90555b600101610bb4565b5080600001868154811061104657611046615177565b600091825260209091206002600690920201015485856110676001826151d9565b81811061107657611076615177565b9050602002013510156111225784846110906001826151d9565b81811061109f5761109f615177565b905060200201358160000187815481106110bb576110bb615177565b60009182526020909120600260069092020101556000805160206155318339815191528686866110ec6001826151d9565b8181106110fb576110fb615177565b90506020020135604051611119929190918252602082015260400190565b60405180910390a15b61112b86613352565b505061077a565b61113b8161345e565b600082900361115d5760405163a9cb9e0d60e01b815260040160405180910390fd5b600061116885612f1d565b60208101519091506000805160206155118339815191529063ffffffff1685856111936001826151d9565b8181106111a2576111a2615177565b9050602002013510156111c8576040516334947ea160e01b815260040160405180910390fd5b60005b848110156116475760008111801561121d575085856111eb6001846151d9565b8181106111fa576111fa615177565b9050602002013586868381811061121357611213615177565b9050602002013510155b1561123b576040516335061dff60e01b815260040160405180910390fd5b867f794aacb42d1ea2e7f72809b74e3ce124325a51c3715b873c36807d3ca37e4fd083600001898154811061127257611272615177565b906000526020600020906006020160030188888581811061129557611295615177565b90506020020135815481106112ac576112ac615177565b906000526020600020016040516112c391906151f0565b60405180910390a260018260000188815481106112e2576112e2615177565b90600052602060002090600602016003018054905061130191906151d9565b86868381811061131357611313615177565b90506020020135036113ca5781600001878154811061133457611334615177565b906000526020600020906006020160030180548061135457611354615297565b6001900381819060005260206000200160006113709190614b1a565b905581600001878154811061138757611387615177565b90600052602060002090600602016004018054806113a7576113a7615297565b6001900381819060005260206000200160006113c39190614b1a565b905561163f565b8160000187815481106113df576113df615177565b9060005260206000209060060201600301600183600001898154811061140757611407615177565b90600052602060002090600602016003018054905061142691906151d9565b8154811061143657611436615177565b9060005260206000200182600001888154811061145557611455615177565b906000526020600020906006020160030187878481811061147857611478615177565b905060200201358154811061148f5761148f615177565b906000526020600020019080546114a59061518d565b6114b0929190614b54565b508160000187815481106114c6576114c6615177565b90600052602060002090600602016003018054806114e6576114e6615297565b6001900381819060005260206000200160006115029190614b1a565b905581600001878154811061151957611519615177565b9060005260206000209060060201600401600183600001898154811061154157611541615177565b90600052602060002090600602016004018054905061156091906151d9565b8154811061157057611570615177565b9060005260206000200182600001888154811061158f5761158f615177565b90600052602060002090600602016004018787848181106115b2576115b2615177565b90506020020135815481106115c9576115c9615177565b906000526020600020019080546115df9061518d565b6115ea929190614b54565b5081600001878154811061160057611600615177565b906000526020600020906006020160040180548061162057611620615297565b60019003818190600052602060002001600061163c9190614b1a565b90555b6001016111cb565b5080600001868154811061165d5761165d615177565b6000918252602090912060026006909202010154858561167e6001826151d9565b81811061168d5761168d615177565b9050602002013510156117395784846116a76001826151d9565b8181106116b6576116b6615177565b905060200201358160000187815481106116d2576116d2615177565b60009182526020909120600260069092020101556000805160206155318339815191528686866117036001826151d9565b81811061171257611712615177565b90506020020135604051611730929190918252602082015260400190565b60405180910390a15b61174286613352565b505050505050565b60006117546136d1565b905090565b611761613328565b6001600160a01b0316336001600160a01b031614611791576040516282b42960e81b815260040160405180910390fd5b6127108111156117b4576040516358d620b360e01b815260040160405180910390fd5b6117bd81613051565b6040518181527fd894096cd1f7e89d9b748c7c2358cb699a790a05e97dcde228fe5949b4e80743906020015b60405180910390a150565b600061183883838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506136fb915050565b90505b92915050565b611849613328565b6001600160a01b0316336001600160a01b031614611879576040516282b42960e81b815260040160405180910390fd5b600080516020615511833981519152805460009082908590811061189f5761189f615177565b600091825260209182902060069190910201600501805460ff1916921515929092179091556040518481527f8d0ba049731b0417f85546bc7503de241522c61e7464e87cceff56d3f2586dbc910160405180910390a18181600001848154811061190b5761190b615177565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055507f97568892aa9e69db7c72b9f32e6d4fe3c0e53b9728a8c0a0f1c2a7eb47c48ad38382600001858154811061197757611977615177565b600091825260209182902060069091020154604080519384526001600160a01b039182169284019290925285169082015260600160405180910390a1505050565b60006117546137a5565b6119ca613328565b6001600160a01b0316336001600160a01b0316146119fa576040516282b42960e81b815260040160405180910390fd5b612710811115611a1d576040516358d620b360e01b815260040160405180910390fd5b611a2681613028565b6040518181527fecd6fc650620aa722cafc3c3e871fa813947eae6f856982d7510a8ff101a5078906020016117e9565b60006117546137cf565b606080600080806000805160206155118339815191529050806000018781548110611a8d57611a8d615177565b90600052602060002090600602016003018681548110611aaf57611aaf615177565b906000526020600020018054611ac49061518d565b80601f0160208091040260200160405190810160405280929190818152602001828054611af09061518d565b8015611b3d5780601f10611b1257610100808354040283529160200191611b3d565b820191906000526020600020905b815481529060010190602001808311611b2057829003601f168201915b50505050509450806000018781548110611b5957611b59615177565b90600052602060002090600602016004018681548110611b7b57611b7b615177565b906000526020600020018054611b909061518d565b80601f0160208091040260200160405190810160405280929190818152602001828054611bbc9061518d565b8015611c095780601f10611bde57610100808354040283529160200191611c09565b820191906000526020600020905b815481529060010190602001808311611bec57829003601f168201915b50505050509350611c21611c1c866137f9565b613853565b9250611c2c87612f1d565b6020015163ffffffff16861091505092959194509250565b6000611754613328565b611c56613328565b6001600160a01b0316336001600160a01b031614611c86576040516282b42960e81b815260040160405180910390fd5b6000805160206155118339815191528054819084908110611ca957611ca9615177565b600091825260209091206005600690920201015460ff1615611cde57604051630450a9a360e21b815260040160405180910390fd5b6000816000018481548110611cf557611cf5615177565b906000526020600020906006020160030180549050905082811015611d3c576040516362106cb360e01b815260048101849052602481018290526044015b60405180910390fd5b82826000018581548110611d5257611d52615177565b906000526020600020906006020160020181905550611d7084613352565b6040805185815260208101859052600080516020615531833981519152910160405180910390a150505050565b6000611da761388d565b9050336001600160a01b03821614611dd1576040516282b42960e81b815260040160405180910390fd5b611dda81612fd6565b6040516001600160a01b03821681527ff29c1089a9594c030706593e345bd8f70a26125bfb7bf4c54e757e20f456fd1c906020016117e9565b6000611e1d613328565b6001600160a01b0316336001600160a01b031614611e4d576040516282b42960e81b815260040160405180910390fd5b6040805160c0810182526000808252602082018190529181018290526060808201819052608082015260a0810191909152600080516020615511833981519152805490919060fb03611eb25760405163a20c741360e01b815260040160405180910390fd5b6001600160a01b03808616825284811660208084019182528454600181810187556000878152839020865160069093020180549286166001600160a01b0319938416178155935190840180549190951691161790925560408301516002820155606083015180518493611f2c926003850192910190614bdf565b5060808201518051611f48916004840191602090910190614bdf565b5060a091909101516005909101805460ff19169115159190911790558154600090611f75906001906151d9565b604080516001600160a01b03808a168252881660208201529081018290529091507f2b3c4db2c0f4f51da09c2510a63e1d90235e486e8f075a609103a5c7a07422179060600160405180910390a195945050505050565b611fd4613328565b6001600160a01b0316336001600160a01b031614612004576040516282b42960e81b815260040160405180910390fd5b61200d816138b6565b60405181151581527f96639403db35a7ef32b25543bec54f73278d8c5ca82883ef1385ddcb27afa7dc906020016117e9565b60008181527fc58a51931c529c2a8796a8fad2ae789ee504643b4b567f2c0c97e809cec93902602052604081205460008051602061551183398151915280549091610100900463ffffffff1690811061209a5761209a615177565b60009182526020909120600160069092020101546001600160a01b031692915050565b8260006000805160206155118339815191528054839081106120e1576120e1615177565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156121f05783829060005260206000200180546121639061518d565b80601f016020809104026020016040519081016040528092919081815260200182805461218f9061518d565b80156121dc5780601f106121b1576101008083540402835291602001916121dc565b820191906000526020600020905b8154815290600101906020018083116121bf57829003601f168201915b505050505081526020019060010190612144565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156122c957838290600052602060002001805461223c9061518d565b80601f01602080910402602001604051908101604052809291908181526020018280546122689061518d565b80156122b55780601f1061228a576101008083540402835291602001916122b5565b820191906000526020600020905b81548152906001019060200180831161229857829003601f168201915b50505050508152602001906001019061221d565b505050908252506005919091015460ff16151560209091015260a08101519091501561230857604051630450a9a360e21b815260040160405180910390fd5b80602001516001600160a01b0316336001600160a01b03161461233d576040516282b42960e81b815260040160405180910390fd5b6000805160206155118339815191528054859082908890811061236257612362615177565b906000526020600020906006020160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160000187815481106123ad576123ad615177565b60009182526020918290206006919091020160010180546001600160a01b0319166001600160a01b0393841617905560408051898152888416928101929092529186168183015290517f97568892aa9e69db7c72b9f32e6d4fe3c0e53b9728a8c0a0f1c2a7eb47c48ad3916060908290030190a1505050505050565b600061183b82613853565b6000611754612c3a565b856124488161345e565b856000036124695760405163a9cb9e0d60e01b815260040160405180910390fd5b612474603085615139565b15158061248b575085612488603086615163565b14155b156124a95760405163337d0f4160e01b815260040160405180910390fd5b6124b4606083615139565b1515806124cb5750856124c8606084615163565b14155b156124e95760405163274cf40160e01b815260040160405180910390fd5b6000805160206155118339815191527fc58a51931c529c2a8796a8fad2ae789ee504643b4b567f2c0c97e809cec9390260005b8881101561272f57600061257489898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061256d9250603091508690506152ad565b60306138df565b905060006125c688888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506125bf9250606091508790506152ad565b60606138df565b9050846000018c815481106125dd576125dd615177565b600091825260208083206003600690930201919091018054600181018255908352918190208451612615939190910191850190614c38565b50846000018c8154811061262b5761262b615177565b600091825260208083206004600690930201919091018054600181018255908352918190208351612663939190910191840190614c38565b50600061266f836137f9565b60008181526020879052604090205490915060ff16156126a45782604051635a303adb60e01b8152600401611d3391906152cc565b60405180604001604052806001151581526020018e63ffffffff1681525085600001600083815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548163ffffffff021916908363ffffffff16021790555090505083600101935050505061251c565b50887fb82c87b84f76f39d5f61ed59b411352603805dda6080a2c44b4a86eab141ff1b888888886040516127669493929190615308565b60405180910390a2610ada89613352565b610b0882826000610af461311e565b600061175461388d565b61279933610690565b565b600061183883838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092506136fb915050565b6127e4613328565b6001600160a01b0316336001600160a01b031614612814576040516282b42960e81b815260040160405180910390fd5b600080516020615511833981519152805460009082908590811061283a5761283a615177565b906000526020600020906006020160020181905550600080516020615531833981519152836000604051612878929190918252602082015260400190565b60405180910390a1600181600001848154811061289757612897615177565b600091825260209182902060069190910201600501805460ff1916921515929092179091556040518481527f4c644bb0e171ba9e5cf08f5d66836528c3947c3512b34dd8e27da30e803527b3910160405180910390a18181600001848154811061290357612903615177565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055507f97568892aa9e69db7c72b9f32e6d4fe3c0e53b9728a8c0a0f1c2a7eb47c48ad38382600001858154811061296f5761296f615177565b600091825260209182902060069091020154604080519384526001600160a01b039182169284019290925285169082015260600160405180910390a16129b483613352565b505050565b6000611838611c1c84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137f992505050565b612a056139ec565b612a2257604051631dd2188d60e31b815260040160405180910390fd5b60006002612a6585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613a1692505050565b604051612a72919061533a565b602060405180830381855afa158015612a8f573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612ab29190615356565b905060007f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e2656000838152602082905260409020549091506001600160a01b03163314612b10576040516282b42960e81b815260040160405180910390fd5b7f833a0d0704fbdc6a0f748ebec819c31dde0b532ca9e3e29f56a5c4e8f3cbc0c9858585604051612b439392919061536f565b60405180910390a160009182526020526040902080546001600160a01b0319166001600160a01b03929092169190911790555050565b612b81613328565b6001600160a01b0316336001600160a01b031614612bb1576040516282b42960e81b815260040160405180910390fd5b6040516001600160a01b03821681527f63cc689e9d3377465b51fb094ea4ca5e0a1436b21f1ad30d707c696111c665009060200160405180910390a1612bf681612fff565b50565b612c01613328565b6001600160a01b0316336001600160a01b031614612c31576040516282b42960e81b815260040160405180910390fd5b612bf681613aaf565b60006117547f559ad51499ae00ca2e9d9d95aab46737c8904ab7da276613fefda282b2c2ac065490565b612c7060008385613ad7565b6129b4612c7d83836151d9565b613d9e565b6000612c8e6000612f1d565b90506000612c9c6001612f1d565b9050600080612cac600243615139565b600003612cd157612cbe600287615163565b9150612cca82876151d9565b9050612ceb565b612cdc600287615163565b9050612ce881876151d9565b91505b835163ffffffff16821115612d1d578351612d0c9063ffffffff16876151d9565b845163ffffffff1692509050612d4c565b825163ffffffff16811115612d4c578251612d3e9063ffffffff16876151d9565b835190925063ffffffff1690505b8115612d5e57612d5e60008389613ad7565b8015612d7057612d7060018289613ad7565b612d87612d7d82846151c1565b612c7d90876151d9565b50505050505050565b80546000612d9d82613dc7565b90506000612dac6001436151d9565b40905060008367ffffffffffffffff811115612dca57612dca61539b565b604051908082528060200260200182016040528015612e2357816020015b6040805160a081018252600080825260208083018290529282018190526060820181905260808201528252600019909201910181612de85790505b50905060005b87811015612e9657600080612e3f858488613e44565b91509150600080612e5284848a89613edd565b915091508060ff168260ff1603612e7257612e6d8287613f8f565b612e87565b612e87612e8183838a8a613fcb565b87613f8f565b84600101945050505050612e29565b5060005b8151811015612f05576000828281518110612eb757612eb7615177565b60200260200101516060015163ffffffff161115612efd57612efd81838381518110612ee557612ee5615177565b60200260200101516060015163ffffffff168b613ad7565b600101612e9a565b50612f13612c7d88886151d9565b5050505050505050565b60408051808201825260008082526020808301828152600286901c83527f37e2c371bbf1c7a1326d52e30855e9c8b6cac15eda4475320e427b948813a9f08252939091205463ffffffff60c060069690961b959095161c8481168352901c909216905290565b60006117547fd5c553085b8382c47128ae7612257fd5dc3b4fc4d3a108925604d3c8700c025b5490565b612bf67fd5c553085b8382c47128ae7612257fd5dc3b4fc4d3a108925604d3c8700c025b829055565b612bf67ffbeda9bc03875013b12a1ec161efb8e5bf7e58e3cec96a1ea9efd3e264d26e64829055565b612bf67f10c92bb459c0223bf996150f2fb702a8288fb8354a33d5b0212e8e6b8273f55e829055565b612bf67fb88142a0318e2b174876bceb4db9dc318011849c83fb8a8bb2997386d562324a829055565b612bf67f41118591c19026bdc7a484e34f80a8e7e632600aff1c72460e9c7dfe94a2dda6829055565b612bf67faa81344d5857c875349bc4a95d531a580c46bdd94c41b35b1e072e4d627079f8829055565b612bf67fb6d5e19fdd6cde5f03ed4f17c2670deffa47975541fd270b0b17e803297d7608829055565b612bf67fbc8b9852d17d50256bb221fdf6ee12d78dd493d807e907f7d223c40d65abd6b9829055565b612bf67fd1c64973da70267569571a091966834c1a36bdba47f2a112b6a95bf41fc9c24e829055565b60006117547faa81344d5857c875349bc4a95d531a580c46bdd94c41b35b1e072e4d627079f85490565b600061318985858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137f992505050565b90506000600284836040516020016131ab929190918252602082015260400190565b60408051601f19818403018152908290526131c59161533a565b602060405180830381855afa1580156131e2573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906132059190615356565b90506000613211614080565b9050600061321f82846140aa565b9050806001600160a01b03163b6000036132a15761323d8284614110565b50604051630b302c9560e21b81526001600160a01b03868116600483015260248201869052821690632cc0b25490604401600060405180830381600087803b15801561328857600080fd5b505af115801561329c573d6000803e3d6000fd5b505050505b806001600160a01b0316633ccfd60b6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156132dc57600080fd5b505af11580156132f0573d6000803e3d6000fd5b505050505050505050505050565b60006117547fb6d5e19fdd6cde5f03ed4f17c2670deffa47975541fd270b0b17e803297d76085490565b60006117547ffbeda9bc03875013b12a1ec161efb8e5bf7e58e3cec96a1ea9efd3e264d26e645490565b600061335d82612f1d565b805160008051602061551183398151915280549293509160009081906133d09085908890811061338f5761338f615177565b9060005260206000209060060201600201548560000188815481106133b6576133b6615177565b9060005260206000209060060201600301805490506141b0565b9050846020015163ffffffff1681116133f8576133f386600087602001516141c1565b61341e565b602085015161340d9063ffffffff16826151d9565b915061341e868387602001516141c1565b8163ffffffff168363ffffffff1614611742576117428263ffffffff168463ffffffff1661344a612c3a565b61345491906151d9565b612c7d91906151c1565b600060008051602061551183398151915280548390811061348157613481615177565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156135905783829060005260206000200180546135039061518d565b80601f016020809104026020016040519081016040528092919081815260200182805461352f9061518d565b801561357c5780601f106135515761010080835404028352916020019161357c565b820191906000526020600020905b81548152906001019060200180831161355f57829003601f168201915b5050505050815260200190600101906134e4565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156136695783829060005260206000200180546135dc9061518d565b80601f01602080910402602001604051908101604052809291908181526020018280546136089061518d565b80156136555780601f1061362a57610100808354040283529160200191613655565b820191906000526020600020905b81548152906001019060200180831161363857829003601f168201915b5050505050815260200190600101906135bd565b505050908252506005919091015460ff16151560209091015260a0810151909150156136a857604051630450a9a360e21b815260040160405180910390fd5b80516001600160a01b03163314610b08576040516282b42960e81b815260040160405180910390fd5b60006117547fb88142a0318e2b174876bceb4db9dc318011849c83fb8a8bb2997386d562324a5490565b600080613707846137f9565b9050600060028483604051602001613729929190918252602082015260400190565b60408051601f19818403018152908290526137439161533a565b602060405180830381855afa158015613760573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906137839190615356565b9050600061378f614080565b905061379b81836140aa565b9695505050505050565b60006117547f41118591c19026bdc7a484e34f80a8e7e632600aff1c72460e9c7dfe94a2dda65490565b60006117547f10c92bb459c0223bf996150f2fb702a8288fb8354a33d5b0212e8e6b8273f55e5490565b6000600261380683613a16565b604051613813919061533a565b602060405180830381855afa158015613830573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061183b9190615356565b60009081527f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e26560205260409020546001600160a01b031690565b60006117547e595eca1f8b39945ff4c404827bfa5fd1e295ef3f7d59d120a8ce3bae4e37a05490565b612bf67fce3b5bd42ef5aae9d7b01cd806ce2a8b66f0a48f2e8b5a15f77dfbbdbbf5144f829055565b6060816138ed81601f6151c1565b101561392c5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401611d33565b61393682846151c1565b8451101561397a5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401611d33565b60608215801561399957604051915060008252602082016040526139e3565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156139d25780518352602092830192016139ba565b5050858452601f01601f1916604052505b50949350505050565b60006117547fce3b5bd42ef5aae9d7b01cd806ce2a8b66f0a48f2e8b5a15f77dfbbdbbf5144f5490565b60606020825110158015613a2c57506040825111155b613a3857613a386153b1565b8151604003613a45575090565b604080516020808252818301909252600091602082018180368337019050509050600060208201528251602003613a8757613a808382614235565b9392505050565b613a8083613aa483600087516040613a9f91906151d9565b6138df565b614235565b50919050565b612bf67e595eca1f8b39945ff4c404827bfa5fd1e295ef3f7d59d120a8ce3bae4e37a0829055565b6000805160206155118339815191528054600090829086908110613afd57613afd615177565b906000526020600020906006020190506000613b1886612f1d565b602081015190915063ffffffff165b85826020015163ffffffff16613b3d91906151c1565b811015613d68576000836003018281548110613b5b57613b5b615177565b906000526020600020018054613b709061518d565b80601f0160208091040260200160405190810160405280929190818152602001828054613b9c9061518d565b8015613be95780601f10613bbe57610100808354040283529160200191613be9565b820191906000526020600020905b815481529060010190602001808311613bcc57829003601f168201915b505050505090506000846004018381548110613c0757613c07615177565b906000526020600020018054613c1c9061518d565b80601f0160208091040260200160405190810160405280929190818152602001828054613c489061518d565b8015613c955780601f10613c6a57610100808354040283529160200191613c95565b820191906000526020600020905b815481529060010190602001808311613c7857829003601f168201915b505050505090506000613ca98360016136fb565b90506000613cb6826142b2565b9050613cc38484836142cb565b6000613cce856137f9565b60008181527f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e26560205260409081902080546001600160a01b0319166001600160a01b038e1690811790915590519192509033907fac1020908b5f7134d59c1580838eba6fc42dd8c28bae65bf345676bba1913f8e90613d5090899089906153c7565b60405180910390a38560010195505050505050613b27565b506117428686836000015163ffffffff16613d8391906151d9565b87846020015163ffffffff16613d9991906151c1565b6141c1565b612bf67f559ad51499ae00ca2e9d9d95aab46737c8904ab7da276613fefda282b2c2ac06829055565b600080613dd261467c565b905060005b6036811015613e2a578360ff16828260368110613df657613df6615177565b602002015160ff1610613e2257818160368110613e1557613e15615177565b6020020151949350505050565b600101613dd7565b50604051631470905f60e01b815260040160405180910390fd5b60008082856020613e568760026152ad565b613e609190615139565b60208110613e7057613e70615177565b613e7c9291901a6153f5565b9150613e89600184615417565b856020613e978760026152ad565b613ea29060016151c1565b613eac9190615139565b60208110613ebc57613ebc615177565b613ec89291901a6153f5565b613ed390600161543a565b9050935093915050565b60008060001980875b8260010b6000191480613efd57508160010b600019145b15613f81576000613f0e828861483a565b63ffffffff161115613f38578260010b60001903613f31578060000b9250613f38565b8060000b91505b8660ff168860ff168260ff16613f4e91906151c1565b613f589190615139565b90508860ff168160ff16148015613f7357508160010b600019145b15613f7c578291505b613ee6565b509097909650945050505050565b6001818360ff1681518110613fa657613fa6615177565b6020026020010151606001818151613fbe919061545f565b63ffffffff169052505050565b600080613fd88684614972565b63ffffffff1690506000613fec8685614972565b63ffffffff16905080821015614006578692505050614078565b80821115614018578592505050614078565b600060028660206140298a8c61543a565b61403391906153f5565b60ff166020811061404657614046615177565b6140529291901a6153f5565b60ff166001149050801515600015150361407157869350505050614078565b8793505050505b949350505050565b60006117547fd1c64973da70267569571a091966834c1a36bdba47f2a112b6a95bf41fc9c24e5490565b6000611838838330604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b03811661183b5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401611d33565b600081831015613aa957508161183b565b600283901c60009081527f37e2c371bbf1c7a1326d52e30855e9c8b6cac15eda4475320e427b948813a9f060209081526040909120805467ffffffffffffffff60c060069790971b9690961695861b191663ffffffff9490941667ffffffff000000009390921b929092161790921b179055565b6060806040519050835180825260208201818101602087015b8183101561426657805183526020928301920161424e565b50855184518101855292509050808201602086015b8183101561429357805183526020928301920161427b565b508651929092011591909101601f01601f191660405250905092915050565b600061183b6001600160a01b038316600160f81b6151c1565b60006142d6846137f9565b905060006002806142ea86600060406138df565b6040516142f7919061533a565b602060405180830381855afa158015614314573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906143379190615356565b600261435261434d886040613a9f8160606151d9565b613a16565b60405161435f919061533a565b602060405180830381855afa15801561437c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061439f9190615356565b60408051602081019390935282015260600160408051601f19818403018152908290526143cb9161533a565b602060405180830381855afa1580156143e8573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061440b9190615356565b90506000614426633b9aca006801bc16d674ec800000615163565b90506801bc16d674ec80000061444082633b9aca006152ad565b1461444d5761444d6153b1565b6000600280858760405160200161446e929190918252602082015260400190565b60408051601f19818403018152908290526144889161533a565b602060405180830381855afa1580156144a5573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906144c89190615356565b60026144d385614aaa565b604080516020810192909252810187905260600160408051601f19818403018152908290526145019161533a565b602060405180830381855afa15801561451e573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906145419190615356565b60408051602081019390935282015260600160408051601f198184030181529082905261456d9161533a565b602060405180830381855afa15801561458a573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906145ad9190615356565b905060006145c46801bc16d674ec800000476151d9565b90506145ce614af0565b6001600160a01b031663228951186801bc16d674ec8000008a896040516020016145fa91815260200190565b6040516020818303038152906040528b876040518663ffffffff1660e01b815260040161462a9493929190615487565b6000604051808303818588803b15801561464357600080fd5b505af1158015614657573d6000803e3d6000fd5b5050505050804714612f1357604051636596d2b760e01b815260040160405180910390fd5b614684614cac565b50604080516106c081018252600281526003602082015260059181019190915260076060820152600b6080820152600d60a0820152601160c0820152601360e08201526017610100820152601d610120820152601f61014082015260256101608201526029610180820152602b6101a0820152602f6101c082015260356101e0820152603b610200820152603d610220820152604361024082015260476102608201526049610280820152604f6102a082015260536102c082015260596102e0820152606161030082015260656103208201526067610340820152606b610360820152606d61038082015260716103a0820152607f6103c082015260836103e08201526089610400820152608b61042082015260956104408201526097610460820152609d61048082015260a36104a082015260a76104c082015260ad6104e082015260b361050082015260b561052082015260bf61054082015260c161056082015260c561058082015260c76105a082015260d36105c082015260df6105e082015260e361060082015260e561062082015260e961064082015260ef61066082015260f161068082015260fb6106a082015290565b600081518360ff161061484f5750600061183b565b818360ff168151811061486457614864615177565b602002602001015160000151151560001515036149265760006148898460ff16612f1d565b90506001838560ff16815181106148a2576148a2615177565b6020908102919091018101519115159091528101518351849060ff87169081106148ce576148ce615177565b60200260200101516040019063ffffffff16908163ffffffff16815250508060000151838560ff168151811061490657614906615177565b60200260200101516080019063ffffffff16908163ffffffff1681525050505b818360ff168151811061493b5761493b615177565b602002602001015160600151828460ff168151811061495c5761495c615177565b60200260200101516080015161183891906154d2565b600081518360ff16106149875750600061183b565b818360ff168151811061499c5761499c615177565b60200260200101516000015115156000151503614a5e5760006149c18460ff16612f1d565b90506001838560ff16815181106149da576149da615177565b6020908102919091018101519115159091528101518351849060ff8716908110614a0657614a06615177565b60200260200101516040019063ffffffff16908163ffffffff16815250508060000151838560ff1681518110614a3e57614a3e615177565b60200260200101516080019063ffffffff16908163ffffffff1681525050505b818360ff1681518110614a7357614a73615177565b602002602001015160600151828460ff1681518110614a9457614a94615177565b602002602001015160400151611838919061545f565b600081815b6008811015614ad857600892831b60ff831617929190911c90614ad1816154f7565b9050614aaf565b508015614ae757614ae76153b1565b5060c01b919050565b60006117547fbc8b9852d17d50256bb221fdf6ee12d78dd493d807e907f7d223c40d65abd6b95490565b508054614b269061518d565b6000825580601f10614b36575050565b601f016020900490600052602060002090810190612bf69190614ccb565b828054614b609061518d565b90600052602060002090601f016020900481019282614b825760008555614bcf565b82601f10614b935780548555614bcf565b82800160010185558215614bcf57600052602060002091601f016020900482015b82811115614bcf578254825591600101919060010190614bb4565b50614bdb929150614ccb565b5090565b828054828255906000526020600020908101928215614c2c579160200282015b82811115614c2c5782518051614c1c918491602090910190614c38565b5091602001919060010190614bff565b50614bdb929150614ce0565b828054614c449061518d565b90600052602060002090601f016020900481019282614c665760008555614bcf565b82601f10614c7f57805160ff1916838001178555614bcf565b82800160010185558215614bcf579182015b82811115614bcf578251825591602001919060010190614c91565b604051806106c001604052806036906020820280368337509192915050565b5b80821115614bdb5760008155600101614ccc565b80821115614bdb576000614cf48282614b1a565b50600101614ce0565b600060208284031215614d0f57600080fd5b5035919050565b80356001600160a01b0381168114614d2d57600080fd5b919050565b600080600080600080600080610100898b031215614d4f57600080fd5b614d5889614d16565b9750614d6660208a01614d16565b9650614d7460408a01614d16565b9550614d8260608a01614d16565b9450614d9060808a01614d16565b9350614d9e60a08a01614d16565b925060c0890135915060e089013590509295985092959890939650565b60008083601f840112614dcd57600080fd5b50813567ffffffffffffffff811115614de557600080fd5b602083019150836020828501011115614dfd57600080fd5b9250929050565b60008060208385031215614e1757600080fd5b823567ffffffffffffffff811115614e2e57600080fd5b614e3a85828601614dbb565b90969095509350505050565b600080600060408486031215614e5b57600080fd5b83359250602084013567ffffffffffffffff80821115614e7a57600080fd5b818601915086601f830112614e8e57600080fd5b813581811115614e9d57600080fd5b8760208260051b8501011115614eb257600080fd5b6020830194508093505050509250925092565b60008060408385031215614ed857600080fd5b82359150614ee860208401614d16565b90509250929050565b60008060408385031215614f0457600080fd5b50508035926020909101359150565b60005b83811015614f2e578181015183820152602001614f16565b8381111561077a5750506000910152565b60008151808452614f57816020860160208601614f13565b601f01601f19169290920160200192915050565b608081526000614f7e6080830187614f3f565b8281036020840152614f908187614f3f565b6001600160a01b03959095166040840152505090151560609091015292915050565b60008060408385031215614fc557600080fd5b614fce83614d16565b9150614ee860208401614d16565b600060208284031215614fee57600080fd5b81358015158114613a8057600080fd5b60008060006060848603121561501357600080fd5b8335925061502360208501614d16565b915061503160408501614d16565b90509250925092565b6000806000806000806080878903121561505357600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561507957600080fd5b6150858a838b01614dbb565b9096509450606089013591508082111561509e57600080fd5b506150ab89828a01614dbb565b979a9699509497509295939492505050565b6000806000604084860312156150d257600080fd5b833567ffffffffffffffff8111156150e957600080fd5b6150f586828701614dbb565b9094509250615031905060208501614d16565b60006020828403121561511a57600080fd5b61183882614d16565b634e487b7160e01b600052601260045260246000fd5b60008261514857615148615123565b500690565b634e487b7160e01b600052601160045260246000fd5b60008261517257615172615123565b500490565b634e487b7160e01b600052603260045260246000fd5b600181811c908216806151a157607f821691505b602082108103613aa957634e487b7160e01b600052602260045260246000fd5b600082198211156151d4576151d461514d565b500190565b6000828210156151eb576151eb61514d565b500390565b600060208083526000845481600182811c91508083168061521257607f831692505b858310810361522f57634e487b7160e01b85526022600452602485fd5b87860183815260200181801561524c576001811461525d57615288565b60ff19861682528782019650615288565b60008b81526020902060005b8681101561528257815484820152908501908901615269565b83019750505b50949998505050505050505050565b634e487b7160e01b600052603160045260246000fd5b60008160001904831182151516156152c7576152c761514d565b500290565b6020815260006118386020830184614f3f565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152600061531c6040830186886152df565b828103602084015261532f8185876152df565b979650505050505050565b6000825161534c818460208701614f13565b9190910192915050565b60006020828403121561536857600080fd5b5051919050565b6040815260006153836040830185876152df565b905060018060a01b0383166020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052600160045260246000fd5b6040815260006153da6040830185614f3f565b82810360208401526153ec8185614f3f565b95945050505050565b600060ff83168061540857615408615123565b8060ff84160691505092915050565b600060ff821660ff8416808210156154315761543161514d565b90039392505050565b600060ff821660ff84168060ff038211156154575761545761514d565b019392505050565b600063ffffffff80831681851680830382111561547e5761547e61514d565b01949350505050565b60808152600061549a6080830187614f3f565b82810360208401526154ac8187614f3f565b905082810360408401526154c08186614f3f565b91505082606083015295945050505050565b600063ffffffff838116908316818110156154ef576154ef61514d565b039392505050565b6000600182016155095761550961514d565b506001019056fed2a2f1f08ad325daf72af0169949ae210065d6916750ff03abd83510331b7b39a4dcee8ff224c7cfd53b1f2cd1f5afd98927d079b4152d639c5e523a52bf1e03a26469706673582212200a6c1962014b7476bb5dc5f50997aba537de06cb542d9fc6e6618512dcd0449664736f6c634300080d0033", + "deployedBytecode": "0x6080604052600436106102085760003560e01c806379ba509711610118578063bf509bd4116100a0578063d2a427471161006f578063d2a42747146105f0578063e00cb6ca14610610578063e99454f514610630578063f0f4426014610650578063f2fde38b1461067057610218565b8063bf509bd414610593578063d0468156146105b3578063d0e30db0146105c8578063d243d69d146105d057610218565b8063a4d8d2c4116100e7578063a4d8d2c414610509578063a740080114610529578063b4336b8414610549578063b747e7dd1461055e578063bf15af561461057e57610218565b806379ba5097146104945780638a1af4c4146104a95780638df4e474146104c95780639adf91ee146104e957610218565b8063286966081161019b5780633b19e84a1161016a5780633b19e84a14610405578063540bc5ea1461041a57806363b4118f1461042f5780636e9960c31461045f578063714b55b21461047457610218565b80632869660814610393578063291206f6146103a85780632ba03a79146103c857806336bf3325146103e857610218565b80631bcbfaba116101d75780631bcbfaba146102f85780631d0958051461031b5780631ee133431461033b578063227e80fa1461037357610218565b806305f63c8a1461023157806308b3a073146102985780630968f264146102b85780631864636c146102d857610218565b366102185761021633610690565b005b60405163574b16a760e11b815260040160405180910390fd5b34801561023d57600080fd5b5061025161024c366004614cfd565b610780565b604080516001600160a01b039889168152979096166020880152948601939093526060850191909152608084015260a0830152151560c082015260e0015b60405180910390f35b3480156102a457600080fd5b506102166102b3366004614d32565b610a10565b3480156102c457600080fd5b506102166102d3366004614e04565b610ae5565b3480156102e457600080fd5b506102166102f3366004614e46565b610b0c565b34801561030457600080fd5b5061030d61174a565b60405190815260200161028f565b34801561032757600080fd5b50610216610336366004614cfd565b611759565b34801561034757600080fd5b5061035b610356366004614e04565b6117f4565b6040516001600160a01b03909116815260200161028f565b34801561037f57600080fd5b5061021661038e366004614ec5565b611841565b34801561039f57600080fd5b5061030d6119b8565b3480156103b457600080fd5b506102166103c3366004614cfd565b6119c2565b3480156103d457600080fd5b506102166103e3366004614e04565b610af9565b3480156103f457600080fd5b5061030d6801bc16d674ec80000081565b34801561041157600080fd5b5061035b611a56565b34801561042657600080fd5b5061030d606081565b34801561043b57600080fd5b5061044f61044a366004614ef1565b611a60565b60405161028f9493929190614f6b565b34801561046b57600080fd5b5061035b611c44565b34801561048057600080fd5b5061021661048f366004614ef1565b611c4e565b3480156104a057600080fd5b50610216611d9d565b3480156104b557600080fd5b5061030d6104c4366004614fb2565b611e13565b3480156104d557600080fd5b506102166104e4366004614fdc565b611fcc565b3480156104f557600080fd5b5061035b610504366004614cfd565b61203f565b34801561051557600080fd5b50610216610524366004614ffe565b6120bd565b34801561053557600080fd5b5061035b610544366004614cfd565b612429565b34801561055557600080fd5b5061030d612434565b34801561056a57600080fd5b5061021661057936600461503a565b61243e565b34801561058a57600080fd5b5061030d603081565b34801561059f57600080fd5b506102166105ae366004614e04565b612777565b3480156105bf57600080fd5b5061035b612786565b610216612790565b3480156105dc57600080fd5b5061035b6105eb366004614e04565b61279b565b3480156105fc57600080fd5b5061021661060b366004614ec5565b6127dc565b34801561061c57600080fd5b5061035b61062b366004614e04565b6129b9565b34801561063c57600080fd5b5061021661064b3660046150bd565b6129fd565b34801561065c57600080fd5b5061021661066b366004615108565b612b79565b34801561067c57600080fd5b5061021661068b366004615108565b612bf9565b3415806106ae57506106ab6801bc16d674ec80000034615139565b15155b156106cc5760405163214121f160e11b815260040160405180910390fd5b60006106d6612c3a565b905060006106ed6801bc16d674ec80000034615163565b905081811115610710576040516315caeb5160e31b815260040160405180910390fd5b60008051602061551183398151915280546000036107415760405163ddf9d24560e01b815260040160405180910390fd5b805460010361075a57610755848385612c64565b61077a565b805460020361076e57610755848385612c82565b61077a84838584612d90565b50505050565b6000808080808080806000805160206155118339815191528054909150891015610a045760006107af8a612f1d565b90506000826000018b815481106107c8576107c8615177565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156108d757838290600052602060002001805461084a9061518d565b80601f01602080910402602001604051908101604052809291908181526020018280546108769061518d565b80156108c35780601f10610898576101008083540402835291602001916108c3565b820191906000526020600020905b8154815290600101906020018083116108a657829003601f168201915b50505050508152602001906001019061082b565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156109b05783829060005260206000200180546109239061518d565b80601f016020809104026020016040519081016040528092919081815260200182805461094f9061518d565b801561099c5780601f106109715761010080835404028352916020019161099c565b820191906000526020600020905b81548152906001019060200180831161097f57829003601f168201915b505050505081526020019060010190610904565b505050908252506005919091015460ff161515602091820152815182820151604084015160608501515160a090950151938701519651929e50909c509a5091985063ffffffff938416975092169450909250505b50919395979092949650565b6001610a1a612f83565b610a259060016151c1565b8114610a435760405162dc149f60e41b815260040160405180910390fd5b610a4c81612fad565b610a5589612fd6565b610a5e88612fff565b612710831115610a81576040516358d620b360e01b815260040160405180910390fd5b610a8a83613028565b612710821115610aad576040516358d620b360e01b815260040160405180910390fd5b610ab682613051565b610abf8661307a565b610ac8856130a3565b610ad1876130cc565b610ada846130f5565b505050505050505050565b610af982826000610af461311e565b613148565b610b0882826001610af46132fe565b5050565b82610b15613328565b6001600160a01b03163303611132576000829003610b465760405163a9cb9e0d60e01b815260040160405180910390fd5b6000610b5185612f1d565b60208101519091506000805160206155118339815191529063ffffffff168585610b7c6001826151d9565b818110610b8b57610b8b615177565b905060200201351015610bb1576040516334947ea160e01b815260040160405180910390fd5b60005b8481101561103057600081118015610c0657508585610bd46001846151d9565b818110610be357610be3615177565b90506020020135868683818110610bfc57610bfc615177565b9050602002013510155b15610c24576040516335061dff60e01b815260040160405180910390fd5b867f794aacb42d1ea2e7f72809b74e3ce124325a51c3715b873c36807d3ca37e4fd0836000018981548110610c5b57610c5b615177565b9060005260206000209060060201600301888885818110610c7e57610c7e615177565b9050602002013581548110610c9557610c95615177565b90600052602060002001604051610cac91906151f0565b60405180910390a26001826000018881548110610ccb57610ccb615177565b906000526020600020906006020160030180549050610cea91906151d9565b868683818110610cfc57610cfc615177565b9050602002013503610db357816000018781548110610d1d57610d1d615177565b9060005260206000209060060201600301805480610d3d57610d3d615297565b600190038181906000526020600020016000610d599190614b1a565b9055816000018781548110610d7057610d70615177565b9060005260206000209060060201600401805480610d9057610d90615297565b600190038181906000526020600020016000610dac9190614b1a565b9055611028565b816000018781548110610dc857610dc8615177565b90600052602060002090600602016003016001836000018981548110610df057610df0615177565b906000526020600020906006020160030180549050610e0f91906151d9565b81548110610e1f57610e1f615177565b90600052602060002001826000018881548110610e3e57610e3e615177565b9060005260206000209060060201600301878784818110610e6157610e61615177565b9050602002013581548110610e7857610e78615177565b90600052602060002001908054610e8e9061518d565b610e99929190614b54565b50816000018781548110610eaf57610eaf615177565b9060005260206000209060060201600301805480610ecf57610ecf615297565b600190038181906000526020600020016000610eeb9190614b1a565b9055816000018781548110610f0257610f02615177565b90600052602060002090600602016004016001836000018981548110610f2a57610f2a615177565b906000526020600020906006020160040180549050610f4991906151d9565b81548110610f5957610f59615177565b90600052602060002001826000018881548110610f7857610f78615177565b9060005260206000209060060201600401878784818110610f9b57610f9b615177565b9050602002013581548110610fb257610fb2615177565b90600052602060002001908054610fc89061518d565b610fd3929190614b54565b50816000018781548110610fe957610fe9615177565b906000526020600020906006020160040180548061100957611009615297565b6001900381819060005260206000200160006110259190614b1a565b90555b600101610bb4565b5080600001868154811061104657611046615177565b600091825260209091206002600690920201015485856110676001826151d9565b81811061107657611076615177565b9050602002013510156111225784846110906001826151d9565b81811061109f5761109f615177565b905060200201358160000187815481106110bb576110bb615177565b60009182526020909120600260069092020101556000805160206155318339815191528686866110ec6001826151d9565b8181106110fb576110fb615177565b90506020020135604051611119929190918252602082015260400190565b60405180910390a15b61112b86613352565b505061077a565b61113b8161345e565b600082900361115d5760405163a9cb9e0d60e01b815260040160405180910390fd5b600061116885612f1d565b60208101519091506000805160206155118339815191529063ffffffff1685856111936001826151d9565b8181106111a2576111a2615177565b9050602002013510156111c8576040516334947ea160e01b815260040160405180910390fd5b60005b848110156116475760008111801561121d575085856111eb6001846151d9565b8181106111fa576111fa615177565b9050602002013586868381811061121357611213615177565b9050602002013510155b1561123b576040516335061dff60e01b815260040160405180910390fd5b867f794aacb42d1ea2e7f72809b74e3ce124325a51c3715b873c36807d3ca37e4fd083600001898154811061127257611272615177565b906000526020600020906006020160030188888581811061129557611295615177565b90506020020135815481106112ac576112ac615177565b906000526020600020016040516112c391906151f0565b60405180910390a260018260000188815481106112e2576112e2615177565b90600052602060002090600602016003018054905061130191906151d9565b86868381811061131357611313615177565b90506020020135036113ca5781600001878154811061133457611334615177565b906000526020600020906006020160030180548061135457611354615297565b6001900381819060005260206000200160006113709190614b1a565b905581600001878154811061138757611387615177565b90600052602060002090600602016004018054806113a7576113a7615297565b6001900381819060005260206000200160006113c39190614b1a565b905561163f565b8160000187815481106113df576113df615177565b9060005260206000209060060201600301600183600001898154811061140757611407615177565b90600052602060002090600602016003018054905061142691906151d9565b8154811061143657611436615177565b9060005260206000200182600001888154811061145557611455615177565b906000526020600020906006020160030187878481811061147857611478615177565b905060200201358154811061148f5761148f615177565b906000526020600020019080546114a59061518d565b6114b0929190614b54565b508160000187815481106114c6576114c6615177565b90600052602060002090600602016003018054806114e6576114e6615297565b6001900381819060005260206000200160006115029190614b1a565b905581600001878154811061151957611519615177565b9060005260206000209060060201600401600183600001898154811061154157611541615177565b90600052602060002090600602016004018054905061156091906151d9565b8154811061157057611570615177565b9060005260206000200182600001888154811061158f5761158f615177565b90600052602060002090600602016004018787848181106115b2576115b2615177565b90506020020135815481106115c9576115c9615177565b906000526020600020019080546115df9061518d565b6115ea929190614b54565b5081600001878154811061160057611600615177565b906000526020600020906006020160040180548061162057611620615297565b60019003818190600052602060002001600061163c9190614b1a565b90555b6001016111cb565b5080600001868154811061165d5761165d615177565b6000918252602090912060026006909202010154858561167e6001826151d9565b81811061168d5761168d615177565b9050602002013510156117395784846116a76001826151d9565b8181106116b6576116b6615177565b905060200201358160000187815481106116d2576116d2615177565b60009182526020909120600260069092020101556000805160206155318339815191528686866117036001826151d9565b81811061171257611712615177565b90506020020135604051611730929190918252602082015260400190565b60405180910390a15b61174286613352565b505050505050565b60006117546136d1565b905090565b611761613328565b6001600160a01b0316336001600160a01b031614611791576040516282b42960e81b815260040160405180910390fd5b6127108111156117b4576040516358d620b360e01b815260040160405180910390fd5b6117bd81613051565b6040518181527fd894096cd1f7e89d9b748c7c2358cb699a790a05e97dcde228fe5949b4e80743906020015b60405180910390a150565b600061183883838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506136fb915050565b90505b92915050565b611849613328565b6001600160a01b0316336001600160a01b031614611879576040516282b42960e81b815260040160405180910390fd5b600080516020615511833981519152805460009082908590811061189f5761189f615177565b600091825260209182902060069190910201600501805460ff1916921515929092179091556040518481527f8d0ba049731b0417f85546bc7503de241522c61e7464e87cceff56d3f2586dbc910160405180910390a18181600001848154811061190b5761190b615177565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055507f97568892aa9e69db7c72b9f32e6d4fe3c0e53b9728a8c0a0f1c2a7eb47c48ad38382600001858154811061197757611977615177565b600091825260209182902060069091020154604080519384526001600160a01b039182169284019290925285169082015260600160405180910390a1505050565b60006117546137a5565b6119ca613328565b6001600160a01b0316336001600160a01b0316146119fa576040516282b42960e81b815260040160405180910390fd5b612710811115611a1d576040516358d620b360e01b815260040160405180910390fd5b611a2681613028565b6040518181527fecd6fc650620aa722cafc3c3e871fa813947eae6f856982d7510a8ff101a5078906020016117e9565b60006117546137cf565b606080600080806000805160206155118339815191529050806000018781548110611a8d57611a8d615177565b90600052602060002090600602016003018681548110611aaf57611aaf615177565b906000526020600020018054611ac49061518d565b80601f0160208091040260200160405190810160405280929190818152602001828054611af09061518d565b8015611b3d5780601f10611b1257610100808354040283529160200191611b3d565b820191906000526020600020905b815481529060010190602001808311611b2057829003601f168201915b50505050509450806000018781548110611b5957611b59615177565b90600052602060002090600602016004018681548110611b7b57611b7b615177565b906000526020600020018054611b909061518d565b80601f0160208091040260200160405190810160405280929190818152602001828054611bbc9061518d565b8015611c095780601f10611bde57610100808354040283529160200191611c09565b820191906000526020600020905b815481529060010190602001808311611bec57829003601f168201915b50505050509350611c21611c1c866137f9565b613853565b9250611c2c87612f1d565b6020015163ffffffff16861091505092959194509250565b6000611754613328565b611c56613328565b6001600160a01b0316336001600160a01b031614611c86576040516282b42960e81b815260040160405180910390fd5b6000805160206155118339815191528054819084908110611ca957611ca9615177565b600091825260209091206005600690920201015460ff1615611cde57604051630450a9a360e21b815260040160405180910390fd5b6000816000018481548110611cf557611cf5615177565b906000526020600020906006020160030180549050905082811015611d3c576040516362106cb360e01b815260048101849052602481018290526044015b60405180910390fd5b82826000018581548110611d5257611d52615177565b906000526020600020906006020160020181905550611d7084613352565b6040805185815260208101859052600080516020615531833981519152910160405180910390a150505050565b6000611da761388d565b9050336001600160a01b03821614611dd1576040516282b42960e81b815260040160405180910390fd5b611dda81612fd6565b6040516001600160a01b03821681527ff29c1089a9594c030706593e345bd8f70a26125bfb7bf4c54e757e20f456fd1c906020016117e9565b6000611e1d613328565b6001600160a01b0316336001600160a01b031614611e4d576040516282b42960e81b815260040160405180910390fd5b6040805160c0810182526000808252602082018190529181018290526060808201819052608082015260a0810191909152600080516020615511833981519152805490919060fb03611eb25760405163a20c741360e01b815260040160405180910390fd5b6001600160a01b03808616825284811660208084019182528454600181810187556000878152839020865160069093020180549286166001600160a01b0319938416178155935190840180549190951691161790925560408301516002820155606083015180518493611f2c926003850192910190614bdf565b5060808201518051611f48916004840191602090910190614bdf565b5060a091909101516005909101805460ff19169115159190911790558154600090611f75906001906151d9565b604080516001600160a01b03808a168252881660208201529081018290529091507f2b3c4db2c0f4f51da09c2510a63e1d90235e486e8f075a609103a5c7a07422179060600160405180910390a195945050505050565b611fd4613328565b6001600160a01b0316336001600160a01b031614612004576040516282b42960e81b815260040160405180910390fd5b61200d816138b6565b60405181151581527f96639403db35a7ef32b25543bec54f73278d8c5ca82883ef1385ddcb27afa7dc906020016117e9565b60008181527fc58a51931c529c2a8796a8fad2ae789ee504643b4b567f2c0c97e809cec93902602052604081205460008051602061551183398151915280549091610100900463ffffffff1690811061209a5761209a615177565b60009182526020909120600160069092020101546001600160a01b031692915050565b8260006000805160206155118339815191528054839081106120e1576120e1615177565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156121f05783829060005260206000200180546121639061518d565b80601f016020809104026020016040519081016040528092919081815260200182805461218f9061518d565b80156121dc5780601f106121b1576101008083540402835291602001916121dc565b820191906000526020600020905b8154815290600101906020018083116121bf57829003601f168201915b505050505081526020019060010190612144565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156122c957838290600052602060002001805461223c9061518d565b80601f01602080910402602001604051908101604052809291908181526020018280546122689061518d565b80156122b55780601f1061228a576101008083540402835291602001916122b5565b820191906000526020600020905b81548152906001019060200180831161229857829003601f168201915b50505050508152602001906001019061221d565b505050908252506005919091015460ff16151560209091015260a08101519091501561230857604051630450a9a360e21b815260040160405180910390fd5b80602001516001600160a01b0316336001600160a01b03161461233d576040516282b42960e81b815260040160405180910390fd5b6000805160206155118339815191528054859082908890811061236257612362615177565b906000526020600020906006020160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160000187815481106123ad576123ad615177565b60009182526020918290206006919091020160010180546001600160a01b0319166001600160a01b0393841617905560408051898152888416928101929092529186168183015290517f97568892aa9e69db7c72b9f32e6d4fe3c0e53b9728a8c0a0f1c2a7eb47c48ad3916060908290030190a1505050505050565b600061183b82613853565b6000611754612c3a565b856124488161345e565b856000036124695760405163a9cb9e0d60e01b815260040160405180910390fd5b612474603085615139565b15158061248b575085612488603086615163565b14155b156124a95760405163337d0f4160e01b815260040160405180910390fd5b6124b4606083615139565b1515806124cb5750856124c8606084615163565b14155b156124e95760405163274cf40160e01b815260040160405180910390fd5b6000805160206155118339815191527fc58a51931c529c2a8796a8fad2ae789ee504643b4b567f2c0c97e809cec9390260005b8881101561272f57600061257489898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061256d9250603091508690506152ad565b60306138df565b905060006125c688888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506125bf9250606091508790506152ad565b60606138df565b9050846000018c815481106125dd576125dd615177565b600091825260208083206003600690930201919091018054600181018255908352918190208451612615939190910191850190614c38565b50846000018c8154811061262b5761262b615177565b600091825260208083206004600690930201919091018054600181018255908352918190208351612663939190910191840190614c38565b50600061266f836137f9565b60008181526020879052604090205490915060ff16156126a45782604051635a303adb60e01b8152600401611d3391906152cc565b60405180604001604052806001151581526020018e63ffffffff1681525085600001600083815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548163ffffffff021916908363ffffffff16021790555090505083600101935050505061251c565b50887fb82c87b84f76f39d5f61ed59b411352603805dda6080a2c44b4a86eab141ff1b888888886040516127669493929190615308565b60405180910390a2610ada89613352565b610b0882826000610af461311e565b600061175461388d565b61279933610690565b565b600061183883838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092506136fb915050565b6127e4613328565b6001600160a01b0316336001600160a01b031614612814576040516282b42960e81b815260040160405180910390fd5b600080516020615511833981519152805460009082908590811061283a5761283a615177565b906000526020600020906006020160020181905550600080516020615531833981519152836000604051612878929190918252602082015260400190565b60405180910390a1600181600001848154811061289757612897615177565b600091825260209182902060069190910201600501805460ff1916921515929092179091556040518481527f4c644bb0e171ba9e5cf08f5d66836528c3947c3512b34dd8e27da30e803527b3910160405180910390a18181600001848154811061290357612903615177565b906000526020600020906006020160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055507f97568892aa9e69db7c72b9f32e6d4fe3c0e53b9728a8c0a0f1c2a7eb47c48ad38382600001858154811061296f5761296f615177565b600091825260209182902060069091020154604080519384526001600160a01b039182169284019290925285169082015260600160405180910390a16129b483613352565b505050565b6000611838611c1c84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137f992505050565b612a056139ec565b612a2257604051631dd2188d60e31b815260040160405180910390fd5b60006002612a6585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613a1692505050565b604051612a72919061533a565b602060405180830381855afa158015612a8f573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612ab29190615356565b905060007f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e2656000838152602082905260409020549091506001600160a01b03163314612b10576040516282b42960e81b815260040160405180910390fd5b7f833a0d0704fbdc6a0f748ebec819c31dde0b532ca9e3e29f56a5c4e8f3cbc0c9858585604051612b439392919061536f565b60405180910390a160009182526020526040902080546001600160a01b0319166001600160a01b03929092169190911790555050565b612b81613328565b6001600160a01b0316336001600160a01b031614612bb1576040516282b42960e81b815260040160405180910390fd5b6040516001600160a01b03821681527f63cc689e9d3377465b51fb094ea4ca5e0a1436b21f1ad30d707c696111c665009060200160405180910390a1612bf681612fff565b50565b612c01613328565b6001600160a01b0316336001600160a01b031614612c31576040516282b42960e81b815260040160405180910390fd5b612bf681613aaf565b60006117547f559ad51499ae00ca2e9d9d95aab46737c8904ab7da276613fefda282b2c2ac065490565b612c7060008385613ad7565b6129b4612c7d83836151d9565b613d9e565b6000612c8e6000612f1d565b90506000612c9c6001612f1d565b9050600080612cac600243615139565b600003612cd157612cbe600287615163565b9150612cca82876151d9565b9050612ceb565b612cdc600287615163565b9050612ce881876151d9565b91505b835163ffffffff16821115612d1d578351612d0c9063ffffffff16876151d9565b845163ffffffff1692509050612d4c565b825163ffffffff16811115612d4c578251612d3e9063ffffffff16876151d9565b835190925063ffffffff1690505b8115612d5e57612d5e60008389613ad7565b8015612d7057612d7060018289613ad7565b612d87612d7d82846151c1565b612c7d90876151d9565b50505050505050565b80546000612d9d82613dc7565b90506000612dac6001436151d9565b40905060008367ffffffffffffffff811115612dca57612dca61539b565b604051908082528060200260200182016040528015612e2357816020015b6040805160a081018252600080825260208083018290529282018190526060820181905260808201528252600019909201910181612de85790505b50905060005b87811015612e9657600080612e3f858488613e44565b91509150600080612e5284848a89613edd565b915091508060ff168260ff1603612e7257612e6d8287613f8f565b612e87565b612e87612e8183838a8a613fcb565b87613f8f565b84600101945050505050612e29565b5060005b8151811015612f05576000828281518110612eb757612eb7615177565b60200260200101516060015163ffffffff161115612efd57612efd81838381518110612ee557612ee5615177565b60200260200101516060015163ffffffff168b613ad7565b600101612e9a565b50612f13612c7d88886151d9565b5050505050505050565b60408051808201825260008082526020808301828152600286901c83527f37e2c371bbf1c7a1326d52e30855e9c8b6cac15eda4475320e427b948813a9f08252939091205463ffffffff60c060069690961b959095161c8481168352901c909216905290565b60006117547fd5c553085b8382c47128ae7612257fd5dc3b4fc4d3a108925604d3c8700c025b5490565b612bf67fd5c553085b8382c47128ae7612257fd5dc3b4fc4d3a108925604d3c8700c025b829055565b612bf67ffbeda9bc03875013b12a1ec161efb8e5bf7e58e3cec96a1ea9efd3e264d26e64829055565b612bf67f10c92bb459c0223bf996150f2fb702a8288fb8354a33d5b0212e8e6b8273f55e829055565b612bf67fb88142a0318e2b174876bceb4db9dc318011849c83fb8a8bb2997386d562324a829055565b612bf67f41118591c19026bdc7a484e34f80a8e7e632600aff1c72460e9c7dfe94a2dda6829055565b612bf67faa81344d5857c875349bc4a95d531a580c46bdd94c41b35b1e072e4d627079f8829055565b612bf67fb6d5e19fdd6cde5f03ed4f17c2670deffa47975541fd270b0b17e803297d7608829055565b612bf67fbc8b9852d17d50256bb221fdf6ee12d78dd493d807e907f7d223c40d65abd6b9829055565b612bf67fd1c64973da70267569571a091966834c1a36bdba47f2a112b6a95bf41fc9c24e829055565b60006117547faa81344d5857c875349bc4a95d531a580c46bdd94c41b35b1e072e4d627079f85490565b600061318985858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137f992505050565b90506000600284836040516020016131ab929190918252602082015260400190565b60408051601f19818403018152908290526131c59161533a565b602060405180830381855afa1580156131e2573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906132059190615356565b90506000613211614080565b9050600061321f82846140aa565b9050806001600160a01b03163b6000036132a15761323d8284614110565b50604051630b302c9560e21b81526001600160a01b03868116600483015260248201869052821690632cc0b25490604401600060405180830381600087803b15801561328857600080fd5b505af115801561329c573d6000803e3d6000fd5b505050505b806001600160a01b0316633ccfd60b6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156132dc57600080fd5b505af11580156132f0573d6000803e3d6000fd5b505050505050505050505050565b60006117547fb6d5e19fdd6cde5f03ed4f17c2670deffa47975541fd270b0b17e803297d76085490565b60006117547ffbeda9bc03875013b12a1ec161efb8e5bf7e58e3cec96a1ea9efd3e264d26e645490565b600061335d82612f1d565b805160008051602061551183398151915280549293509160009081906133d09085908890811061338f5761338f615177565b9060005260206000209060060201600201548560000188815481106133b6576133b6615177565b9060005260206000209060060201600301805490506141b0565b9050846020015163ffffffff1681116133f8576133f386600087602001516141c1565b61341e565b602085015161340d9063ffffffff16826151d9565b915061341e868387602001516141c1565b8163ffffffff168363ffffffff1614611742576117428263ffffffff168463ffffffff1661344a612c3a565b61345491906151d9565b612c7d91906151c1565b600060008051602061551183398151915280548390811061348157613481615177565b600091825260208083206040805160c081018252600690940290910180546001600160a01b039081168552600182015416848401526002810154848301526003810180548351818602810186019094528084529495919460608701949192909184015b828210156135905783829060005260206000200180546135039061518d565b80601f016020809104026020016040519081016040528092919081815260200182805461352f9061518d565b801561357c5780601f106135515761010080835404028352916020019161357c565b820191906000526020600020905b81548152906001019060200180831161355f57829003601f168201915b5050505050815260200190600101906134e4565b50505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156136695783829060005260206000200180546135dc9061518d565b80601f01602080910402602001604051908101604052809291908181526020018280546136089061518d565b80156136555780601f1061362a57610100808354040283529160200191613655565b820191906000526020600020905b81548152906001019060200180831161363857829003601f168201915b5050505050815260200190600101906135bd565b505050908252506005919091015460ff16151560209091015260a0810151909150156136a857604051630450a9a360e21b815260040160405180910390fd5b80516001600160a01b03163314610b08576040516282b42960e81b815260040160405180910390fd5b60006117547fb88142a0318e2b174876bceb4db9dc318011849c83fb8a8bb2997386d562324a5490565b600080613707846137f9565b9050600060028483604051602001613729929190918252602082015260400190565b60408051601f19818403018152908290526137439161533a565b602060405180830381855afa158015613760573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906137839190615356565b9050600061378f614080565b905061379b81836140aa565b9695505050505050565b60006117547f41118591c19026bdc7a484e34f80a8e7e632600aff1c72460e9c7dfe94a2dda65490565b60006117547f10c92bb459c0223bf996150f2fb702a8288fb8354a33d5b0212e8e6b8273f55e5490565b6000600261380683613a16565b604051613813919061533a565b602060405180830381855afa158015613830573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061183b9190615356565b60009081527f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e26560205260409020546001600160a01b031690565b60006117547e595eca1f8b39945ff4c404827bfa5fd1e295ef3f7d59d120a8ce3bae4e37a05490565b612bf67fce3b5bd42ef5aae9d7b01cd806ce2a8b66f0a48f2e8b5a15f77dfbbdbbf5144f829055565b6060816138ed81601f6151c1565b101561392c5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401611d33565b61393682846151c1565b8451101561397a5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401611d33565b60608215801561399957604051915060008252602082016040526139e3565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156139d25780518352602092830192016139ba565b5050858452601f01601f1916604052505b50949350505050565b60006117547fce3b5bd42ef5aae9d7b01cd806ce2a8b66f0a48f2e8b5a15f77dfbbdbbf5144f5490565b60606020825110158015613a2c57506040825111155b613a3857613a386153b1565b8151604003613a45575090565b604080516020808252818301909252600091602082018180368337019050509050600060208201528251602003613a8757613a808382614235565b9392505050565b613a8083613aa483600087516040613a9f91906151d9565b6138df565b614235565b50919050565b612bf67e595eca1f8b39945ff4c404827bfa5fd1e295ef3f7d59d120a8ce3bae4e37a0829055565b6000805160206155118339815191528054600090829086908110613afd57613afd615177565b906000526020600020906006020190506000613b1886612f1d565b602081015190915063ffffffff165b85826020015163ffffffff16613b3d91906151c1565b811015613d68576000836003018281548110613b5b57613b5b615177565b906000526020600020018054613b709061518d565b80601f0160208091040260200160405190810160405280929190818152602001828054613b9c9061518d565b8015613be95780601f10613bbe57610100808354040283529160200191613be9565b820191906000526020600020905b815481529060010190602001808311613bcc57829003601f168201915b505050505090506000846004018381548110613c0757613c07615177565b906000526020600020018054613c1c9061518d565b80601f0160208091040260200160405190810160405280929190818152602001828054613c489061518d565b8015613c955780601f10613c6a57610100808354040283529160200191613c95565b820191906000526020600020905b815481529060010190602001808311613c7857829003601f168201915b505050505090506000613ca98360016136fb565b90506000613cb6826142b2565b9050613cc38484836142cb565b6000613cce856137f9565b60008181527f86647fdbbdb534026d3e0f93a551cecf651c2b40fcdfef4b9fd9ed826133e26560205260409081902080546001600160a01b0319166001600160a01b038e1690811790915590519192509033907fac1020908b5f7134d59c1580838eba6fc42dd8c28bae65bf345676bba1913f8e90613d5090899089906153c7565b60405180910390a38560010195505050505050613b27565b506117428686836000015163ffffffff16613d8391906151d9565b87846020015163ffffffff16613d9991906151c1565b6141c1565b612bf67f559ad51499ae00ca2e9d9d95aab46737c8904ab7da276613fefda282b2c2ac06829055565b600080613dd261467c565b905060005b6036811015613e2a578360ff16828260368110613df657613df6615177565b602002015160ff1610613e2257818160368110613e1557613e15615177565b6020020151949350505050565b600101613dd7565b50604051631470905f60e01b815260040160405180910390fd5b60008082856020613e568760026152ad565b613e609190615139565b60208110613e7057613e70615177565b613e7c9291901a6153f5565b9150613e89600184615417565b856020613e978760026152ad565b613ea29060016151c1565b613eac9190615139565b60208110613ebc57613ebc615177565b613ec89291901a6153f5565b613ed390600161543a565b9050935093915050565b60008060001980875b8260010b6000191480613efd57508160010b600019145b15613f81576000613f0e828861483a565b63ffffffff161115613f38578260010b60001903613f31578060000b9250613f38565b8060000b91505b8660ff168860ff168260ff16613f4e91906151c1565b613f589190615139565b90508860ff168160ff16148015613f7357508160010b600019145b15613f7c578291505b613ee6565b509097909650945050505050565b6001818360ff1681518110613fa657613fa6615177565b6020026020010151606001818151613fbe919061545f565b63ffffffff169052505050565b600080613fd88684614972565b63ffffffff1690506000613fec8685614972565b63ffffffff16905080821015614006578692505050614078565b80821115614018578592505050614078565b600060028660206140298a8c61543a565b61403391906153f5565b60ff166020811061404657614046615177565b6140529291901a6153f5565b60ff166001149050801515600015150361407157869350505050614078565b8793505050505b949350505050565b60006117547fd1c64973da70267569571a091966834c1a36bdba47f2a112b6a95bf41fc9c24e5490565b6000611838838330604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b03811661183b5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401611d33565b600081831015613aa957508161183b565b600283901c60009081527f37e2c371bbf1c7a1326d52e30855e9c8b6cac15eda4475320e427b948813a9f060209081526040909120805467ffffffffffffffff60c060069790971b9690961695861b191663ffffffff9490941667ffffffff000000009390921b929092161790921b179055565b6060806040519050835180825260208201818101602087015b8183101561426657805183526020928301920161424e565b50855184518101855292509050808201602086015b8183101561429357805183526020928301920161427b565b508651929092011591909101601f01601f191660405250905092915050565b600061183b6001600160a01b038316600160f81b6151c1565b60006142d6846137f9565b905060006002806142ea86600060406138df565b6040516142f7919061533a565b602060405180830381855afa158015614314573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906143379190615356565b600261435261434d886040613a9f8160606151d9565b613a16565b60405161435f919061533a565b602060405180830381855afa15801561437c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061439f9190615356565b60408051602081019390935282015260600160408051601f19818403018152908290526143cb9161533a565b602060405180830381855afa1580156143e8573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061440b9190615356565b90506000614426633b9aca006801bc16d674ec800000615163565b90506801bc16d674ec80000061444082633b9aca006152ad565b1461444d5761444d6153b1565b6000600280858760405160200161446e929190918252602082015260400190565b60408051601f19818403018152908290526144889161533a565b602060405180830381855afa1580156144a5573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906144c89190615356565b60026144d385614aaa565b604080516020810192909252810187905260600160408051601f19818403018152908290526145019161533a565b602060405180830381855afa15801561451e573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906145419190615356565b60408051602081019390935282015260600160408051601f198184030181529082905261456d9161533a565b602060405180830381855afa15801561458a573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906145ad9190615356565b905060006145c46801bc16d674ec800000476151d9565b90506145ce614af0565b6001600160a01b031663228951186801bc16d674ec8000008a896040516020016145fa91815260200190565b6040516020818303038152906040528b876040518663ffffffff1660e01b815260040161462a9493929190615487565b6000604051808303818588803b15801561464357600080fd5b505af1158015614657573d6000803e3d6000fd5b5050505050804714612f1357604051636596d2b760e01b815260040160405180910390fd5b614684614cac565b50604080516106c081018252600281526003602082015260059181019190915260076060820152600b6080820152600d60a0820152601160c0820152601360e08201526017610100820152601d610120820152601f61014082015260256101608201526029610180820152602b6101a0820152602f6101c082015260356101e0820152603b610200820152603d610220820152604361024082015260476102608201526049610280820152604f6102a082015260536102c082015260596102e0820152606161030082015260656103208201526067610340820152606b610360820152606d61038082015260716103a0820152607f6103c082015260836103e08201526089610400820152608b61042082015260956104408201526097610460820152609d61048082015260a36104a082015260a76104c082015260ad6104e082015260b361050082015260b561052082015260bf61054082015260c161056082015260c561058082015260c76105a082015260d36105c082015260df6105e082015260e361060082015260e561062082015260e961064082015260ef61066082015260f161068082015260fb6106a082015290565b600081518360ff161061484f5750600061183b565b818360ff168151811061486457614864615177565b602002602001015160000151151560001515036149265760006148898460ff16612f1d565b90506001838560ff16815181106148a2576148a2615177565b6020908102919091018101519115159091528101518351849060ff87169081106148ce576148ce615177565b60200260200101516040019063ffffffff16908163ffffffff16815250508060000151838560ff168151811061490657614906615177565b60200260200101516080019063ffffffff16908163ffffffff1681525050505b818360ff168151811061493b5761493b615177565b602002602001015160600151828460ff168151811061495c5761495c615177565b60200260200101516080015161183891906154d2565b600081518360ff16106149875750600061183b565b818360ff168151811061499c5761499c615177565b60200260200101516000015115156000151503614a5e5760006149c18460ff16612f1d565b90506001838560ff16815181106149da576149da615177565b6020908102919091018101519115159091528101518351849060ff8716908110614a0657614a06615177565b60200260200101516040019063ffffffff16908163ffffffff16815250508060000151838560ff1681518110614a3e57614a3e615177565b60200260200101516080019063ffffffff16908163ffffffff1681525050505b818360ff1681518110614a7357614a73615177565b602002602001015160600151828460ff1681518110614a9457614a94615177565b602002602001015160400151611838919061545f565b600081815b6008811015614ad857600892831b60ff831617929190911c90614ad1816154f7565b9050614aaf565b508015614ae757614ae76153b1565b5060c01b919050565b60006117547fbc8b9852d17d50256bb221fdf6ee12d78dd493d807e907f7d223c40d65abd6b95490565b508054614b269061518d565b6000825580601f10614b36575050565b601f016020900490600052602060002090810190612bf69190614ccb565b828054614b609061518d565b90600052602060002090601f016020900481019282614b825760008555614bcf565b82601f10614b935780548555614bcf565b82800160010185558215614bcf57600052602060002091601f016020900482015b82811115614bcf578254825591600101919060010190614bb4565b50614bdb929150614ccb565b5090565b828054828255906000526020600020908101928215614c2c579160200282015b82811115614c2c5782518051614c1c918491602090910190614c38565b5091602001919060010190614bff565b50614bdb929150614ce0565b828054614c449061518d565b90600052602060002090601f016020900481019282614c665760008555614bcf565b82601f10614c7f57805160ff1916838001178555614bcf565b82800160010185558215614bcf579182015b82811115614bcf578251825591602001919060010190614c91565b604051806106c001604052806036906020820280368337509192915050565b5b80821115614bdb5760008155600101614ccc565b80821115614bdb576000614cf48282614b1a565b50600101614ce0565b600060208284031215614d0f57600080fd5b5035919050565b80356001600160a01b0381168114614d2d57600080fd5b919050565b600080600080600080600080610100898b031215614d4f57600080fd5b614d5889614d16565b9750614d6660208a01614d16565b9650614d7460408a01614d16565b9550614d8260608a01614d16565b9450614d9060808a01614d16565b9350614d9e60a08a01614d16565b925060c0890135915060e089013590509295985092959890939650565b60008083601f840112614dcd57600080fd5b50813567ffffffffffffffff811115614de557600080fd5b602083019150836020828501011115614dfd57600080fd5b9250929050565b60008060208385031215614e1757600080fd5b823567ffffffffffffffff811115614e2e57600080fd5b614e3a85828601614dbb565b90969095509350505050565b600080600060408486031215614e5b57600080fd5b83359250602084013567ffffffffffffffff80821115614e7a57600080fd5b818601915086601f830112614e8e57600080fd5b813581811115614e9d57600080fd5b8760208260051b8501011115614eb257600080fd5b6020830194508093505050509250925092565b60008060408385031215614ed857600080fd5b82359150614ee860208401614d16565b90509250929050565b60008060408385031215614f0457600080fd5b50508035926020909101359150565b60005b83811015614f2e578181015183820152602001614f16565b8381111561077a5750506000910152565b60008151808452614f57816020860160208601614f13565b601f01601f19169290920160200192915050565b608081526000614f7e6080830187614f3f565b8281036020840152614f908187614f3f565b6001600160a01b03959095166040840152505090151560609091015292915050565b60008060408385031215614fc557600080fd5b614fce83614d16565b9150614ee860208401614d16565b600060208284031215614fee57600080fd5b81358015158114613a8057600080fd5b60008060006060848603121561501357600080fd5b8335925061502360208501614d16565b915061503160408501614d16565b90509250925092565b6000806000806000806080878903121561505357600080fd5b8635955060208701359450604087013567ffffffffffffffff8082111561507957600080fd5b6150858a838b01614dbb565b9096509450606089013591508082111561509e57600080fd5b506150ab89828a01614dbb565b979a9699509497509295939492505050565b6000806000604084860312156150d257600080fd5b833567ffffffffffffffff8111156150e957600080fd5b6150f586828701614dbb565b9094509250615031905060208501614d16565b60006020828403121561511a57600080fd5b61183882614d16565b634e487b7160e01b600052601260045260246000fd5b60008261514857615148615123565b500690565b634e487b7160e01b600052601160045260246000fd5b60008261517257615172615123565b500490565b634e487b7160e01b600052603260045260246000fd5b600181811c908216806151a157607f821691505b602082108103613aa957634e487b7160e01b600052602260045260246000fd5b600082198211156151d4576151d461514d565b500190565b6000828210156151eb576151eb61514d565b500390565b600060208083526000845481600182811c91508083168061521257607f831692505b858310810361522f57634e487b7160e01b85526022600452602485fd5b87860183815260200181801561524c576001811461525d57615288565b60ff19861682528782019650615288565b60008b81526020902060005b8681101561528257815484820152908501908901615269565b83019750505b50949998505050505050505050565b634e487b7160e01b600052603160045260246000fd5b60008160001904831182151516156152c7576152c761514d565b500290565b6020815260006118386020830184614f3f565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152600061531c6040830186886152df565b828103602084015261532f8185876152df565b979650505050505050565b6000825161534c818460208701614f13565b9190910192915050565b60006020828403121561536857600080fd5b5051919050565b6040815260006153836040830185876152df565b905060018060a01b0383166020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052600160045260246000fd5b6040815260006153da6040830185614f3f565b82810360208401526153ec8185614f3f565b95945050505050565b600060ff83168061540857615408615123565b8060ff84160691505092915050565b600060ff821660ff8416808210156154315761543161514d565b90039392505050565b600060ff821660ff84168060ff038211156154575761545761514d565b019392505050565b600063ffffffff80831681851680830382111561547e5761547e61514d565b01949350505050565b60808152600061549a6080830187614f3f565b82810360208401526154ac8187614f3f565b905082810360408401526154c08186614f3f565b91505082606083015295945050505050565b600063ffffffff838116908316818110156154ef576154ef61514d565b039392505050565b6000600182016155095761550961514d565b506001019056fed2a2f1f08ad325daf72af0169949ae210065d6916750ff03abd83510331b7b39a4dcee8ff224c7cfd53b1f2cd1f5afd98927d079b4152d639c5e523a52bf1e03a26469706673582212200a6c1962014b7476bb5dc5f50997aba537de06cb542d9fc6e6618512dcd0449664736f6c634300080d0033", "devdoc": { "author": "Kiln", "kind": "dev", @@ -934,6 +1143,11 @@ "_publicKey": "Public key to change withdrawer" } }, + "setWithdrawerCustomizationEnabled(bool)": { + "params": { + "_enabled": "True to allow users to customize the withdrawer" + } + }, "transferOwnership(address)": { "details": "Only callable by admin", "params": { @@ -1043,6 +1257,9 @@ "setWithdrawer(bytes,address)": { "notice": "Set withdrawer for public key" }, + "setWithdrawerCustomizationEnabled(bool)": { + "notice": "Changes the behavior of the withdrawer customization logic" + }, "transferOwnership(address)": { "notice": "Set new admin" }, diff --git a/deployments/goerli_live/StakingContract_Proxy.json b/deployments/goerli_live/StakingContract_Proxy.json index 625347c..30e1668 100644 --- a/deployments/goerli_live/StakingContract_Proxy.json +++ b/deployments/goerli_live/StakingContract_Proxy.json @@ -1,5 +1,5 @@ { - "address": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9", + "address": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543", "abi": [ { "inputs": [ @@ -178,52 +178,52 @@ "type": "receive" } ], - "transactionHash": "0x68f55b5e08089000625fef7b009a4f752aaae649c0a380397841227a96c5f718", + "transactionHash": "0x4fe4f74d8e46b177403b71e8119c8d90f598d30b9ec690945d71e44eb5ac96f1", "receipt": { "to": null, - "from": "0x92D7d6DADe15fcF369534cEb8CD1A27f97185ab3", - "contractAddress": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9", - "transactionIndex": 33, + "from": "0xB58ef7246fA10aC1F1de5F36F86ec0328310a0Ca", + "contractAddress": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543", + "transactionIndex": 16, "gasUsed": "890236", - "logsBloom": "0x00000000000000000000000000000000400000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000010000000000000000080400000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x7ef4cd037726387dd9593e2c2745150e96a5a5424b68f1dc96c6a6e2b05ac2d7", - "transactionHash": "0x68f55b5e08089000625fef7b009a4f752aaae649c0a380397841227a96c5f718", + "logsBloom": "0x00000000000000000000000000000000400000080000000000000000000000000000000000000000000000000000000000040040000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000008000000000001000000000000000000000800000000000000000000000000001000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xc7a4c9cc122115baefe04a46acea0372c92e09afb32e3bda3b3810361dd69fef", + "transactionHash": "0x4fe4f74d8e46b177403b71e8119c8d90f598d30b9ec690945d71e44eb5ac96f1", "logs": [ { - "transactionIndex": 33, - "blockNumber": 7476027, - "transactionHash": "0x68f55b5e08089000625fef7b009a4f752aaae649c0a380397841227a96c5f718", - "address": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9", + "transactionIndex": 16, + "blockNumber": 7633620, + "transactionHash": "0x4fe4f74d8e46b177403b71e8119c8d90f598d30b9ec690945d71e44eb5ac96f1", + "address": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543", "topics": [ "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", - "0x000000000000000000000000e8129e75a5324d7c95aa36dd4babf4fed825f5c3" + "0x0000000000000000000000007f14a8048de0c3baae292177aa8b8fe55b32e704" ], "data": "0x", - "logIndex": 99, - "blockHash": "0x7ef4cd037726387dd9593e2c2745150e96a5a5424b68f1dc96c6a6e2b05ac2d7" + "logIndex": 20, + "blockHash": "0xc7a4c9cc122115baefe04a46acea0372c92e09afb32e3bda3b3810361dd69fef" }, { - "transactionIndex": 33, - "blockNumber": 7476027, - "transactionHash": "0x68f55b5e08089000625fef7b009a4f752aaae649c0a380397841227a96c5f718", - "address": "0xFABFf6e6f6ed3e602b2257008eA3ce1EC3539AF9", + "transactionIndex": 16, + "blockNumber": 7633620, + "transactionHash": "0x4fe4f74d8e46b177403b71e8119c8d90f598d30b9ec690945d71e44eb5ac96f1", + "address": "0xe8Ff2a04837aac535199eEcB5ecE52b2735b3543", "topics": [ "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f" ], "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b9b2c07eff60ac828117c997e04c61890ad2ed7", - "logIndex": 100, - "blockHash": "0x7ef4cd037726387dd9593e2c2745150e96a5a5424b68f1dc96c6a6e2b05ac2d7" + "logIndex": 21, + "blockHash": "0xc7a4c9cc122115baefe04a46acea0372c92e09afb32e3bda3b3810361dd69fef" } ], - "blockNumber": 7476027, - "cumulativeGasUsed": "10422347", + "blockNumber": 7633620, + "cumulativeGasUsed": "5292552", "status": 1, "byzantium": true }, "args": [ - "0xe8129e75a5324D7C95Aa36Dd4BaBF4fed825f5c3", + "0x7f14a8048De0c3BaAe292177Aa8b8fe55b32E704", "0x3B9B2C07eff60aC828117C997E04c61890Ad2Ed7", - "0x08b3a073000000000000000000000000c4b8469165d0a0e0939500bdece7c0cd3415a9fb0000000000000000000000005137b5540730d44326fbb237184425a9fb311ddf000000000000000000000000ff50ed3d0ec03ac01d4c79aad74928bff48a7b2b000000000000000000000000800e3f26134488f6d28dda1af6870dbf70790aa30000000000000000000000008daa332f78e9261969cdab643f057608dbe711210000000000000000000000008909bee5b1cb83c42e7ff192e9da34074104a4bb00000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d0" + "0x08b3a073000000000000000000000000c4b8469165d0a0e0939500bdece7c0cd3415a9fb0000000000000000000000005137b5540730d44326fbb237184425a9fb311ddf000000000000000000000000ff50ed3d0ec03ac01d4c79aad74928bff48a7b2b000000000000000000000000639d818639b85a1892bfbb40bd724b4ddea43c0c00000000000000000000000050dba42662fd69f5fd9236540aad9f99f7f6b3b20000000000000000000000001acd717adf8a3a1e4c23c6510cfbe76834e3f1bf00000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d0" ], "numDeployments": 1, "solcInputHash": "8fad9248104c7377e7ee874218595b1c", diff --git a/deployments/goerli_live/solcInputs/721f6bc7fc7142905e230dbfd85db3e8.json b/deployments/goerli_live/solcInputs/721f6bc7fc7142905e230dbfd85db3e8.json deleted file mode 100644 index 0e3bc80..0000000 --- a/deployments/goerli_live/solcInputs/721f6bc7fc7142905e230dbfd85db3e8.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "language": "Solidity", - "sources": { - "src/contracts/ConsensusLayerFeeDispatcher.sol": { - "content": "//SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.8.10;\n\nimport \"./libs/DispatchersStorageLib.sol\";\nimport \"./interfaces/IStakingContractFeeDetails.sol\";\nimport \"./interfaces/IFeeDispatcher.sol\";\n\n/// @title Consensus Layer Fee Recipient\n/// @author Kiln\n/// @notice This contract can be used to receive fees from a validator and split them with a node operator\ncontract ConsensusLayerFeeDispatcher is IFeeDispatcher {\n using DispatchersStorageLib for bytes32;\n\n event Withdrawal(\n address indexed withdrawer,\n address indexed feeRecipient,\n uint256 rewards,\n uint256 nodeOperatorFee,\n uint256 treasuryFee\n );\n\n error TreasuryReceiveError(bytes errorData);\n error FeeRecipientReceiveError(bytes errorData);\n error WithdrawerReceiveError(bytes errorData);\n error ZeroBalanceWithdrawal();\n error AlreadyInitialized();\n error InvalidCall();\n error NotImplemented();\n\n bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =\n keccak256(\"ConsensusLayerFeeRecipient.stakingContractAddress\");\n uint256 internal constant BASIS_POINTS = 10_000;\n bytes32 internal constant VERSION_SLOT = keccak256(\"ConsensusLayerFeeRecipient.version\");\n\n /// @notice Ensures an initialisation call has been called only once per _version value\n /// @param _version The current initialisation value\n modifier init(uint256 _version) {\n if (_version != VERSION_SLOT.getUint256() + 1) {\n revert AlreadyInitialized();\n }\n\n VERSION_SLOT.setUint256(_version);\n\n _;\n }\n\n /// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\n constructor(uint256 _version) {\n VERSION_SLOT.setUint256(_version);\n }\n\n /// @notice Initialize the contract by storing the staking contract\n /// @param _stakingContract Address of the Staking Contract\n function initCLD(address _stakingContract) external init(1) {\n STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);\n }\n\n /// @notice Performs a withdrawal on this contract's balance\n function dispatch(bytes32) external payable {\n revert NotImplemented();\n /*\n uint256 balance = address(this).balance; // this has taken into account msg.value\n if (balance == 0) {\n revert ZeroBalanceWithdrawal();\n }\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\n );\n address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\n address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);\n address treasury = stakingContract.getTreasury();\n uint256 globalFee;\n\n if (balance >= 32 ether) {\n // withdrawing a healthy & exited validator\n globalFee = ((balance - 32 ether) * stakingContract.getGlobalFee()) / BASIS_POINTS;\n } else if (balance <= 16 ether) {\n // withdrawing from what looks like skimming\n globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;\n }\n\n uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;\n\n (bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}(\"\");\n if (status == false) {\n revert WithdrawerReceiveError(data);\n }\n if (globalFee > 0) {\n (status, data) = treasury.call{value: globalFee - operatorFee}(\"\");\n if (status == false) {\n revert FeeRecipientReceiveError(data);\n }\n }\n if (operatorFee > 0) {\n (status, data) = operator.call{value: operatorFee}(\"\");\n if (status == false) {\n revert TreasuryReceiveError(data);\n }\n }\n emit Withdrawal(withdrawer, operator, balance - globalFee, operatorFee, globalFee - operatorFee);\n */\n }\n\n /// @notice Retrieve the staking contract address\n function getStakingContract() external view returns (address) {\n return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();\n }\n\n /// @notice Retrieve the assigned withdrawer for the given public key root\n /// @param _publicKeyRoot Public key root to get the owner\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\n );\n return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\n }\n\n receive() external payable {\n revert InvalidCall();\n }\n\n fallback() external payable {\n revert InvalidCall();\n }\n}\n" - }, - "src/contracts/libs/DispatchersStorageLib.sol": { - "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\nlibrary DispatchersStorageLib {\n function getUint256(bytes32 position) internal view returns (uint256 data) {\n assembly {\n data := sload(position)\n }\n }\n\n function setUint256(bytes32 position, uint256 data) internal {\n assembly {\n sstore(position, data)\n }\n }\n\n function getAddress(bytes32 position) internal view returns (address data) {\n assembly {\n data := sload(position)\n }\n }\n\n function setAddress(bytes32 position, address data) internal {\n assembly {\n sstore(position, data)\n }\n }\n}\n" - }, - "src/contracts/interfaces/IStakingContractFeeDetails.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\ninterface IStakingContractFeeDetails {\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address);\n\n function getTreasury() external view returns (address);\n\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address);\n\n function getGlobalFee() external view returns (uint256);\n\n function getOperatorFee() external view returns (uint256);\n}\n" - }, - "src/contracts/interfaces/IFeeDispatcher.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\ninterface IFeeDispatcher {\n function dispatch(bytes32 _publicKeyRoot) external payable;\n\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address);\n}\n" - }, - "src/contracts/FeeRecipient.sol": { - "content": "//SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.8.10;\n\nimport \"./interfaces/IFeeDispatcher.sol\";\n\ncontract FeeRecipient {\n /// @notice Constructor replay prevention\n bool internal initialized;\n /// @notice Address where funds are sent to be dispatched\n IFeeDispatcher internal dispatcher;\n /// @notice Public Key root assigned to this receiver\n bytes32 internal publicKeyRoot;\n\n error AlreadyInitialized();\n\n /// @notice Initializes the receiver\n /// @param _dispatcher Address that will handle the fee dispatching\n /// @param _publicKeyRoot Public Key root assigned to this receiver\n function init(address _dispatcher, bytes32 _publicKeyRoot) external {\n if (initialized) {\n revert AlreadyInitialized();\n }\n initialized = true;\n dispatcher = IFeeDispatcher(_dispatcher);\n publicKeyRoot = _publicKeyRoot;\n }\n\n /// @notice Empty calldata fallback\n receive() external payable {}\n\n /// @notice Non-empty calldata fallback\n fallback() external payable {}\n\n /// @notice Triggers a withdrawal by sending its funds + its public key root to the dispatcher\n /// @dev Can be called by any wallet as recipients are not parameters\n function withdraw() external {\n dispatcher.dispatch{value: address(this).balance}(publicKeyRoot);\n }\n\n /// @notice Retrieve the assigned public key root\n function getPublicKeyRoot() external view returns (bytes32) {\n return publicKeyRoot;\n }\n\n /// @notice retrieve the assigned withdrawer\n function getWithdrawer() external view returns (address) {\n return dispatcher.getWithdrawer(publicKeyRoot);\n }\n}\n" - }, - "src/contracts/ExecutionLayerFeeDispatcher.sol": { - "content": "//SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.8.10;\n\nimport \"./libs/DispatchersStorageLib.sol\";\nimport \"./interfaces/IStakingContractFeeDetails.sol\";\nimport \"./interfaces/IFeeDispatcher.sol\";\n\n/// @title Execution Layer Fee Recipient\n/// @author Kiln\n/// @notice This contract can be used to receive fees from a validator and split them with a node operator\ncontract ExecutionLayerFeeDispatcher is IFeeDispatcher {\n using DispatchersStorageLib for bytes32;\n\n event Withdrawal(\n address indexed withdrawer,\n address indexed feeRecipient,\n uint256 rewards,\n uint256 nodeOperatorFee,\n uint256 treasuryFee\n );\n\n error TreasuryReceiveError(bytes errorData);\n error FeeRecipientReceiveError(bytes errorData);\n error WithdrawerReceiveError(bytes errorData);\n error ZeroBalanceWithdrawal();\n error AlreadyInitialized();\n error InvalidCall();\n\n bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =\n keccak256(\"ExecutionLayerFeeRecipient.stakingContractAddress\");\n uint256 internal constant BASIS_POINTS = 10_000;\n bytes32 internal constant VERSION_SLOT = keccak256(\"ExecutionLayerFeeRecipient.version\");\n\n /// @notice Ensures an initialisation call has been called only once per _version value\n /// @param _version The current initialisation value\n modifier init(uint256 _version) {\n if (_version != VERSION_SLOT.getUint256() + 1) {\n revert AlreadyInitialized();\n }\n\n VERSION_SLOT.setUint256(_version);\n\n _;\n }\n\n /// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\n constructor(uint256 _version) {\n VERSION_SLOT.setUint256(_version);\n }\n\n /// @notice Initialize the contract by storing the staking contract and the public key in storage\n /// @param _stakingContract Address of the Staking Contract\n function initELD(address _stakingContract) external init(1) {\n STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);\n }\n\n /// @notice Performs a withdrawal on this contract's balance\n function dispatch(bytes32 _publicKeyRoot) external payable {\n uint256 balance = address(this).balance;\n if (balance == 0) {\n revert ZeroBalanceWithdrawal();\n }\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\n );\n address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\n address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);\n address treasury = stakingContract.getTreasury();\n uint256 globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;\n uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;\n\n (bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}(\"\");\n if (status == false) {\n revert WithdrawerReceiveError(data);\n }\n if (globalFee > 0) {\n (status, data) = treasury.call{value: globalFee - operatorFee}(\"\");\n if (status == false) {\n revert FeeRecipientReceiveError(data);\n }\n }\n if (operatorFee > 0) {\n (status, data) = operator.call{value: operatorFee}(\"\");\n if (status == false) {\n revert TreasuryReceiveError(data);\n }\n }\n emit Withdrawal(withdrawer, operator, balance - globalFee, operatorFee, globalFee - operatorFee);\n }\n\n /// @notice Retrieve the staking contract address\n function getStakingContract() external view returns (address) {\n return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();\n }\n\n /// @notice Retrieve the assigned withdrawer for the given public key root\n /// @param _publicKeyRoot Public key root to get the owner\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\n );\n return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\n }\n\n receive() external payable {\n revert InvalidCall();\n }\n\n fallback() external payable {\n revert InvalidCall();\n }\n}\n" - } - }, - "settings": { - "optimizer": { - "enabled": true, - "runs": 200 - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "evm.bytecode", - "evm.deployedBytecode", - "evm.methodIdentifiers", - "metadata", - "devdoc", - "userdoc", - "storageLayout", - "evm.gasEstimates", - "devdoc", - "userdoc" - ], - "": [ - "ast" - ] - } - }, - "metadata": { - "useLiteralContent": true - } - } -} \ No newline at end of file diff --git a/deployments/goerli_live/solcInputs/7c01cac1856570acc6f28ecd3fd2c735.json b/deployments/goerli_live/solcInputs/7c01cac1856570acc6f28ecd3fd2c735.json new file mode 100644 index 0000000..6a0edca --- /dev/null +++ b/deployments/goerli_live/solcInputs/7c01cac1856570acc6f28ecd3fd2c735.json @@ -0,0 +1,52 @@ +{ + "language": "Solidity", + "sources": { + "src/contracts/ConsensusLayerFeeDispatcher.sol": { + "content": "//SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.8.10;\n\nimport \"./libs/DispatchersStorageLib.sol\";\nimport \"./interfaces/IStakingContractFeeDetails.sol\";\nimport \"./interfaces/IFeeDispatcher.sol\";\n\n/// @title Consensus Layer Fee Recipient\n/// @author Kiln\n/// @notice This contract can be used to receive fees from a validator and split them with a node operator\ncontract ConsensusLayerFeeDispatcher is IFeeDispatcher {\n using DispatchersStorageLib for bytes32;\n\n event Withdrawal(\n address indexed withdrawer,\n address indexed feeRecipient,\n bytes32 pubKeyRoot,\n uint256 rewards,\n uint256 nodeOperatorFee,\n uint256 treasuryFee\n );\n\n error TreasuryReceiveError(bytes errorData);\n error FeeRecipientReceiveError(bytes errorData);\n error WithdrawerReceiveError(bytes errorData);\n error ZeroBalanceWithdrawal();\n error AlreadyInitialized();\n error InvalidCall();\n error NotImplemented();\n\n bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =\n keccak256(\"ConsensusLayerFeeRecipient.stakingContractAddress\");\n uint256 internal constant BASIS_POINTS = 10_000;\n bytes32 internal constant VERSION_SLOT = keccak256(\"ConsensusLayerFeeRecipient.version\");\n\n /// @notice Ensures an initialisation call has been called only once per _version value\n /// @param _version The current initialisation value\n modifier init(uint256 _version) {\n if (_version != VERSION_SLOT.getUint256() + 1) {\n revert AlreadyInitialized();\n }\n\n VERSION_SLOT.setUint256(_version);\n\n _;\n }\n\n /// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\n constructor(uint256 _version) {\n VERSION_SLOT.setUint256(_version);\n }\n\n /// @notice Initialize the contract by storing the staking contract\n /// @param _stakingContract Address of the Staking Contract\n function initCLD(address _stakingContract) external init(1) {\n STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);\n }\n\n /// @notice Performs a withdrawal on this contract's balance\n function dispatch(bytes32) external payable {\n revert NotImplemented();\n /*\n uint256 balance = address(this).balance; // this has taken into account msg.value\n if (balance == 0) {\n revert ZeroBalanceWithdrawal();\n }\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\n );\n address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\n address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);\n address treasury = stakingContract.getTreasury();\n uint256 globalFee;\n\n if (balance >= 32 ether) {\n // withdrawing a healthy & exited validator\n globalFee = ((balance - 32 ether) * stakingContract.getGlobalFee()) / BASIS_POINTS;\n } else if (balance <= 16 ether) {\n // withdrawing from what looks like skimming\n globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;\n }\n\n uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;\n\n (bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}(\"\");\n if (status == false) {\n revert WithdrawerReceiveError(data);\n }\n if (globalFee > 0) {\n (status, data) = treasury.call{value: globalFee - operatorFee}(\"\");\n if (status == false) {\n revert FeeRecipientReceiveError(data);\n }\n }\n if (operatorFee > 0) {\n (status, data) = operator.call{value: operatorFee}(\"\");\n if (status == false) {\n revert TreasuryReceiveError(data);\n }\n }\n emit Withdrawal(withdrawer, operator, balance - globalFee, operatorFee, globalFee - operatorFee);\n */\n }\n\n /// @notice Retrieve the staking contract address\n function getStakingContract() external view returns (address) {\n return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();\n }\n\n /// @notice Retrieve the assigned withdrawer for the given public key root\n /// @param _publicKeyRoot Public key root to get the owner\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\n );\n return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\n }\n\n receive() external payable {\n revert InvalidCall();\n }\n\n fallback() external payable {\n revert InvalidCall();\n }\n}\n" + }, + "src/contracts/libs/DispatchersStorageLib.sol": { + "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\nlibrary DispatchersStorageLib {\n function getUint256(bytes32 position) internal view returns (uint256 data) {\n assembly {\n data := sload(position)\n }\n }\n\n function setUint256(bytes32 position, uint256 data) internal {\n assembly {\n sstore(position, data)\n }\n }\n\n function getAddress(bytes32 position) internal view returns (address data) {\n assembly {\n data := sload(position)\n }\n }\n\n function setAddress(bytes32 position, address data) internal {\n assembly {\n sstore(position, data)\n }\n }\n}\n" + }, + "src/contracts/interfaces/IStakingContractFeeDetails.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\ninterface IStakingContractFeeDetails {\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address);\n\n function getTreasury() external view returns (address);\n\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address);\n\n function getGlobalFee() external view returns (uint256);\n\n function getOperatorFee() external view returns (uint256);\n}\n" + }, + "src/contracts/interfaces/IFeeDispatcher.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\ninterface IFeeDispatcher {\n function dispatch(bytes32 _publicKeyRoot) external payable;\n\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address);\n}\n" + }, + "src/contracts/FeeRecipient.sol": { + "content": "//SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.8.10;\n\nimport \"./interfaces/IFeeDispatcher.sol\";\n\ncontract FeeRecipient {\n /// @notice Constructor replay prevention\n bool internal initialized;\n /// @notice Address where funds are sent to be dispatched\n IFeeDispatcher internal dispatcher;\n /// @notice Public Key root assigned to this receiver\n bytes32 internal publicKeyRoot;\n\n error AlreadyInitialized();\n\n /// @notice Initializes the receiver\n /// @param _dispatcher Address that will handle the fee dispatching\n /// @param _publicKeyRoot Public Key root assigned to this receiver\n function init(address _dispatcher, bytes32 _publicKeyRoot) external {\n if (initialized) {\n revert AlreadyInitialized();\n }\n initialized = true;\n dispatcher = IFeeDispatcher(_dispatcher);\n publicKeyRoot = _publicKeyRoot;\n }\n\n /// @notice Empty calldata fallback\n receive() external payable {}\n\n /// @notice Non-empty calldata fallback\n fallback() external payable {}\n\n /// @notice Triggers a withdrawal by sending its funds + its public key root to the dispatcher\n /// @dev Can be called by any wallet as recipients are not parameters\n function withdraw() external {\n dispatcher.dispatch{value: address(this).balance}(publicKeyRoot);\n }\n\n /// @notice Retrieve the assigned public key root\n function getPublicKeyRoot() external view returns (bytes32) {\n return publicKeyRoot;\n }\n\n /// @notice retrieve the assigned withdrawer\n function getWithdrawer() external view returns (address) {\n return dispatcher.getWithdrawer(publicKeyRoot);\n }\n}\n" + }, + "src/contracts/ExecutionLayerFeeDispatcher.sol": { + "content": "//SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.8.10;\n\nimport \"./libs/DispatchersStorageLib.sol\";\nimport \"./interfaces/IStakingContractFeeDetails.sol\";\nimport \"./interfaces/IFeeDispatcher.sol\";\n\n/// @title Execution Layer Fee Recipient\n/// @author Kiln\n/// @notice This contract can be used to receive fees from a validator and split them with a node operator\ncontract ExecutionLayerFeeDispatcher is IFeeDispatcher {\n using DispatchersStorageLib for bytes32;\n\n event Withdrawal(\n address indexed withdrawer,\n address indexed feeRecipient,\n bytes32 pubKeyRoot,\n uint256 rewards,\n uint256 nodeOperatorFee,\n uint256 treasuryFee\n );\n\n error TreasuryReceiveError(bytes errorData);\n error FeeRecipientReceiveError(bytes errorData);\n error WithdrawerReceiveError(bytes errorData);\n error ZeroBalanceWithdrawal();\n error AlreadyInitialized();\n error InvalidCall();\n\n bytes32 internal constant STAKING_CONTRACT_ADDRESS_SLOT =\n keccak256(\"ExecutionLayerFeeRecipient.stakingContractAddress\");\n uint256 internal constant BASIS_POINTS = 10_000;\n bytes32 internal constant VERSION_SLOT = keccak256(\"ExecutionLayerFeeRecipient.version\");\n\n /// @notice Ensures an initialisation call has been called only once per _version value\n /// @param _version The current initialisation value\n modifier init(uint256 _version) {\n if (_version != VERSION_SLOT.getUint256() + 1) {\n revert AlreadyInitialized();\n }\n\n VERSION_SLOT.setUint256(_version);\n\n _;\n }\n\n /// @notice Constructor method allowing us to prevent calls to initCLFR by setting the appropriate version\n constructor(uint256 _version) {\n VERSION_SLOT.setUint256(_version);\n }\n\n /// @notice Initialize the contract by storing the staking contract and the public key in storage\n /// @param _stakingContract Address of the Staking Contract\n function initELD(address _stakingContract) external init(1) {\n STAKING_CONTRACT_ADDRESS_SLOT.setAddress(_stakingContract);\n }\n\n /// @notice Performs a withdrawal on this contract's balance\n function dispatch(bytes32 _publicKeyRoot) external payable {\n uint256 balance = address(this).balance;\n if (balance == 0) {\n revert ZeroBalanceWithdrawal();\n }\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\n );\n address withdrawer = stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\n address operator = stakingContract.getOperatorFeeRecipient(_publicKeyRoot);\n address treasury = stakingContract.getTreasury();\n uint256 globalFee = (balance * stakingContract.getGlobalFee()) / BASIS_POINTS;\n uint256 operatorFee = (globalFee * stakingContract.getOperatorFee()) / BASIS_POINTS;\n\n (bool status, bytes memory data) = withdrawer.call{value: balance - globalFee}(\"\");\n if (status == false) {\n revert WithdrawerReceiveError(data);\n }\n if (globalFee > 0) {\n (status, data) = treasury.call{value: globalFee - operatorFee}(\"\");\n if (status == false) {\n revert FeeRecipientReceiveError(data);\n }\n }\n if (operatorFee > 0) {\n (status, data) = operator.call{value: operatorFee}(\"\");\n if (status == false) {\n revert TreasuryReceiveError(data);\n }\n }\n emit Withdrawal(\n withdrawer,\n operator,\n _publicKeyRoot,\n balance - globalFee,\n operatorFee,\n globalFee - operatorFee\n );\n }\n\n /// @notice Retrieve the staking contract address\n function getStakingContract() external view returns (address) {\n return STAKING_CONTRACT_ADDRESS_SLOT.getAddress();\n }\n\n /// @notice Retrieve the assigned withdrawer for the given public key root\n /// @param _publicKeyRoot Public key root to get the owner\n function getWithdrawer(bytes32 _publicKeyRoot) external view returns (address) {\n IStakingContractFeeDetails stakingContract = IStakingContractFeeDetails(\n STAKING_CONTRACT_ADDRESS_SLOT.getAddress()\n );\n return stakingContract.getWithdrawerFromPublicKeyRoot(_publicKeyRoot);\n }\n\n receive() external payable {\n revert InvalidCall();\n }\n\n fallback() external payable {\n revert InvalidCall();\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates", + "devdoc", + "userdoc" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/goerli_live/solcInputs/9b429e318c7698f5c83d9f1f7ab2fb85.json b/deployments/goerli_live/solcInputs/9b429e318c7698f5c83d9f1f7ab2fb85.json deleted file mode 100644 index a1a34d8..0000000 --- a/deployments/goerli_live/solcInputs/9b429e318c7698f5c83d9f1f7ab2fb85.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "language": "Solidity", - "sources": { - "src/contracts/interfaces/IDepositContract.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\ninterface IDepositContract {\n function deposit(\n bytes calldata pubkey,\n bytes calldata withdrawalCredentials,\n bytes calldata signature,\n bytes32 depositDataRoot\n ) external payable;\n}\n" - }, - "src/contracts/StakingContract.sol": { - "content": "//SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.8.10;\n\nimport \"./libs/UintLib.sol\";\nimport \"./libs/BytesLib.sol\";\nimport \"./interfaces/IFeeRecipient.sol\";\nimport \"./interfaces/IDepositContract.sol\";\nimport \"./libs/StakingContractStorageLib.sol\";\nimport \"@openzeppelin/contracts/proxy/Clones.sol\";\n\n/// @title Ethereum Staking Contract\n/// @author Kiln\n/// @notice You can use this contract to store validator keys and have users fund them and trigger deposits.\ncontract StakingContract {\n using StakingContractStorageLib for bytes32;\n\n uint256 internal constant EXECUTION_LAYER_SALT_PREFIX = 0;\n uint256 internal constant CONSENSUS_LAYER_SALT_PREFIX = 1;\n uint256 public constant SIGNATURE_LENGTH = 96;\n uint256 public constant PUBLIC_KEY_LENGTH = 48;\n uint256 public constant DEPOSIT_SIZE = 32 ether;\n uint256 internal constant BASIS_POINTS = 10_000;\n\n error Deactivated();\n error NoOperators();\n error InvalidCall();\n error Unauthorized();\n error InvalidFee();\n error DepositFailure();\n error InvalidArgument();\n error UnsortedIndexes();\n error InvalidPublicKeys();\n error InvalidSignatures();\n error AlreadyInitialized();\n error InvalidDepositValue();\n error NotEnoughValidators();\n error InvalidValidatorCount();\n error DuplicateValidatorKey(bytes);\n error FundedValidatorDeletionAttempt();\n error OperatorLimitTooHigh(uint256 limit, uint256 keyCount);\n error MaximumOperatorCountAlreadyReached();\n\n struct ValidatorAllocationCache {\n bool used;\n uint8 operatorIndex;\n uint32 funded;\n uint32 toDeposit;\n uint32 available;\n }\n\n event Deposit(address indexed caller, address indexed withdrawer, bytes publicKey);\n event ValidatorKeysAdded(uint256 indexed operatorIndex, bytes publicKeys);\n event ValidatorKeyRemoved(uint256 indexed operatorIndex, bytes publicKey);\n\n /// @notice Ensures an initialisation call has been called only once per _version value\n /// @param _version The current initialisation value\n modifier init(uint256 _version) {\n if (_version != StakingContractStorageLib.getVersion() + 1) {\n revert AlreadyInitialized();\n }\n\n StakingContractStorageLib.setVersion(_version);\n _;\n }\n\n /// @notice Ensures that the caller is the admin\n modifier onlyAdmin() {\n if (msg.sender != StakingContractStorageLib.getAdmin()) {\n revert Unauthorized();\n }\n\n _;\n }\n\n /// @notice Ensures that the caller is the admin or the operator\n modifier onlyActiveOperatorOrAdmin(uint256 _operatorIndex) {\n if (msg.sender == StakingContractStorageLib.getAdmin()) {\n _;\n } else {\n _onlyActiveOperator(_operatorIndex);\n _;\n }\n }\n\n /// @notice Ensures that the caller is the admin\n modifier onlyActiveOperator(uint256 _operatorIndex) {\n _onlyActiveOperator(_operatorIndex);\n _;\n }\n\n /// @notice Ensures that the caller is the operator fee recipient\n modifier onlyOperatorFeeRecipient(uint256 _operatorIndex) {\n StakingContractStorageLib.OperatorInfo memory operatorInfo = StakingContractStorageLib.getOperators().value[\n _operatorIndex\n ];\n\n if (operatorInfo.deactivated) {\n revert Deactivated();\n }\n\n if (msg.sender != operatorInfo.feeRecipient) {\n revert Unauthorized();\n }\n\n _;\n }\n\n /// @notice Explicit deposit method using msg.sender\n /// @dev A multiple of 32 ETH should be sent\n function deposit() external payable {\n _deposit(msg.sender);\n }\n\n /// @notice Implicit deposit method\n /// @dev A multiple of 32 ETH should be sent\n /// @dev The withdrawer is set to the message sender address\n receive() external payable {\n _deposit(msg.sender);\n }\n\n /// @notice Fallback detection\n /// @dev Fails on any call that fallbacks\n fallback() external payable {\n revert InvalidCall();\n }\n\n function initialize_1(\n address _admin,\n address _treasury,\n address _depositContract,\n address _elDispatcher,\n address _clDispatcher,\n address _feeRecipientImplementation,\n uint256 _globalFee,\n uint256 _operatorFee\n ) external init(1) {\n StakingContractStorageLib.setAdmin(_admin);\n StakingContractStorageLib.setTreasury(_treasury);\n\n if (_globalFee > BASIS_POINTS) {\n revert InvalidFee();\n }\n StakingContractStorageLib.setGlobalFee(_globalFee);\n if (_operatorFee > BASIS_POINTS) {\n revert InvalidFee();\n }\n StakingContractStorageLib.setOperatorFee(_operatorFee);\n\n StakingContractStorageLib.setELDispatcher(_elDispatcher);\n StakingContractStorageLib.setCLDispatcher(_clDispatcher);\n StakingContractStorageLib.setDepositContract(_depositContract);\n StakingContractStorageLib.setFeeRecipientImplementation(_feeRecipientImplementation);\n }\n\n /// @notice Retrieve system admin\n function getAdmin() external view returns (address) {\n return StakingContractStorageLib.getAdmin();\n }\n\n /// @notice Set new treasury\n /// @dev Only callable by admin\n /// @param _newTreasury New Treasury address\n function setTreasury(address _newTreasury) external onlyAdmin {\n return StakingContractStorageLib.setTreasury(_newTreasury);\n }\n\n /// @notice Retrieve system treasury\n function getTreasury() external view returns (address) {\n return StakingContractStorageLib.getTreasury();\n }\n\n /// @notice Retrieve the global fee\n function getGlobalFee() external view returns (uint256) {\n return StakingContractStorageLib.getGlobalFee();\n }\n\n /// @notice Retrieve the operator fee\n function getOperatorFee() external view returns (uint256) {\n return StakingContractStorageLib.getOperatorFee();\n }\n\n /// @notice Compute the Execution Layer Fee recipient address for a given validator public key\n /// @param _publicKey Validator to get the recipient\n function getELFeeRecipient(bytes calldata _publicKey) external view returns (address) {\n return _getDeterministicReceiver(_publicKey, EXECUTION_LAYER_SALT_PREFIX);\n }\n\n /// @notice Compute the Consensus Layer Fee recipient address for a given validator public key\n /// @param _publicKey Validator to get the recipient\n function getCLFeeRecipient(bytes calldata _publicKey) external view returns (address) {\n return _getDeterministicReceiver(_publicKey, CONSENSUS_LAYER_SALT_PREFIX);\n }\n\n /// @notice Retrieve the Execution & Consensus Layer Fee operator recipient for a given public key\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address) {\n return\n StakingContractStorageLib\n .getOperators()\n .value[StakingContractStorageLib.getOperatorIndexPerValidator().value[pubKeyRoot].operatorIndex]\n .feeRecipient;\n }\n\n /// @notice Retrieve withdrawer of public key\n /// @param _publicKey Public Key to check\n function getWithdrawer(bytes calldata _publicKey) external view returns (address) {\n return _getWithdrawer(_getPubKeyRoot(_publicKey));\n }\n\n /// @notice Retrieve withdrawer of public key root\n /// @param _publicKeyRoot Hash of the public key\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address) {\n return _getWithdrawer(_publicKeyRoot);\n }\n\n /// @notice Retrieve operator details\n /// @param _operatorIndex Operator index\n function getOperator(uint256 _operatorIndex)\n external\n view\n returns (\n address operatorAddress,\n address feeRecipientAddress,\n uint256 limit,\n uint256 keys,\n uint256 funded,\n uint256 available,\n bool deactivated\n )\n {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n if (_operatorIndex < operators.value.length) {\n StakingContractStorageLib.ValidatorsFundingInfo memory _operatorInfo = StakingContractStorageLib\n .getValidatorsFundingInfo(_operatorIndex);\n StakingContractStorageLib.OperatorInfo memory _operator = operators.value[_operatorIndex];\n\n (operatorAddress, feeRecipientAddress, limit, keys, deactivated) = (\n _operator.operator,\n _operator.feeRecipient,\n _operator.limit,\n _operator.publicKeys.length,\n _operator.deactivated\n );\n (funded, available) = (_operatorInfo.funded, _operatorInfo.availableKeys);\n }\n }\n\n /// @notice Get details about a validator\n /// @param _operatorIndex Index of the operator running the validator\n /// @param _validatorIndex Index of the validator\n function getValidator(uint256 _operatorIndex, uint256 _validatorIndex)\n external\n view\n returns (\n bytes memory publicKey,\n bytes memory signature,\n address withdrawer,\n bool funded\n )\n {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n publicKey = operators.value[_operatorIndex].publicKeys[_validatorIndex];\n signature = operators.value[_operatorIndex].signatures[_validatorIndex];\n withdrawer = _getWithdrawer(_getPubKeyRoot(publicKey));\n funded = _validatorIndex < StakingContractStorageLib.getValidatorsFundingInfo(_operatorIndex).funded;\n }\n\n /// @notice Get the total available keys that are ready to be used for deposits\n function getAvailableValidatorCount() external view returns (uint256) {\n return StakingContractStorageLib.getTotalAvailableValidators();\n }\n\n /// @notice Set new admin\n /// @dev Only callable by admin\n /// @param _newAdmin New Administrator address\n function transferOwnership(address _newAdmin) external onlyAdmin {\n StakingContractStorageLib.setPendingAdmin(_newAdmin);\n }\n\n /// @notice New admin must accept its role by calling this method\n /// @dev Only callable by new admin\n function acceptOwnership() external {\n address newAdmin = StakingContractStorageLib.getPendingAdmin();\n\n if (msg.sender != newAdmin) {\n revert Unauthorized();\n }\n StakingContractStorageLib.setAdmin(newAdmin);\n }\n\n /// @notice Get the new admin's address previously set for an ownership transfer\n function getPendingAdmin() external view returns (address) {\n return StakingContractStorageLib.getPendingAdmin();\n }\n\n /// @notice Add new operator\n /// @dev Only callable by admin\n /// @param _operatorAddress Operator address allowed to add / remove validators\n /// @param _feeRecipientAddress Operator address used to manage rewards\n function addOperator(address _operatorAddress, address _feeRecipientAddress) external onlyAdmin returns (uint256) {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n StakingContractStorageLib.OperatorInfo memory newOperator;\n\n if (operators.value.length == 251) {\n revert MaximumOperatorCountAlreadyReached();\n }\n newOperator.operator = _operatorAddress;\n newOperator.feeRecipient = _feeRecipientAddress;\n operators.value.push(newOperator);\n return operators.value.length - 1;\n }\n\n /// @notice Set new operator addresses (operations and reward management)\n /// @dev Only callable by fee recipient address manager\n /// @param _operatorIndex Index of the operator to update\n /// @param _operatorAddress New operator address for operations management\n /// @param _feeRecipientAddress New operator address for reward management\n function setOperatorAddresses(\n uint256 _operatorIndex,\n address _operatorAddress,\n address _feeRecipientAddress\n ) external onlyOperatorFeeRecipient(_operatorIndex) {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n\n operators.value[_operatorIndex].operator = _operatorAddress;\n operators.value[_operatorIndex].feeRecipient = _feeRecipientAddress;\n }\n\n /// @notice Set withdrawer for public key\n /// @dev Only callable by current public key withdrawer\n /// @param _publicKey Public key to change withdrawer\n /// @param _newWithdrawer New withdrawer address\n function setWithdrawer(bytes calldata _publicKey, address _newWithdrawer) external {\n bytes32 pubkeyRoot = sha256(BytesLib.pad64(_publicKey));\n StakingContractStorageLib.WithdrawersSlot storage withdrawers = StakingContractStorageLib.getWithdrawers();\n\n if (withdrawers.value[pubkeyRoot] != msg.sender) {\n revert Unauthorized();\n }\n\n withdrawers.value[pubkeyRoot] = _newWithdrawer;\n }\n\n /// @notice Set operator staking limits\n /// @dev Only callable by admin\n /// @dev Limit should not exceed the validator key count of the operator\n /// @dev Keys should be registered before limit is increased\n /// @dev Allows all keys to be verified by the system admin before limit is increased\n /// @param _operatorIndex Operator Index\n /// @param _limit New staking limit\n function setOperatorLimit(uint256 _operatorIndex, uint256 _limit) external onlyAdmin {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n if (operators.value[_operatorIndex].deactivated) {\n revert Deactivated();\n }\n uint256 publicKeyCount = operators.value[_operatorIndex].publicKeys.length;\n if (publicKeyCount < _limit) {\n revert OperatorLimitTooHigh(_limit, publicKeyCount);\n }\n operators.value[_operatorIndex].limit = _limit;\n _updateAvailableValidatorCount(_operatorIndex);\n }\n\n /// @notice Deactivates an operator and changes the fee recipient address and the staking limit\n /// @param _operatorIndex Operator Index\n /// @param _temporaryFeeRecipient Temporary address to receive funds decided by the system admin\n function deactivateOperator(uint256 _operatorIndex, address _temporaryFeeRecipient) external onlyAdmin {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n operators.value[_operatorIndex].limit = 0;\n operators.value[_operatorIndex].deactivated = true;\n operators.value[_operatorIndex].feeRecipient = _temporaryFeeRecipient;\n _updateAvailableValidatorCount(_operatorIndex);\n }\n\n /// @notice Activates an operator, without changing its 0 staking limit\n /// @param _operatorIndex Operator Index\n /// @param _newFeeRecipient Sets the fee recipient address\n function activateOperator(uint256 _operatorIndex, address _newFeeRecipient) external onlyAdmin {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n operators.value[_operatorIndex].deactivated = false;\n operators.value[_operatorIndex].feeRecipient = _newFeeRecipient;\n }\n\n /// @notice Change the Operator fee\n /// @param _operatorFee Fee in Basis Point\n function setOperatorFee(uint256 _operatorFee) external onlyAdmin {\n if (_operatorFee > BASIS_POINTS) {\n revert InvalidFee();\n }\n StakingContractStorageLib.setOperatorFee(_operatorFee);\n }\n\n /// @notice Change the Global fee\n /// @param _globalFee Fee in Basis Point\n function setGlobalFee(uint256 _globalFee) external onlyAdmin {\n if (_globalFee > BASIS_POINTS) {\n revert InvalidFee();\n }\n StakingContractStorageLib.setGlobalFee(_globalFee);\n }\n\n /// @notice Add new validator public keys and signatures\n /// @dev Only callable by operator\n /// @param _operatorIndex Operator Index\n /// @param _keyCount Number of keys added\n /// @param _publicKeys Concatenated _keyCount public keys\n /// @param _signatures Concatenated _keyCount signatures\n function addValidators(\n uint256 _operatorIndex,\n uint256 _keyCount,\n bytes calldata _publicKeys,\n bytes calldata _signatures\n ) external onlyActiveOperator(_operatorIndex) {\n if (_keyCount == 0) {\n revert InvalidArgument();\n }\n\n if (_publicKeys.length % PUBLIC_KEY_LENGTH != 0 || _publicKeys.length / PUBLIC_KEY_LENGTH != _keyCount) {\n revert InvalidPublicKeys();\n }\n\n if (_signatures.length % SIGNATURE_LENGTH != 0 || _signatures.length / SIGNATURE_LENGTH != _keyCount) {\n revert InvalidSignatures();\n }\n\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n StakingContractStorageLib.OperatorIndexPerValidatorSlot\n storage operatorIndexPerValidator = StakingContractStorageLib.getOperatorIndexPerValidator();\n\n for (uint256 i; i < _keyCount; ) {\n bytes memory publicKey = BytesLib.slice(_publicKeys, i * PUBLIC_KEY_LENGTH, PUBLIC_KEY_LENGTH);\n bytes memory signature = BytesLib.slice(_signatures, i * SIGNATURE_LENGTH, SIGNATURE_LENGTH);\n\n operators.value[_operatorIndex].publicKeys.push(publicKey);\n operators.value[_operatorIndex].signatures.push(signature);\n\n bytes32 pubKeyRoot = _getPubKeyRoot(publicKey);\n\n if (operatorIndexPerValidator.value[pubKeyRoot].enabled) {\n revert DuplicateValidatorKey(publicKey);\n }\n\n operatorIndexPerValidator.value[pubKeyRoot] = StakingContractStorageLib.OperatorIndex({\n enabled: true,\n operatorIndex: uint32(_operatorIndex)\n });\n\n unchecked {\n ++i;\n }\n }\n\n emit ValidatorKeysAdded(_operatorIndex, _publicKeys);\n\n _updateAvailableValidatorCount(_operatorIndex);\n }\n\n /// @notice Remove unfunded validators\n /// @dev Only callable by operator\n /// @dev Indexes should be provided in decreasing order\n /// @dev The limit will be set to the lowest removed operator index to ensure all changes above the\n /// lowest removed validator key are verified by the system administrator\n /// @param _operatorIndex Operator Index\n /// @param _indexes List of indexes to delete, in decreasing order\n function removeValidators(uint256 _operatorIndex, uint256[] calldata _indexes)\n external\n onlyActiveOperatorOrAdmin(_operatorIndex)\n {\n if (_indexes.length == 0) {\n revert InvalidArgument();\n }\n\n StakingContractStorageLib.ValidatorsFundingInfo memory operatorInfo = StakingContractStorageLib\n .getValidatorsFundingInfo(_operatorIndex);\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n\n if (_indexes[_indexes.length - 1] < operatorInfo.funded) {\n revert FundedValidatorDeletionAttempt();\n }\n for (uint256 i; i < _indexes.length; ) {\n if (i > 0 && _indexes[i] >= _indexes[i - 1]) {\n revert UnsortedIndexes();\n }\n\n emit ValidatorKeyRemoved(_operatorIndex, operators.value[_operatorIndex].publicKeys[_indexes[i]]);\n if (_indexes[i] == operators.value[_operatorIndex].publicKeys.length - 1) {\n operators.value[_operatorIndex].publicKeys.pop();\n operators.value[_operatorIndex].signatures.pop();\n } else {\n operators.value[_operatorIndex].publicKeys[_indexes[i]] = operators.value[_operatorIndex].publicKeys[\n operators.value[_operatorIndex].publicKeys.length - 1\n ];\n operators.value[_operatorIndex].publicKeys.pop();\n operators.value[_operatorIndex].signatures[_indexes[i]] = operators.value[_operatorIndex].signatures[\n operators.value[_operatorIndex].signatures.length - 1\n ];\n operators.value[_operatorIndex].signatures.pop();\n }\n\n unchecked {\n ++i;\n }\n }\n\n if (_indexes[_indexes.length - 1] < operators.value[_operatorIndex].limit) {\n operators.value[_operatorIndex].limit = _indexes[_indexes.length - 1];\n }\n\n _updateAvailableValidatorCount(_operatorIndex);\n }\n\n /// @notice Withdraw the Execution Layer Fee for a given validator public key\n /// @dev Funds are sent to the withdrawer account\n /// @dev This method is public on purpose\n /// @param _publicKey Validator to withdraw Execution Layer Fees from\n function withdrawELFee(bytes calldata _publicKey) external {\n _deployAndWithdraw(_publicKey, EXECUTION_LAYER_SALT_PREFIX, StakingContractStorageLib.getELDispatcher());\n }\n\n /// @notice Withdraw the Consensus Layer Fee for a given validator public key\n /// @dev Funds are sent to the withdrawer account\n /// @dev This method is public on purpose\n /// @param _publicKey Validator to withdraw Consensus Layer Fees from\n function withdrawCLFee(bytes calldata _publicKey) external {\n _deployAndWithdraw(_publicKey, CONSENSUS_LAYER_SALT_PREFIX, StakingContractStorageLib.getCLDispatcher());\n }\n\n /// @notice Withdraw both Consensus and Execution Layer Fee for a given validator public key\n /// @dev Reverts if any is null\n /// @param _publicKey Validator to withdraw Execution and Consensus Layer Fees from\n function withdraw(bytes calldata _publicKey) external {\n _deployAndWithdraw(_publicKey, EXECUTION_LAYER_SALT_PREFIX, StakingContractStorageLib.getELDispatcher());\n _deployAndWithdraw(_publicKey, CONSENSUS_LAYER_SALT_PREFIX, StakingContractStorageLib.getCLDispatcher());\n }\n\n /// ██ ███ ██ ████████ ███████ ██████ ███ ██ █████ ██\n /// ██ ████ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██\n /// ██ ██ ██ ██ ██ █████ ██████ ██ ██ ██ ███████ ██\n /// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██\n /// ██ ██ ████ ██ ███████ ██ ██ ██ ████ ██ ██ ███████\n\n function _onlyActiveOperator(uint256 _operatorIndex) internal view {\n StakingContractStorageLib.OperatorInfo memory operatorInfo = StakingContractStorageLib.getOperators().value[\n _operatorIndex\n ];\n\n if (operatorInfo.deactivated) {\n revert Deactivated();\n }\n\n if (msg.sender != operatorInfo.operator) {\n revert Unauthorized();\n }\n }\n\n function _getPubKeyRoot(bytes memory _publicKey) internal pure returns (bytes32) {\n return sha256(BytesLib.pad64(_publicKey));\n }\n\n function _getWithdrawer(bytes32 _publicKeyRoot) internal view returns (address) {\n return StakingContractStorageLib.getWithdrawers().value[_publicKeyRoot];\n }\n\n function _updateAvailableValidatorCount(uint256 _operatorIndex) internal {\n StakingContractStorageLib.ValidatorsFundingInfo memory validatorFundingInfo = StakingContractStorageLib\n .getValidatorsFundingInfo(_operatorIndex);\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n\n uint32 oldAvailableCount = validatorFundingInfo.availableKeys;\n uint32 newAvailableCount = 0;\n uint256 cap = _min(operators.value[_operatorIndex].limit, operators.value[_operatorIndex].publicKeys.length);\n\n if (cap <= validatorFundingInfo.funded) {\n StakingContractStorageLib.setValidatorsFundingInfo(_operatorIndex, 0, validatorFundingInfo.funded);\n } else {\n newAvailableCount = uint32(cap - validatorFundingInfo.funded);\n StakingContractStorageLib.setValidatorsFundingInfo(\n _operatorIndex,\n newAvailableCount,\n validatorFundingInfo.funded\n );\n }\n\n if (oldAvailableCount != newAvailableCount) {\n StakingContractStorageLib.setTotalAvailableValidators(\n (StakingContractStorageLib.getTotalAvailableValidators() - oldAvailableCount) + newAvailableCount\n );\n }\n }\n\n function _addressToWithdrawalCredentials(address _recipient) internal pure returns (bytes32) {\n return\n bytes32(uint256(uint160(_recipient)) + 0x0100000000000000000000000000000000000000000000000000000000000000);\n }\n\n function _depositValidatorsOfOperator(\n uint256 _operatorIndex,\n uint256 _validatorCount,\n address _withdrawer\n ) internal {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n StakingContractStorageLib.OperatorInfo storage operator = operators.value[_operatorIndex];\n StakingContractStorageLib.ValidatorsFundingInfo memory vfi = StakingContractStorageLib.getValidatorsFundingInfo(\n _operatorIndex\n );\n\n for (uint256 i = vfi.funded; i < vfi.funded + _validatorCount; ) {\n bytes memory publicKey = operator.publicKeys[i];\n bytes memory signature = operator.signatures[i];\n address consensusLayerRecipient = _getDeterministicReceiver(publicKey, CONSENSUS_LAYER_SALT_PREFIX);\n bytes32 withdrawalCredentials = _addressToWithdrawalCredentials(consensusLayerRecipient);\n _depositValidator(publicKey, signature, withdrawalCredentials);\n bytes32 pubkeyRoot = _getPubKeyRoot(publicKey);\n StakingContractStorageLib.getWithdrawers().value[pubkeyRoot] = _withdrawer;\n emit Deposit(msg.sender, _withdrawer, publicKey);\n unchecked {\n ++i;\n }\n }\n\n StakingContractStorageLib.setValidatorsFundingInfo(\n _operatorIndex,\n uint32(vfi.availableKeys - _validatorCount),\n uint32(vfi.funded + _validatorCount)\n );\n }\n\n /// @notice Internal utility to deposit a public key, its signature and 32 ETH to the consensus layer\n /// @param _publicKey The Public Key to deposit\n /// @param _signature The Signature to deposit\n /// @param _withdrawalCredentials The Withdrawal Credentials to deposit\n function _depositValidator(\n bytes memory _publicKey,\n bytes memory _signature,\n bytes32 _withdrawalCredentials\n ) internal {\n bytes32 pubkeyRoot = _getPubKeyRoot(_publicKey);\n bytes32 signatureRoot = sha256(\n abi.encodePacked(\n sha256(BytesLib.slice(_signature, 0, 64)),\n sha256(BytesLib.pad64(BytesLib.slice(_signature, 64, SIGNATURE_LENGTH - 64)))\n )\n );\n\n uint256 depositAmount = DEPOSIT_SIZE / 1000000000 wei;\n assert(depositAmount * 1000000000 wei == DEPOSIT_SIZE);\n\n bytes32 depositDataRoot = sha256(\n abi.encodePacked(\n sha256(abi.encodePacked(pubkeyRoot, _withdrawalCredentials)),\n sha256(abi.encodePacked(Uint256Lib.toLittleEndian64(depositAmount), signatureRoot))\n )\n );\n\n uint256 targetBalance = address(this).balance - DEPOSIT_SIZE;\n\n IDepositContract(StakingContractStorageLib.getDepositContract()).deposit{value: DEPOSIT_SIZE}(\n _publicKey,\n abi.encodePacked(_withdrawalCredentials),\n _signature,\n depositDataRoot\n );\n\n if (address(this).balance != targetBalance) {\n revert DepositFailure();\n }\n }\n\n function _depositOnOneOperator(\n address _withdrawer,\n uint256 _depositCount,\n uint256 _totalAvailableValidators\n ) internal {\n _depositValidatorsOfOperator(0, _depositCount, _withdrawer);\n StakingContractStorageLib.setTotalAvailableValidators(_totalAvailableValidators - _depositCount);\n }\n\n function _depositOnTwoOperators(\n address _withdrawer,\n uint256 _depositCount,\n uint256 _totalAvailableValidators\n ) internal {\n StakingContractStorageLib.ValidatorsFundingInfo memory oneOsi = StakingContractStorageLib\n .getValidatorsFundingInfo(0);\n StakingContractStorageLib.ValidatorsFundingInfo memory twoOsi = StakingContractStorageLib\n .getValidatorsFundingInfo(1);\n\n uint256 oneDepositCount;\n uint256 twoDepositCount;\n\n // using this tactic to prevent deposits of 1 validator to always go to operator 2\n if (block.number % 2 == 0) {\n oneDepositCount = _depositCount / 2;\n twoDepositCount = _depositCount - oneDepositCount;\n } else {\n twoDepositCount = _depositCount / 2;\n oneDepositCount = _depositCount - twoDepositCount;\n }\n\n if (oneDepositCount > oneOsi.availableKeys) {\n twoDepositCount = _depositCount - oneOsi.availableKeys;\n oneDepositCount = oneOsi.availableKeys;\n } else if (twoDepositCount > twoOsi.availableKeys) {\n oneDepositCount = _depositCount - twoOsi.availableKeys;\n twoDepositCount = twoOsi.availableKeys;\n }\n\n if (oneDepositCount > 0) {\n _depositValidatorsOfOperator(0, oneDepositCount, _withdrawer);\n }\n if (twoDepositCount > 0) {\n _depositValidatorsOfOperator(1, twoDepositCount, _withdrawer);\n }\n StakingContractStorageLib.setTotalAvailableValidators(\n _totalAvailableValidators - (oneDepositCount + twoDepositCount)\n );\n }\n\n function _getBaseSkip(\n bytes32 blockHash,\n uint256 index,\n uint8 prime\n ) internal pure returns (uint8 base, uint8 skip) {\n base = uint8(blockHash[(index * 2) % 32]) % prime;\n skip = (uint8(blockHash[((index * 2) + 1) % 32]) % (prime - 1)) + 1;\n }\n\n function _getOperatorFundedCount(uint8 operatorIndex, ValidatorAllocationCache[] memory vd)\n internal\n view\n returns (uint32)\n {\n if (operatorIndex >= vd.length) {\n return 0;\n }\n if (vd[operatorIndex].used == false) {\n StakingContractStorageLib.ValidatorsFundingInfo memory osi = StakingContractStorageLib\n .getValidatorsFundingInfo(operatorIndex);\n vd[operatorIndex].used = true;\n vd[operatorIndex].funded = osi.funded;\n vd[operatorIndex].available = osi.availableKeys;\n }\n return vd[operatorIndex].funded + vd[operatorIndex].toDeposit;\n }\n\n function _getOperatorAvailableCount(uint8 operatorIndex, ValidatorAllocationCache[] memory vd)\n internal\n view\n returns (uint32)\n {\n if (operatorIndex >= vd.length) {\n return 0;\n }\n if (vd[operatorIndex].used == false) {\n StakingContractStorageLib.ValidatorsFundingInfo memory osi = StakingContractStorageLib\n .getValidatorsFundingInfo(operatorIndex);\n vd[operatorIndex].used = true;\n vd[operatorIndex].funded = osi.funded;\n vd[operatorIndex].available = osi.availableKeys;\n }\n return vd[operatorIndex].available - vd[operatorIndex].toDeposit;\n }\n\n function _assignTemporaryDeposit(uint8 operatorIndex, ValidatorAllocationCache[] memory vd) internal pure {\n vd[operatorIndex].toDeposit += 1;\n }\n\n function _getBestOperator(\n uint8 alphaIndex,\n uint8 betaIndex,\n bytes32 blockHash,\n ValidatorAllocationCache[] memory vd\n ) internal view returns (uint8) {\n uint256 alphaFundedCount = _getOperatorFundedCount(alphaIndex, vd);\n uint256 betaFundedCount = _getOperatorFundedCount(betaIndex, vd);\n if (alphaFundedCount < betaFundedCount) {\n return alphaIndex;\n } else if (alphaFundedCount > betaFundedCount) {\n return betaIndex;\n } else {\n bool coinToss = (uint8(blockHash[(alphaIndex + betaIndex) % 32]) % 2) == 1;\n if (coinToss == false) {\n return betaIndex;\n } else {\n return alphaIndex;\n }\n }\n }\n\n function _getElligibleOperators(\n uint8 base,\n uint8 skip,\n uint8 prime,\n ValidatorAllocationCache[] memory vd\n ) internal view returns (uint8, uint8) {\n int16 alphaIndex = -1;\n int16 betaIndex = -1;\n uint8 index = base;\n while (alphaIndex == -1 || betaIndex == -1) {\n if (_getOperatorAvailableCount(index, vd) > 0) {\n if (alphaIndex == -1) {\n alphaIndex = int8(index);\n } else {\n betaIndex = int8(index);\n }\n }\n index = uint8((uint256(index) + skip) % prime);\n if (index == base && betaIndex == -1) {\n betaIndex = alphaIndex;\n }\n }\n return (uint8(int8(alphaIndex)), uint8(int8(betaIndex)));\n }\n\n function _depositOnThreeOrMoreOperators(\n address _withdrawer,\n uint256 _depositCount,\n uint256 _totalAvailableValidators,\n StakingContractStorageLib.OperatorsSlot storage _operators\n ) internal {\n uint256 operatorCount = _operators.value.length;\n uint8 optimusPrime = _getClosestPrimeAbove(uint8(operatorCount));\n bytes32 blockHash = blockhash(block.number - 1); // weak random number as it's not a security issue\n\n ValidatorAllocationCache[] memory vd = new ValidatorAllocationCache[](operatorCount);\n\n for (uint256 index; index < _depositCount; ) {\n // Retrieve base index and skip value based on block hash and current loop index\n (uint8 base, uint8 skip) = _getBaseSkip(blockHash, index, optimusPrime);\n // Retrieve two operator indexes pointing to two (or the same) operator(s) that have at least one available\n // validator key to be used for a deposit. This method takes into account possible pending deposits from\n // previous loop rounds.\n (uint8 alphaIndex, uint8 betaIndex) = _getElligibleOperators(base, skip, optimusPrime, vd);\n\n if (alphaIndex == betaIndex) {\n // Assign the deposit to the only operator having available keys\n _assignTemporaryDeposit(alphaIndex, vd);\n } else {\n // Assign the deposit to the operator having the lowest amount of funded keys\n _assignTemporaryDeposit(_getBestOperator(alphaIndex, betaIndex, blockHash, vd), vd);\n }\n\n unchecked {\n ++index;\n }\n }\n\n // Loop through the cached operator values and deposit any pending deposits\n for (uint256 index; index < vd.length; ) {\n if (vd[index].toDeposit > 0) {\n _depositValidatorsOfOperator(index, vd[index].toDeposit, _withdrawer);\n }\n unchecked {\n ++index;\n }\n }\n\n StakingContractStorageLib.setTotalAvailableValidators(_totalAvailableValidators - _depositCount);\n }\n\n function _deposit(address _withdrawer) internal {\n if (msg.value == 0 || msg.value % DEPOSIT_SIZE != 0) {\n revert InvalidDepositValue();\n }\n uint256 totalAvailableValidators = StakingContractStorageLib.getTotalAvailableValidators();\n uint256 depositCount = msg.value / DEPOSIT_SIZE;\n if (depositCount > totalAvailableValidators) {\n revert NotEnoughValidators();\n }\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n if (operators.value.length == 0) {\n revert NoOperators();\n } else if (operators.value.length == 1) {\n _depositOnOneOperator(_withdrawer, depositCount, totalAvailableValidators);\n } else if (operators.value.length == 2) {\n _depositOnTwoOperators(_withdrawer, depositCount, totalAvailableValidators);\n } else {\n _depositOnThreeOrMoreOperators(_withdrawer, depositCount, totalAvailableValidators, operators);\n }\n }\n\n function _primes() internal pure returns (uint8[54] memory primes) {\n primes = [\n 2,\n 3,\n 5,\n 7,\n 11,\n 13,\n 17,\n 19,\n 23,\n 29,\n 31,\n 37,\n 41,\n 43,\n 47,\n 53,\n 59,\n 61,\n 67,\n 71,\n 73,\n 79,\n 83,\n 89,\n 97,\n 101,\n 103,\n 107,\n 109,\n 113,\n 127,\n 131,\n 137,\n 139,\n 149,\n 151,\n 157,\n 163,\n 167,\n 173,\n 179,\n 181,\n 191,\n 193,\n 197,\n 199,\n 211,\n 223,\n 227,\n 229,\n 233,\n 239,\n 241,\n 251\n ];\n }\n\n function _getClosestPrimeAbove(uint8 _count) internal pure returns (uint8) {\n uint8[54] memory primes = _primes();\n for (uint256 i; i < primes.length; ) {\n if (primes[i] >= _count) {\n return primes[i];\n }\n unchecked {\n ++i;\n }\n }\n revert InvalidValidatorCount();\n }\n\n function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {\n if (_a < _b) {\n return _a;\n }\n return _b;\n }\n\n /// @notice Internal utility to compute the receiver deterministic address\n /// @param _publicKey Public Key assigned to the receiver\n /// @param _prefix Prefix used to generate multiple receivers per public key\n function _getDeterministicReceiver(bytes memory _publicKey, uint256 _prefix) internal view returns (address) {\n bytes32 publicKeyRoot = _getPubKeyRoot(_publicKey);\n bytes32 salt = sha256(abi.encodePacked(_prefix, publicKeyRoot));\n address implementation = StakingContractStorageLib.getFeeRecipientImplementation();\n return Clones.predictDeterministicAddress(implementation, salt);\n }\n\n /// @notice Internal utility to deploy and withdraw the fees from a receiver\n /// @param _publicKey Public Key assigned to the receiver\n /// @param _prefix Prefix used to generate multiple receivers per public key\n /// @param _dispatcher Address of the dispatcher contract\n function _deployAndWithdraw(\n bytes calldata _publicKey,\n uint256 _prefix,\n address _dispatcher\n ) internal {\n bytes32 publicKeyRoot = _getPubKeyRoot(_publicKey);\n bytes32 feeRecipientSalt = sha256(abi.encodePacked(_prefix, publicKeyRoot));\n address implementation = StakingContractStorageLib.getFeeRecipientImplementation();\n address feeRecipientAddress = Clones.predictDeterministicAddress(implementation, feeRecipientSalt);\n if (feeRecipientAddress.code.length == 0) {\n Clones.cloneDeterministic(implementation, feeRecipientSalt);\n IFeeRecipient(feeRecipientAddress).init(_dispatcher, publicKeyRoot);\n }\n IFeeRecipient(feeRecipientAddress).withdraw();\n }\n}\n" - }, - "src/contracts/libs/UintLib.sol": { - "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\nlibrary Uint256Lib {\n function toLittleEndian64(uint256 _value) internal pure returns (uint256 result) {\n result = 0;\n uint256 temp_value = _value;\n for (uint256 i = 0; i < 8; ++i) {\n result = (result << 8) | (temp_value & 0xFF);\n temp_value >>= 8;\n }\n\n assert(0 == temp_value); // fully converted\n result <<= (24 * 8);\n }\n}\n" - }, - "src/contracts/libs/BytesLib.sol": { - "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\nlibrary BytesLib {\n function pad64(bytes memory _b) internal pure returns (bytes memory) {\n assert(_b.length >= 32 && _b.length <= 64);\n if (64 == _b.length) return _b;\n\n bytes memory zero32 = new bytes(32);\n assembly {\n mstore(add(zero32, 0x20), 0)\n }\n\n if (32 == _b.length) return BytesLib.concat(_b, zero32);\n else return BytesLib.concat(_b, BytesLib.slice(zero32, 0, uint256(64) - _b.length));\n }\n\n function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(\n 0x40,\n and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n )\n )\n }\n\n return tempBytes;\n }\n\n function slice(\n bytes memory _bytes,\n uint256 _start,\n uint256 _length\n ) internal pure returns (bytes memory) {\n require(_length + 31 >= _length, \"slice_overflow\");\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n}\n" - }, - "src/contracts/interfaces/IFeeRecipient.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\ninterface IFeeRecipient {\n function init(address _dispatcher, bytes32 _publicKeyRoot) external;\n\n function withdraw() external;\n}\n" - }, - "src/contracts/libs/StakingContractStorageLib.sol": { - "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\nlibrary StakingContractStorageLib {\n function getUint256(bytes32 position) internal view returns (uint256 data) {\n assembly {\n data := sload(position)\n }\n }\n\n function setUint256(bytes32 position, uint256 data) internal {\n assembly {\n sstore(position, data)\n }\n }\n\n function getAddress(bytes32 position) internal view returns (address data) {\n assembly {\n data := sload(position)\n }\n }\n\n function setAddress(bytes32 position, address data) internal {\n assembly {\n sstore(position, data)\n }\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant VERSION_SLOT = keccak256(\"StakingContract.version\");\n\n function getVersion() internal view returns (uint256) {\n return getUint256(VERSION_SLOT);\n }\n\n function setVersion(uint256 _newVersion) internal {\n setUint256(VERSION_SLOT, _newVersion);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant ADMIN_SLOT = keccak256(\"StakingContract.admin\");\n bytes32 internal constant PENDING_ADMIN_SLOT = keccak256(\"StakingContract.pendingAdmin\");\n\n function getAdmin() internal view returns (address) {\n return getAddress(ADMIN_SLOT);\n }\n\n function setAdmin(address _newAdmin) internal {\n setAddress(ADMIN_SLOT, _newAdmin);\n }\n\n function getPendingAdmin() internal view returns (address) {\n return getAddress(PENDING_ADMIN_SLOT);\n }\n\n function setPendingAdmin(address _newPendingAdmin) internal {\n setAddress(PENDING_ADMIN_SLOT, _newPendingAdmin);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant TREASURY_SLOT = keccak256(\"StakingContract.treasury\");\n\n function getTreasury() internal view returns (address) {\n return getAddress(TREASURY_SLOT);\n }\n\n function setTreasury(address _newTreasury) internal {\n setAddress(TREASURY_SLOT, _newTreasury);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant DEPOSIT_CONTRACT_SLOT = keccak256(\"StakingContract.depositContract\");\n\n function getDepositContract() internal view returns (address) {\n return getAddress(DEPOSIT_CONTRACT_SLOT);\n }\n\n function setDepositContract(address _newDepositContract) internal {\n setAddress(DEPOSIT_CONTRACT_SLOT, _newDepositContract);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant OPERATORS_SLOT = keccak256(\"StakingContract.operators\");\n\n struct OperatorInfo {\n address operator;\n address feeRecipient;\n uint256 limit;\n bytes[] publicKeys;\n bytes[] signatures;\n bool deactivated;\n }\n\n struct OperatorsSlot {\n OperatorInfo[] value;\n }\n\n function getOperators() internal pure returns (OperatorsSlot storage p) {\n bytes32 slot = OPERATORS_SLOT;\n assembly {\n p.slot := slot\n }\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant VALIDATORS_FUNDING_INFO_SLOT = keccak256(\"StakingContract.validatorsFundingInfo\");\n\n struct ValidatorsFundingInfo {\n uint32 availableKeys;\n uint32 funded;\n }\n\n struct UintToUintMappingSlot {\n mapping(uint256 => uint256) value;\n }\n\n function getValidatorsFundingInfo(uint256 _index) internal view returns (ValidatorsFundingInfo memory vfi) {\n UintToUintMappingSlot storage p;\n bytes32 slot = VALIDATORS_FUNDING_INFO_SLOT;\n\n assembly {\n p.slot := slot\n }\n\n uint256 slotIndex = _index >> 2;\n uint256 innerIndex = (_index & 3) << 6;\n uint256 value = p.value[slotIndex] >> innerIndex;\n vfi.availableKeys = uint32(value);\n vfi.funded = uint32(value >> 32);\n }\n\n function setValidatorsFundingInfo(\n uint256 _index,\n uint32 _availableKeys,\n uint32 _funded\n ) internal {\n UintToUintMappingSlot storage p;\n bytes32 slot = VALIDATORS_FUNDING_INFO_SLOT;\n\n assembly {\n p.slot := slot\n }\n\n uint256 slotIndex = _index >> 2;\n uint256 innerIndex = (_index & 3) << 6;\n p.value[slotIndex] =\n (p.value[slotIndex] & (~(uint256(0xFFFFFFFFFFFFFFFF) << innerIndex))) |\n ((uint256(_availableKeys) | (uint256(_funded) << 32)) << innerIndex);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant TOTAL_AVAILABLE_VALIDATORS_SLOT = keccak256(\"StakingContract.totalAvailableValidators\");\n\n function getTotalAvailableValidators() internal view returns (uint256) {\n return getUint256(TOTAL_AVAILABLE_VALIDATORS_SLOT);\n }\n\n function setTotalAvailableValidators(uint256 _newTotal) internal {\n setUint256(TOTAL_AVAILABLE_VALIDATORS_SLOT, _newTotal);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant WITHDRAWERS_SLOT = keccak256(\"StakingContract.withdrawers\");\n\n struct WithdrawersSlot {\n mapping(bytes32 => address) value;\n }\n\n function getWithdrawers() internal pure returns (WithdrawersSlot storage p) {\n bytes32 slot = WITHDRAWERS_SLOT;\n assembly {\n p.slot := slot\n }\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n struct OperatorIndex {\n bool enabled;\n uint32 operatorIndex;\n }\n\n struct OperatorIndexPerValidatorSlot {\n mapping(bytes32 => OperatorIndex) value;\n }\n\n bytes32 internal constant OPERATOR_INDEX_PER_VALIDATOR_SLOT =\n keccak256(\"StakingContract.operatorIndexPerValidator\");\n\n function getOperatorIndexPerValidator() internal pure returns (OperatorIndexPerValidatorSlot storage p) {\n bytes32 slot = OPERATOR_INDEX_PER_VALIDATOR_SLOT;\n assembly {\n p.slot := slot\n }\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant GLOBAL_FEE_SLOT = keccak256(\"StakingContract.globalFee\");\n\n function getGlobalFee() internal view returns (uint256) {\n return getUint256(GLOBAL_FEE_SLOT);\n }\n\n function setGlobalFee(uint256 _newTreasuryFee) internal {\n setUint256(GLOBAL_FEE_SLOT, _newTreasuryFee);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant OPERATOR_FEE_SLOT = keccak256(\"StakingContract.operatorFee\");\n\n function getOperatorFee() internal view returns (uint256) {\n return getUint256(OPERATOR_FEE_SLOT);\n }\n\n function setOperatorFee(uint256 _newOperatorFee) internal {\n setUint256(OPERATOR_FEE_SLOT, _newOperatorFee);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant EL_DISPATCHER_SLOT = keccak256(\"StakingContract.executionLayerDispatcher\");\n\n function getELDispatcher() internal view returns (address) {\n return getAddress(EL_DISPATCHER_SLOT);\n }\n\n function setELDispatcher(address _newElDispatcher) internal {\n setAddress(EL_DISPATCHER_SLOT, _newElDispatcher);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant CL_DISPATCHER_SLOT = keccak256(\"StakingContract.consensusLayerDispatcher\");\n\n function getCLDispatcher() internal view returns (address) {\n return getAddress(CL_DISPATCHER_SLOT);\n }\n\n function setCLDispatcher(address _newClDispatcher) internal {\n setAddress(CL_DISPATCHER_SLOT, _newClDispatcher);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant FEE_RECIPIENT_IMPLEMENTATION_SLOT =\n keccak256(\"StakingContract.feeRecipientImplementation\");\n\n function getFeeRecipientImplementation() internal view returns (address) {\n return getAddress(FEE_RECIPIENT_IMPLEMENTATION_SLOT);\n }\n\n function setFeeRecipientImplementation(address _newFeeRecipientImplementation) internal {\n setAddress(FEE_RECIPIENT_IMPLEMENTATION_SLOT, _newFeeRecipientImplementation);\n }\n}\n" - }, - "@openzeppelin/contracts/proxy/Clones.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create(0, ptr, 0x37)\n }\n require(instance != address(0), \"ERC1167: create failed\");\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create2(0, ptr, 0x37, salt)\n }\n require(instance != address(0), \"ERC1167: create2 failed\");\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\n mstore(add(ptr, 0x38), shl(0x60, deployer))\n mstore(add(ptr, 0x4c), salt)\n mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\n predicted := keccak256(add(ptr, 0x37), 0x55)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(address implementation, bytes32 salt)\n internal\n view\n returns (address predicted)\n {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n}\n" - } - }, - "settings": { - "optimizer": { - "enabled": true, - "runs": 200 - }, - "outputSelection": { - "*": { - "*": [ - "abi", - "evm.bytecode", - "evm.deployedBytecode", - "evm.methodIdentifiers", - "metadata", - "devdoc", - "userdoc", - "storageLayout", - "evm.gasEstimates", - "devdoc", - "userdoc" - ], - "": [ - "ast" - ] - } - }, - "metadata": { - "useLiteralContent": true - } - } -} \ No newline at end of file diff --git a/deployments/goerli_live/solcInputs/ba9e63c4d731596ae86ac9b18992133c.json b/deployments/goerli_live/solcInputs/ba9e63c4d731596ae86ac9b18992133c.json new file mode 100644 index 0000000..817c39c --- /dev/null +++ b/deployments/goerli_live/solcInputs/ba9e63c4d731596ae86ac9b18992133c.json @@ -0,0 +1,55 @@ +{ + "language": "Solidity", + "sources": { + "src/contracts/interfaces/IDepositContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\ninterface IDepositContract {\n function deposit(\n bytes calldata pubkey,\n bytes calldata withdrawalCredentials,\n bytes calldata signature,\n bytes32 depositDataRoot\n ) external payable;\n}\n" + }, + "src/contracts/StakingContract.sol": { + "content": "//SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.8.10;\n\nimport \"./libs/UintLib.sol\";\nimport \"./libs/BytesLib.sol\";\nimport \"./interfaces/IFeeRecipient.sol\";\nimport \"./interfaces/IDepositContract.sol\";\nimport \"./libs/StakingContractStorageLib.sol\";\nimport \"@openzeppelin/contracts/proxy/Clones.sol\";\n\n/// @title Ethereum Staking Contract\n/// @author Kiln\n/// @notice You can use this contract to store validator keys and have users fund them and trigger deposits.\ncontract StakingContract {\n using StakingContractStorageLib for bytes32;\n\n uint256 internal constant EXECUTION_LAYER_SALT_PREFIX = 0;\n uint256 internal constant CONSENSUS_LAYER_SALT_PREFIX = 1;\n uint256 public constant SIGNATURE_LENGTH = 96;\n uint256 public constant PUBLIC_KEY_LENGTH = 48;\n uint256 public constant DEPOSIT_SIZE = 32 ether;\n uint256 internal constant BASIS_POINTS = 10_000;\n\n error Forbidden();\n error InvalidFee();\n error Deactivated();\n error NoOperators();\n error InvalidCall();\n error Unauthorized();\n error DepositFailure();\n error InvalidArgument();\n error UnsortedIndexes();\n error InvalidPublicKeys();\n error InvalidSignatures();\n error AlreadyInitialized();\n error InvalidDepositValue();\n error NotEnoughValidators();\n error InvalidValidatorCount();\n error DuplicateValidatorKey(bytes);\n error FundedValidatorDeletionAttempt();\n error OperatorLimitTooHigh(uint256 limit, uint256 keyCount);\n error MaximumOperatorCountAlreadyReached();\n\n struct ValidatorAllocationCache {\n bool used;\n uint8 operatorIndex;\n uint32 funded;\n uint32 toDeposit;\n uint32 available;\n }\n\n event Deposit(address indexed caller, address indexed withdrawer, bytes publicKey, bytes signature);\n event ValidatorKeysAdded(uint256 indexed operatorIndex, bytes publicKeys, bytes signatures);\n event ValidatorKeyRemoved(uint256 indexed operatorIndex, bytes publicKey);\n event ChangedWithdrawer(bytes publicKey, address newWithdrawer);\n event ChangedOperatorLimit(uint256 operatorIndex, uint256 limit);\n event ChangedTreasury(address newTreasury);\n event ChangedGlobalFee(uint256 newGlobalFee);\n event ChangedOperatorFee(uint256 newOperatorFee);\n event ChangedAdmin(address newAdmin);\n event NewOperator(address operatorAddress, address feeRecipientAddress, uint256 index);\n event ChangedOperatorAddresses(uint256 operatorIndex, address operatorAddress, address feeRecipientAddress);\n event DeactivatedOperator(uint256 _operatorIndex);\n event ActivatedOperator(uint256 _operatorIndex);\n event SetWithdrawerCustomizationStatus(bool _status);\n\n /// @notice Ensures an initialisation call has been called only once per _version value\n /// @param _version The current initialisation value\n modifier init(uint256 _version) {\n if (_version != StakingContractStorageLib.getVersion() + 1) {\n revert AlreadyInitialized();\n }\n\n StakingContractStorageLib.setVersion(_version);\n _;\n }\n\n /// @notice Ensures that the caller is the admin\n modifier onlyAdmin() {\n if (msg.sender != StakingContractStorageLib.getAdmin()) {\n revert Unauthorized();\n }\n\n _;\n }\n\n /// @notice Ensures that the caller is the admin or the operator\n modifier onlyActiveOperatorOrAdmin(uint256 _operatorIndex) {\n if (msg.sender == StakingContractStorageLib.getAdmin()) {\n _;\n } else {\n _onlyActiveOperator(_operatorIndex);\n _;\n }\n }\n\n /// @notice Ensures that the caller is the admin\n modifier onlyActiveOperator(uint256 _operatorIndex) {\n _onlyActiveOperator(_operatorIndex);\n _;\n }\n\n /// @notice Ensures that the caller is the operator fee recipient\n modifier onlyOperatorFeeRecipient(uint256 _operatorIndex) {\n StakingContractStorageLib.OperatorInfo memory operatorInfo = StakingContractStorageLib.getOperators().value[\n _operatorIndex\n ];\n\n if (operatorInfo.deactivated) {\n revert Deactivated();\n }\n\n if (msg.sender != operatorInfo.feeRecipient) {\n revert Unauthorized();\n }\n\n _;\n }\n\n /// @notice Explicit deposit method using msg.sender\n /// @dev A multiple of 32 ETH should be sent\n function deposit() external payable {\n _deposit(msg.sender);\n }\n\n /// @notice Implicit deposit method\n /// @dev A multiple of 32 ETH should be sent\n /// @dev The withdrawer is set to the message sender address\n receive() external payable {\n _deposit(msg.sender);\n }\n\n /// @notice Fallback detection\n /// @dev Fails on any call that fallbacks\n fallback() external payable {\n revert InvalidCall();\n }\n\n function initialize_1(\n address _admin,\n address _treasury,\n address _depositContract,\n address _elDispatcher,\n address _clDispatcher,\n address _feeRecipientImplementation,\n uint256 _globalFee,\n uint256 _operatorFee\n ) external init(1) {\n StakingContractStorageLib.setAdmin(_admin);\n StakingContractStorageLib.setTreasury(_treasury);\n\n if (_globalFee > BASIS_POINTS) {\n revert InvalidFee();\n }\n StakingContractStorageLib.setGlobalFee(_globalFee);\n if (_operatorFee > BASIS_POINTS) {\n revert InvalidFee();\n }\n StakingContractStorageLib.setOperatorFee(_operatorFee);\n\n StakingContractStorageLib.setELDispatcher(_elDispatcher);\n StakingContractStorageLib.setCLDispatcher(_clDispatcher);\n StakingContractStorageLib.setDepositContract(_depositContract);\n StakingContractStorageLib.setFeeRecipientImplementation(_feeRecipientImplementation);\n }\n\n /// @notice Changes the behavior of the withdrawer customization logic\n /// @param _enabled True to allow users to customize the withdrawer\n function setWithdrawerCustomizationEnabled(bool _enabled) external onlyAdmin {\n StakingContractStorageLib.setWithdrawerCustomizationEnabled(_enabled);\n emit SetWithdrawerCustomizationStatus(_enabled);\n }\n\n /// @notice Retrieve system admin\n function getAdmin() external view returns (address) {\n return StakingContractStorageLib.getAdmin();\n }\n\n /// @notice Set new treasury\n /// @dev Only callable by admin\n /// @param _newTreasury New Treasury address\n function setTreasury(address _newTreasury) external onlyAdmin {\n emit ChangedTreasury(_newTreasury);\n StakingContractStorageLib.setTreasury(_newTreasury);\n }\n\n /// @notice Retrieve system treasury\n function getTreasury() external view returns (address) {\n return StakingContractStorageLib.getTreasury();\n }\n\n /// @notice Retrieve the global fee\n function getGlobalFee() external view returns (uint256) {\n return StakingContractStorageLib.getGlobalFee();\n }\n\n /// @notice Retrieve the operator fee\n function getOperatorFee() external view returns (uint256) {\n return StakingContractStorageLib.getOperatorFee();\n }\n\n /// @notice Compute the Execution Layer Fee recipient address for a given validator public key\n /// @param _publicKey Validator to get the recipient\n function getELFeeRecipient(bytes calldata _publicKey) external view returns (address) {\n return _getDeterministicReceiver(_publicKey, EXECUTION_LAYER_SALT_PREFIX);\n }\n\n /// @notice Compute the Consensus Layer Fee recipient address for a given validator public key\n /// @param _publicKey Validator to get the recipient\n function getCLFeeRecipient(bytes calldata _publicKey) external view returns (address) {\n return _getDeterministicReceiver(_publicKey, CONSENSUS_LAYER_SALT_PREFIX);\n }\n\n /// @notice Retrieve the Execution & Consensus Layer Fee operator recipient for a given public key\n function getOperatorFeeRecipient(bytes32 pubKeyRoot) external view returns (address) {\n return\n StakingContractStorageLib\n .getOperators()\n .value[StakingContractStorageLib.getOperatorIndexPerValidator().value[pubKeyRoot].operatorIndex]\n .feeRecipient;\n }\n\n /// @notice Retrieve withdrawer of public key\n /// @param _publicKey Public Key to check\n function getWithdrawer(bytes calldata _publicKey) external view returns (address) {\n return _getWithdrawer(_getPubKeyRoot(_publicKey));\n }\n\n /// @notice Retrieve withdrawer of public key root\n /// @param _publicKeyRoot Hash of the public key\n function getWithdrawerFromPublicKeyRoot(bytes32 _publicKeyRoot) external view returns (address) {\n return _getWithdrawer(_publicKeyRoot);\n }\n\n /// @notice Retrieve operator details\n /// @param _operatorIndex Operator index\n function getOperator(uint256 _operatorIndex)\n external\n view\n returns (\n address operatorAddress,\n address feeRecipientAddress,\n uint256 limit,\n uint256 keys,\n uint256 funded,\n uint256 available,\n bool deactivated\n )\n {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n if (_operatorIndex < operators.value.length) {\n StakingContractStorageLib.ValidatorsFundingInfo memory _operatorInfo = StakingContractStorageLib\n .getValidatorsFundingInfo(_operatorIndex);\n StakingContractStorageLib.OperatorInfo memory _operator = operators.value[_operatorIndex];\n\n (operatorAddress, feeRecipientAddress, limit, keys, deactivated) = (\n _operator.operator,\n _operator.feeRecipient,\n _operator.limit,\n _operator.publicKeys.length,\n _operator.deactivated\n );\n (funded, available) = (_operatorInfo.funded, _operatorInfo.availableKeys);\n }\n }\n\n /// @notice Get details about a validator\n /// @param _operatorIndex Index of the operator running the validator\n /// @param _validatorIndex Index of the validator\n function getValidator(uint256 _operatorIndex, uint256 _validatorIndex)\n external\n view\n returns (\n bytes memory publicKey,\n bytes memory signature,\n address withdrawer,\n bool funded\n )\n {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n publicKey = operators.value[_operatorIndex].publicKeys[_validatorIndex];\n signature = operators.value[_operatorIndex].signatures[_validatorIndex];\n withdrawer = _getWithdrawer(_getPubKeyRoot(publicKey));\n funded = _validatorIndex < StakingContractStorageLib.getValidatorsFundingInfo(_operatorIndex).funded;\n }\n\n /// @notice Get the total available keys that are ready to be used for deposits\n function getAvailableValidatorCount() external view returns (uint256) {\n return StakingContractStorageLib.getTotalAvailableValidators();\n }\n\n /// @notice Set new admin\n /// @dev Only callable by admin\n /// @param _newAdmin New Administrator address\n function transferOwnership(address _newAdmin) external onlyAdmin {\n StakingContractStorageLib.setPendingAdmin(_newAdmin);\n }\n\n /// @notice New admin must accept its role by calling this method\n /// @dev Only callable by new admin\n function acceptOwnership() external {\n address newAdmin = StakingContractStorageLib.getPendingAdmin();\n\n if (msg.sender != newAdmin) {\n revert Unauthorized();\n }\n StakingContractStorageLib.setAdmin(newAdmin);\n emit ChangedAdmin(newAdmin);\n }\n\n /// @notice Get the new admin's address previously set for an ownership transfer\n function getPendingAdmin() external view returns (address) {\n return StakingContractStorageLib.getPendingAdmin();\n }\n\n /// @notice Add new operator\n /// @dev Only callable by admin\n /// @param _operatorAddress Operator address allowed to add / remove validators\n /// @param _feeRecipientAddress Operator address used to manage rewards\n function addOperator(address _operatorAddress, address _feeRecipientAddress) external onlyAdmin returns (uint256) {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n StakingContractStorageLib.OperatorInfo memory newOperator;\n\n if (operators.value.length == 251) {\n revert MaximumOperatorCountAlreadyReached();\n }\n newOperator.operator = _operatorAddress;\n newOperator.feeRecipient = _feeRecipientAddress;\n operators.value.push(newOperator);\n uint256 operatorIndex = operators.value.length - 1;\n emit NewOperator(_operatorAddress, _feeRecipientAddress, operatorIndex);\n return operatorIndex;\n }\n\n /// @notice Set new operator addresses (operations and reward management)\n /// @dev Only callable by fee recipient address manager\n /// @param _operatorIndex Index of the operator to update\n /// @param _operatorAddress New operator address for operations management\n /// @param _feeRecipientAddress New operator address for reward management\n function setOperatorAddresses(\n uint256 _operatorIndex,\n address _operatorAddress,\n address _feeRecipientAddress\n ) external onlyOperatorFeeRecipient(_operatorIndex) {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n\n operators.value[_operatorIndex].operator = _operatorAddress;\n operators.value[_operatorIndex].feeRecipient = _feeRecipientAddress;\n emit ChangedOperatorAddresses(_operatorIndex, _operatorAddress, _feeRecipientAddress);\n }\n\n /// @notice Set withdrawer for public key\n /// @dev Only callable by current public key withdrawer\n /// @param _publicKey Public key to change withdrawer\n /// @param _newWithdrawer New withdrawer address\n function setWithdrawer(bytes calldata _publicKey, address _newWithdrawer) external {\n if (!StakingContractStorageLib.getWithdrawerCustomizationEnabled()) {\n revert Forbidden();\n }\n bytes32 pubkeyRoot = sha256(BytesLib.pad64(_publicKey));\n StakingContractStorageLib.WithdrawersSlot storage withdrawers = StakingContractStorageLib.getWithdrawers();\n\n if (withdrawers.value[pubkeyRoot] != msg.sender) {\n revert Unauthorized();\n }\n\n emit ChangedWithdrawer(_publicKey, _newWithdrawer);\n\n withdrawers.value[pubkeyRoot] = _newWithdrawer;\n }\n\n /// @notice Set operator staking limits\n /// @dev Only callable by admin\n /// @dev Limit should not exceed the validator key count of the operator\n /// @dev Keys should be registered before limit is increased\n /// @dev Allows all keys to be verified by the system admin before limit is increased\n /// @param _operatorIndex Operator Index\n /// @param _limit New staking limit\n function setOperatorLimit(uint256 _operatorIndex, uint256 _limit) external onlyAdmin {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n if (operators.value[_operatorIndex].deactivated) {\n revert Deactivated();\n }\n uint256 publicKeyCount = operators.value[_operatorIndex].publicKeys.length;\n if (publicKeyCount < _limit) {\n revert OperatorLimitTooHigh(_limit, publicKeyCount);\n }\n operators.value[_operatorIndex].limit = _limit;\n _updateAvailableValidatorCount(_operatorIndex);\n emit ChangedOperatorLimit(_operatorIndex, _limit);\n }\n\n /// @notice Deactivates an operator and changes the fee recipient address and the staking limit\n /// @param _operatorIndex Operator Index\n /// @param _temporaryFeeRecipient Temporary address to receive funds decided by the system admin\n function deactivateOperator(uint256 _operatorIndex, address _temporaryFeeRecipient) external onlyAdmin {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n operators.value[_operatorIndex].limit = 0;\n emit ChangedOperatorLimit(_operatorIndex, 0);\n operators.value[_operatorIndex].deactivated = true;\n emit DeactivatedOperator(_operatorIndex);\n operators.value[_operatorIndex].feeRecipient = _temporaryFeeRecipient;\n emit ChangedOperatorAddresses(_operatorIndex, operators.value[_operatorIndex].operator, _temporaryFeeRecipient);\n _updateAvailableValidatorCount(_operatorIndex);\n }\n\n /// @notice Activates an operator, without changing its 0 staking limit\n /// @param _operatorIndex Operator Index\n /// @param _newFeeRecipient Sets the fee recipient address\n function activateOperator(uint256 _operatorIndex, address _newFeeRecipient) external onlyAdmin {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n operators.value[_operatorIndex].deactivated = false;\n emit ActivatedOperator(_operatorIndex);\n operators.value[_operatorIndex].feeRecipient = _newFeeRecipient;\n emit ChangedOperatorAddresses(_operatorIndex, operators.value[_operatorIndex].operator, _newFeeRecipient);\n }\n\n /// @notice Change the Operator fee\n /// @param _operatorFee Fee in Basis Point\n function setOperatorFee(uint256 _operatorFee) external onlyAdmin {\n if (_operatorFee > BASIS_POINTS) {\n revert InvalidFee();\n }\n StakingContractStorageLib.setOperatorFee(_operatorFee);\n emit ChangedOperatorFee(_operatorFee);\n }\n\n /// @notice Change the Global fee\n /// @param _globalFee Fee in Basis Point\n function setGlobalFee(uint256 _globalFee) external onlyAdmin {\n if (_globalFee > BASIS_POINTS) {\n revert InvalidFee();\n }\n StakingContractStorageLib.setGlobalFee(_globalFee);\n emit ChangedGlobalFee(_globalFee);\n }\n\n /// @notice Add new validator public keys and signatures\n /// @dev Only callable by operator\n /// @param _operatorIndex Operator Index\n /// @param _keyCount Number of keys added\n /// @param _publicKeys Concatenated _keyCount public keys\n /// @param _signatures Concatenated _keyCount signatures\n function addValidators(\n uint256 _operatorIndex,\n uint256 _keyCount,\n bytes calldata _publicKeys,\n bytes calldata _signatures\n ) external onlyActiveOperator(_operatorIndex) {\n if (_keyCount == 0) {\n revert InvalidArgument();\n }\n\n if (_publicKeys.length % PUBLIC_KEY_LENGTH != 0 || _publicKeys.length / PUBLIC_KEY_LENGTH != _keyCount) {\n revert InvalidPublicKeys();\n }\n\n if (_signatures.length % SIGNATURE_LENGTH != 0 || _signatures.length / SIGNATURE_LENGTH != _keyCount) {\n revert InvalidSignatures();\n }\n\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n StakingContractStorageLib.OperatorIndexPerValidatorSlot\n storage operatorIndexPerValidator = StakingContractStorageLib.getOperatorIndexPerValidator();\n\n for (uint256 i; i < _keyCount; ) {\n bytes memory publicKey = BytesLib.slice(_publicKeys, i * PUBLIC_KEY_LENGTH, PUBLIC_KEY_LENGTH);\n bytes memory signature = BytesLib.slice(_signatures, i * SIGNATURE_LENGTH, SIGNATURE_LENGTH);\n\n operators.value[_operatorIndex].publicKeys.push(publicKey);\n operators.value[_operatorIndex].signatures.push(signature);\n\n bytes32 pubKeyRoot = _getPubKeyRoot(publicKey);\n\n if (operatorIndexPerValidator.value[pubKeyRoot].enabled) {\n revert DuplicateValidatorKey(publicKey);\n }\n\n operatorIndexPerValidator.value[pubKeyRoot] = StakingContractStorageLib.OperatorIndex({\n enabled: true,\n operatorIndex: uint32(_operatorIndex)\n });\n\n unchecked {\n ++i;\n }\n }\n\n emit ValidatorKeysAdded(_operatorIndex, _publicKeys, _signatures);\n\n _updateAvailableValidatorCount(_operatorIndex);\n }\n\n /// @notice Remove unfunded validators\n /// @dev Only callable by operator\n /// @dev Indexes should be provided in decreasing order\n /// @dev The limit will be set to the lowest removed operator index to ensure all changes above the\n /// lowest removed validator key are verified by the system administrator\n /// @param _operatorIndex Operator Index\n /// @param _indexes List of indexes to delete, in decreasing order\n function removeValidators(uint256 _operatorIndex, uint256[] calldata _indexes)\n external\n onlyActiveOperatorOrAdmin(_operatorIndex)\n {\n if (_indexes.length == 0) {\n revert InvalidArgument();\n }\n\n StakingContractStorageLib.ValidatorsFundingInfo memory operatorInfo = StakingContractStorageLib\n .getValidatorsFundingInfo(_operatorIndex);\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n\n if (_indexes[_indexes.length - 1] < operatorInfo.funded) {\n revert FundedValidatorDeletionAttempt();\n }\n for (uint256 i; i < _indexes.length; ) {\n if (i > 0 && _indexes[i] >= _indexes[i - 1]) {\n revert UnsortedIndexes();\n }\n\n emit ValidatorKeyRemoved(_operatorIndex, operators.value[_operatorIndex].publicKeys[_indexes[i]]);\n if (_indexes[i] == operators.value[_operatorIndex].publicKeys.length - 1) {\n operators.value[_operatorIndex].publicKeys.pop();\n operators.value[_operatorIndex].signatures.pop();\n } else {\n operators.value[_operatorIndex].publicKeys[_indexes[i]] = operators.value[_operatorIndex].publicKeys[\n operators.value[_operatorIndex].publicKeys.length - 1\n ];\n operators.value[_operatorIndex].publicKeys.pop();\n operators.value[_operatorIndex].signatures[_indexes[i]] = operators.value[_operatorIndex].signatures[\n operators.value[_operatorIndex].signatures.length - 1\n ];\n operators.value[_operatorIndex].signatures.pop();\n }\n\n unchecked {\n ++i;\n }\n }\n\n if (_indexes[_indexes.length - 1] < operators.value[_operatorIndex].limit) {\n operators.value[_operatorIndex].limit = _indexes[_indexes.length - 1];\n emit ChangedOperatorLimit(_operatorIndex, _indexes[_indexes.length - 1]);\n }\n\n _updateAvailableValidatorCount(_operatorIndex);\n }\n\n /// @notice Withdraw the Execution Layer Fee for a given validator public key\n /// @dev Funds are sent to the withdrawer account\n /// @dev This method is public on purpose\n /// @param _publicKey Validator to withdraw Execution Layer Fees from\n function withdrawELFee(bytes calldata _publicKey) external {\n _deployAndWithdraw(_publicKey, EXECUTION_LAYER_SALT_PREFIX, StakingContractStorageLib.getELDispatcher());\n }\n\n /// @notice Withdraw the Consensus Layer Fee for a given validator public key\n /// @dev Funds are sent to the withdrawer account\n /// @dev This method is public on purpose\n /// @param _publicKey Validator to withdraw Consensus Layer Fees from\n function withdrawCLFee(bytes calldata _publicKey) external {\n _deployAndWithdraw(_publicKey, CONSENSUS_LAYER_SALT_PREFIX, StakingContractStorageLib.getCLDispatcher());\n }\n\n /// @notice Withdraw both Consensus and Execution Layer Fee for a given validator public key\n /// @dev Reverts if any is null\n /// @param _publicKey Validator to withdraw Execution and Consensus Layer Fees from\n function withdraw(bytes calldata _publicKey) external {\n _deployAndWithdraw(_publicKey, EXECUTION_LAYER_SALT_PREFIX, StakingContractStorageLib.getELDispatcher());\n _deployAndWithdraw(_publicKey, CONSENSUS_LAYER_SALT_PREFIX, StakingContractStorageLib.getCLDispatcher());\n }\n\n /// ██ ███ ██ ████████ ███████ ██████ ███ ██ █████ ██\n /// ██ ████ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██\n /// ██ ██ ██ ██ ██ █████ ██████ ██ ██ ██ ███████ ██\n /// ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██\n /// ██ ██ ████ ██ ███████ ██ ██ ██ ████ ██ ██ ███████\n\n function _onlyActiveOperator(uint256 _operatorIndex) internal view {\n StakingContractStorageLib.OperatorInfo memory operatorInfo = StakingContractStorageLib.getOperators().value[\n _operatorIndex\n ];\n\n if (operatorInfo.deactivated) {\n revert Deactivated();\n }\n\n if (msg.sender != operatorInfo.operator) {\n revert Unauthorized();\n }\n }\n\n function _getPubKeyRoot(bytes memory _publicKey) internal pure returns (bytes32) {\n return sha256(BytesLib.pad64(_publicKey));\n }\n\n function _getWithdrawer(bytes32 _publicKeyRoot) internal view returns (address) {\n return StakingContractStorageLib.getWithdrawers().value[_publicKeyRoot];\n }\n\n function _updateAvailableValidatorCount(uint256 _operatorIndex) internal {\n StakingContractStorageLib.ValidatorsFundingInfo memory validatorFundingInfo = StakingContractStorageLib\n .getValidatorsFundingInfo(_operatorIndex);\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n\n uint32 oldAvailableCount = validatorFundingInfo.availableKeys;\n uint32 newAvailableCount = 0;\n uint256 cap = _min(operators.value[_operatorIndex].limit, operators.value[_operatorIndex].publicKeys.length);\n\n if (cap <= validatorFundingInfo.funded) {\n StakingContractStorageLib.setValidatorsFundingInfo(_operatorIndex, 0, validatorFundingInfo.funded);\n } else {\n newAvailableCount = uint32(cap - validatorFundingInfo.funded);\n StakingContractStorageLib.setValidatorsFundingInfo(\n _operatorIndex,\n newAvailableCount,\n validatorFundingInfo.funded\n );\n }\n\n if (oldAvailableCount != newAvailableCount) {\n StakingContractStorageLib.setTotalAvailableValidators(\n (StakingContractStorageLib.getTotalAvailableValidators() - oldAvailableCount) + newAvailableCount\n );\n }\n }\n\n function _addressToWithdrawalCredentials(address _recipient) internal pure returns (bytes32) {\n return\n bytes32(uint256(uint160(_recipient)) + 0x0100000000000000000000000000000000000000000000000000000000000000);\n }\n\n function _depositValidatorsOfOperator(\n uint256 _operatorIndex,\n uint256 _validatorCount,\n address _withdrawer\n ) internal {\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n StakingContractStorageLib.OperatorInfo storage operator = operators.value[_operatorIndex];\n StakingContractStorageLib.ValidatorsFundingInfo memory vfi = StakingContractStorageLib.getValidatorsFundingInfo(\n _operatorIndex\n );\n\n for (uint256 i = vfi.funded; i < vfi.funded + _validatorCount; ) {\n bytes memory publicKey = operator.publicKeys[i];\n bytes memory signature = operator.signatures[i];\n address consensusLayerRecipient = _getDeterministicReceiver(publicKey, CONSENSUS_LAYER_SALT_PREFIX);\n bytes32 withdrawalCredentials = _addressToWithdrawalCredentials(consensusLayerRecipient);\n _depositValidator(publicKey, signature, withdrawalCredentials);\n bytes32 pubkeyRoot = _getPubKeyRoot(publicKey);\n StakingContractStorageLib.getWithdrawers().value[pubkeyRoot] = _withdrawer;\n emit Deposit(msg.sender, _withdrawer, publicKey, signature);\n unchecked {\n ++i;\n }\n }\n\n StakingContractStorageLib.setValidatorsFundingInfo(\n _operatorIndex,\n uint32(vfi.availableKeys - _validatorCount),\n uint32(vfi.funded + _validatorCount)\n );\n }\n\n /// @notice Internal utility to deposit a public key, its signature and 32 ETH to the consensus layer\n /// @param _publicKey The Public Key to deposit\n /// @param _signature The Signature to deposit\n /// @param _withdrawalCredentials The Withdrawal Credentials to deposit\n function _depositValidator(\n bytes memory _publicKey,\n bytes memory _signature,\n bytes32 _withdrawalCredentials\n ) internal {\n bytes32 pubkeyRoot = _getPubKeyRoot(_publicKey);\n bytes32 signatureRoot = sha256(\n abi.encodePacked(\n sha256(BytesLib.slice(_signature, 0, 64)),\n sha256(BytesLib.pad64(BytesLib.slice(_signature, 64, SIGNATURE_LENGTH - 64)))\n )\n );\n\n uint256 depositAmount = DEPOSIT_SIZE / 1000000000 wei;\n assert(depositAmount * 1000000000 wei == DEPOSIT_SIZE);\n\n bytes32 depositDataRoot = sha256(\n abi.encodePacked(\n sha256(abi.encodePacked(pubkeyRoot, _withdrawalCredentials)),\n sha256(abi.encodePacked(Uint256Lib.toLittleEndian64(depositAmount), signatureRoot))\n )\n );\n\n uint256 targetBalance = address(this).balance - DEPOSIT_SIZE;\n\n IDepositContract(StakingContractStorageLib.getDepositContract()).deposit{value: DEPOSIT_SIZE}(\n _publicKey,\n abi.encodePacked(_withdrawalCredentials),\n _signature,\n depositDataRoot\n );\n\n if (address(this).balance != targetBalance) {\n revert DepositFailure();\n }\n }\n\n function _depositOnOneOperator(\n address _withdrawer,\n uint256 _depositCount,\n uint256 _totalAvailableValidators\n ) internal {\n _depositValidatorsOfOperator(0, _depositCount, _withdrawer);\n StakingContractStorageLib.setTotalAvailableValidators(_totalAvailableValidators - _depositCount);\n }\n\n function _depositOnTwoOperators(\n address _withdrawer,\n uint256 _depositCount,\n uint256 _totalAvailableValidators\n ) internal {\n StakingContractStorageLib.ValidatorsFundingInfo memory oneOsi = StakingContractStorageLib\n .getValidatorsFundingInfo(0);\n StakingContractStorageLib.ValidatorsFundingInfo memory twoOsi = StakingContractStorageLib\n .getValidatorsFundingInfo(1);\n\n uint256 oneDepositCount;\n uint256 twoDepositCount;\n\n // using this tactic to prevent deposits of 1 validator to always go to operator 2\n if (block.number % 2 == 0) {\n oneDepositCount = _depositCount / 2;\n twoDepositCount = _depositCount - oneDepositCount;\n } else {\n twoDepositCount = _depositCount / 2;\n oneDepositCount = _depositCount - twoDepositCount;\n }\n\n if (oneDepositCount > oneOsi.availableKeys) {\n twoDepositCount = _depositCount - oneOsi.availableKeys;\n oneDepositCount = oneOsi.availableKeys;\n } else if (twoDepositCount > twoOsi.availableKeys) {\n oneDepositCount = _depositCount - twoOsi.availableKeys;\n twoDepositCount = twoOsi.availableKeys;\n }\n\n if (oneDepositCount > 0) {\n _depositValidatorsOfOperator(0, oneDepositCount, _withdrawer);\n }\n if (twoDepositCount > 0) {\n _depositValidatorsOfOperator(1, twoDepositCount, _withdrawer);\n }\n StakingContractStorageLib.setTotalAvailableValidators(\n _totalAvailableValidators - (oneDepositCount + twoDepositCount)\n );\n }\n\n function _getBaseSkip(\n bytes32 blockHash,\n uint256 index,\n uint8 prime\n ) internal pure returns (uint8 base, uint8 skip) {\n base = uint8(blockHash[(index * 2) % 32]) % prime;\n skip = (uint8(blockHash[((index * 2) + 1) % 32]) % (prime - 1)) + 1;\n }\n\n function _getOperatorFundedCount(uint8 operatorIndex, ValidatorAllocationCache[] memory vd)\n internal\n view\n returns (uint32)\n {\n if (operatorIndex >= vd.length) {\n return 0;\n }\n if (vd[operatorIndex].used == false) {\n StakingContractStorageLib.ValidatorsFundingInfo memory osi = StakingContractStorageLib\n .getValidatorsFundingInfo(operatorIndex);\n vd[operatorIndex].used = true;\n vd[operatorIndex].funded = osi.funded;\n vd[operatorIndex].available = osi.availableKeys;\n }\n return vd[operatorIndex].funded + vd[operatorIndex].toDeposit;\n }\n\n function _getOperatorAvailableCount(uint8 operatorIndex, ValidatorAllocationCache[] memory vd)\n internal\n view\n returns (uint32)\n {\n if (operatorIndex >= vd.length) {\n return 0;\n }\n if (vd[operatorIndex].used == false) {\n StakingContractStorageLib.ValidatorsFundingInfo memory osi = StakingContractStorageLib\n .getValidatorsFundingInfo(operatorIndex);\n vd[operatorIndex].used = true;\n vd[operatorIndex].funded = osi.funded;\n vd[operatorIndex].available = osi.availableKeys;\n }\n return vd[operatorIndex].available - vd[operatorIndex].toDeposit;\n }\n\n function _assignTemporaryDeposit(uint8 operatorIndex, ValidatorAllocationCache[] memory vd) internal pure {\n vd[operatorIndex].toDeposit += 1;\n }\n\n function _getBestOperator(\n uint8 alphaIndex,\n uint8 betaIndex,\n bytes32 blockHash,\n ValidatorAllocationCache[] memory vd\n ) internal view returns (uint8) {\n uint256 alphaFundedCount = _getOperatorFundedCount(alphaIndex, vd);\n uint256 betaFundedCount = _getOperatorFundedCount(betaIndex, vd);\n if (alphaFundedCount < betaFundedCount) {\n return alphaIndex;\n } else if (alphaFundedCount > betaFundedCount) {\n return betaIndex;\n } else {\n bool coinToss = (uint8(blockHash[(alphaIndex + betaIndex) % 32]) % 2) == 1;\n if (coinToss == false) {\n return betaIndex;\n } else {\n return alphaIndex;\n }\n }\n }\n\n function _getElligibleOperators(\n uint8 base,\n uint8 skip,\n uint8 prime,\n ValidatorAllocationCache[] memory vd\n ) internal view returns (uint8, uint8) {\n int16 alphaIndex = -1;\n int16 betaIndex = -1;\n uint8 index = base;\n while (alphaIndex == -1 || betaIndex == -1) {\n if (_getOperatorAvailableCount(index, vd) > 0) {\n if (alphaIndex == -1) {\n alphaIndex = int8(index);\n } else {\n betaIndex = int8(index);\n }\n }\n index = uint8((uint256(index) + skip) % prime);\n if (index == base && betaIndex == -1) {\n betaIndex = alphaIndex;\n }\n }\n return (uint8(int8(alphaIndex)), uint8(int8(betaIndex)));\n }\n\n function _depositOnThreeOrMoreOperators(\n address _withdrawer,\n uint256 _depositCount,\n uint256 _totalAvailableValidators,\n StakingContractStorageLib.OperatorsSlot storage _operators\n ) internal {\n uint256 operatorCount = _operators.value.length;\n uint8 optimusPrime = _getClosestPrimeAbove(uint8(operatorCount));\n bytes32 blockHash = blockhash(block.number - 1); // weak random number as it's not a security issue\n\n ValidatorAllocationCache[] memory vd = new ValidatorAllocationCache[](operatorCount);\n\n for (uint256 index; index < _depositCount; ) {\n // Retrieve base index and skip value based on block hash and current loop index\n (uint8 base, uint8 skip) = _getBaseSkip(blockHash, index, optimusPrime);\n // Retrieve two operator indexes pointing to two (or the same) operator(s) that have at least one available\n // validator key to be used for a deposit. This method takes into account possible pending deposits from\n // previous loop rounds.\n (uint8 alphaIndex, uint8 betaIndex) = _getElligibleOperators(base, skip, optimusPrime, vd);\n\n if (alphaIndex == betaIndex) {\n // Assign the deposit to the only operator having available keys\n _assignTemporaryDeposit(alphaIndex, vd);\n } else {\n // Assign the deposit to the operator having the lowest amount of funded keys\n _assignTemporaryDeposit(_getBestOperator(alphaIndex, betaIndex, blockHash, vd), vd);\n }\n\n unchecked {\n ++index;\n }\n }\n\n // Loop through the cached operator values and deposit any pending deposits\n for (uint256 index; index < vd.length; ) {\n if (vd[index].toDeposit > 0) {\n _depositValidatorsOfOperator(index, vd[index].toDeposit, _withdrawer);\n }\n unchecked {\n ++index;\n }\n }\n\n StakingContractStorageLib.setTotalAvailableValidators(_totalAvailableValidators - _depositCount);\n }\n\n function _deposit(address _withdrawer) internal {\n if (msg.value == 0 || msg.value % DEPOSIT_SIZE != 0) {\n revert InvalidDepositValue();\n }\n uint256 totalAvailableValidators = StakingContractStorageLib.getTotalAvailableValidators();\n uint256 depositCount = msg.value / DEPOSIT_SIZE;\n if (depositCount > totalAvailableValidators) {\n revert NotEnoughValidators();\n }\n StakingContractStorageLib.OperatorsSlot storage operators = StakingContractStorageLib.getOperators();\n if (operators.value.length == 0) {\n revert NoOperators();\n } else if (operators.value.length == 1) {\n _depositOnOneOperator(_withdrawer, depositCount, totalAvailableValidators);\n } else if (operators.value.length == 2) {\n _depositOnTwoOperators(_withdrawer, depositCount, totalAvailableValidators);\n } else {\n _depositOnThreeOrMoreOperators(_withdrawer, depositCount, totalAvailableValidators, operators);\n }\n }\n\n function _primes() internal pure returns (uint8[54] memory primes) {\n primes = [\n 2,\n 3,\n 5,\n 7,\n 11,\n 13,\n 17,\n 19,\n 23,\n 29,\n 31,\n 37,\n 41,\n 43,\n 47,\n 53,\n 59,\n 61,\n 67,\n 71,\n 73,\n 79,\n 83,\n 89,\n 97,\n 101,\n 103,\n 107,\n 109,\n 113,\n 127,\n 131,\n 137,\n 139,\n 149,\n 151,\n 157,\n 163,\n 167,\n 173,\n 179,\n 181,\n 191,\n 193,\n 197,\n 199,\n 211,\n 223,\n 227,\n 229,\n 233,\n 239,\n 241,\n 251\n ];\n }\n\n function _getClosestPrimeAbove(uint8 _count) internal pure returns (uint8) {\n uint8[54] memory primes = _primes();\n for (uint256 i; i < primes.length; ) {\n if (primes[i] >= _count) {\n return primes[i];\n }\n unchecked {\n ++i;\n }\n }\n revert InvalidValidatorCount();\n }\n\n function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {\n if (_a < _b) {\n return _a;\n }\n return _b;\n }\n\n /// @notice Internal utility to compute the receiver deterministic address\n /// @param _publicKey Public Key assigned to the receiver\n /// @param _prefix Prefix used to generate multiple receivers per public key\n function _getDeterministicReceiver(bytes memory _publicKey, uint256 _prefix) internal view returns (address) {\n bytes32 publicKeyRoot = _getPubKeyRoot(_publicKey);\n bytes32 salt = sha256(abi.encodePacked(_prefix, publicKeyRoot));\n address implementation = StakingContractStorageLib.getFeeRecipientImplementation();\n return Clones.predictDeterministicAddress(implementation, salt);\n }\n\n /// @notice Internal utility to deploy and withdraw the fees from a receiver\n /// @param _publicKey Public Key assigned to the receiver\n /// @param _prefix Prefix used to generate multiple receivers per public key\n /// @param _dispatcher Address of the dispatcher contract\n function _deployAndWithdraw(\n bytes calldata _publicKey,\n uint256 _prefix,\n address _dispatcher\n ) internal {\n bytes32 publicKeyRoot = _getPubKeyRoot(_publicKey);\n bytes32 feeRecipientSalt = sha256(abi.encodePacked(_prefix, publicKeyRoot));\n address implementation = StakingContractStorageLib.getFeeRecipientImplementation();\n address feeRecipientAddress = Clones.predictDeterministicAddress(implementation, feeRecipientSalt);\n if (feeRecipientAddress.code.length == 0) {\n Clones.cloneDeterministic(implementation, feeRecipientSalt);\n IFeeRecipient(feeRecipientAddress).init(_dispatcher, publicKeyRoot);\n }\n IFeeRecipient(feeRecipientAddress).withdraw();\n }\n}\n" + }, + "src/contracts/libs/UintLib.sol": { + "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\nlibrary Uint256Lib {\n function toLittleEndian64(uint256 _value) internal pure returns (uint256 result) {\n result = 0;\n uint256 temp_value = _value;\n for (uint256 i = 0; i < 8; ++i) {\n result = (result << 8) | (temp_value & 0xFF);\n temp_value >>= 8;\n }\n\n assert(0 == temp_value); // fully converted\n result <<= (24 * 8);\n }\n}\n" + }, + "src/contracts/libs/BytesLib.sol": { + "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\nlibrary BytesLib {\n function pad64(bytes memory _b) internal pure returns (bytes memory) {\n assert(_b.length >= 32 && _b.length <= 64);\n if (64 == _b.length) {\n return _b;\n }\n\n bytes memory zero32 = new bytes(32);\n assembly {\n mstore(add(zero32, 0x20), 0)\n }\n\n if (32 == _b.length) {\n return BytesLib.concat(_b, zero32);\n } else {\n return BytesLib.concat(_b, BytesLib.slice(zero32, 0, uint256(64) - _b.length));\n }\n }\n\n function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(\n 0x40,\n and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n )\n )\n }\n\n return tempBytes;\n }\n\n function slice(\n bytes memory _bytes,\n uint256 _start,\n uint256 _length\n ) internal pure returns (bytes memory) {\n require(_length + 31 >= _length, \"slice_overflow\");\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n}\n" + }, + "src/contracts/interfaces/IFeeRecipient.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\ninterface IFeeRecipient {\n function init(address _dispatcher, bytes32 _publicKeyRoot) external;\n\n function withdraw() external;\n}\n" + }, + "src/contracts/libs/StakingContractStorageLib.sol": { + "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.10;\n\nlibrary StakingContractStorageLib {\n function getUint256(bytes32 position) internal view returns (uint256 data) {\n assembly {\n data := sload(position)\n }\n }\n\n function setUint256(bytes32 position, uint256 data) internal {\n assembly {\n sstore(position, data)\n }\n }\n\n function getAddress(bytes32 position) internal view returns (address data) {\n assembly {\n data := sload(position)\n }\n }\n\n function setAddress(bytes32 position, address data) internal {\n assembly {\n sstore(position, data)\n }\n }\n\n function getBool(bytes32 position) internal view returns (bool data) {\n assembly {\n data := sload(position)\n }\n }\n\n function setBool(bytes32 position, bool data) internal {\n assembly {\n sstore(position, data)\n }\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant VERSION_SLOT = keccak256(\"StakingContract.version\");\n\n function getVersion() internal view returns (uint256) {\n return getUint256(VERSION_SLOT);\n }\n\n function setVersion(uint256 _newVersion) internal {\n setUint256(VERSION_SLOT, _newVersion);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant ADMIN_SLOT = keccak256(\"StakingContract.admin\");\n bytes32 internal constant PENDING_ADMIN_SLOT = keccak256(\"StakingContract.pendingAdmin\");\n\n function getAdmin() internal view returns (address) {\n return getAddress(ADMIN_SLOT);\n }\n\n function setAdmin(address _newAdmin) internal {\n setAddress(ADMIN_SLOT, _newAdmin);\n }\n\n function getPendingAdmin() internal view returns (address) {\n return getAddress(PENDING_ADMIN_SLOT);\n }\n\n function setPendingAdmin(address _newPendingAdmin) internal {\n setAddress(PENDING_ADMIN_SLOT, _newPendingAdmin);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant TREASURY_SLOT = keccak256(\"StakingContract.treasury\");\n\n function getTreasury() internal view returns (address) {\n return getAddress(TREASURY_SLOT);\n }\n\n function setTreasury(address _newTreasury) internal {\n setAddress(TREASURY_SLOT, _newTreasury);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant DEPOSIT_CONTRACT_SLOT = keccak256(\"StakingContract.depositContract\");\n\n function getDepositContract() internal view returns (address) {\n return getAddress(DEPOSIT_CONTRACT_SLOT);\n }\n\n function setDepositContract(address _newDepositContract) internal {\n setAddress(DEPOSIT_CONTRACT_SLOT, _newDepositContract);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant OPERATORS_SLOT = keccak256(\"StakingContract.operators\");\n\n struct OperatorInfo {\n address operator;\n address feeRecipient;\n uint256 limit;\n bytes[] publicKeys;\n bytes[] signatures;\n bool deactivated;\n }\n\n struct OperatorsSlot {\n OperatorInfo[] value;\n }\n\n function getOperators() internal pure returns (OperatorsSlot storage p) {\n bytes32 slot = OPERATORS_SLOT;\n assembly {\n p.slot := slot\n }\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant VALIDATORS_FUNDING_INFO_SLOT = keccak256(\"StakingContract.validatorsFundingInfo\");\n\n struct ValidatorsFundingInfo {\n uint32 availableKeys;\n uint32 funded;\n }\n\n struct UintToUintMappingSlot {\n mapping(uint256 => uint256) value;\n }\n\n function getValidatorsFundingInfo(uint256 _index) internal view returns (ValidatorsFundingInfo memory vfi) {\n UintToUintMappingSlot storage p;\n bytes32 slot = VALIDATORS_FUNDING_INFO_SLOT;\n\n assembly {\n p.slot := slot\n }\n\n uint256 slotIndex = _index >> 2;\n uint256 innerIndex = (_index & 3) << 6;\n uint256 value = p.value[slotIndex] >> innerIndex;\n vfi.availableKeys = uint32(value);\n vfi.funded = uint32(value >> 32);\n }\n\n function setValidatorsFundingInfo(\n uint256 _index,\n uint32 _availableKeys,\n uint32 _funded\n ) internal {\n UintToUintMappingSlot storage p;\n bytes32 slot = VALIDATORS_FUNDING_INFO_SLOT;\n\n assembly {\n p.slot := slot\n }\n\n uint256 slotIndex = _index >> 2;\n uint256 innerIndex = (_index & 3) << 6;\n p.value[slotIndex] =\n (p.value[slotIndex] & (~(uint256(0xFFFFFFFFFFFFFFFF) << innerIndex))) |\n ((uint256(_availableKeys) | (uint256(_funded) << 32)) << innerIndex);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant TOTAL_AVAILABLE_VALIDATORS_SLOT = keccak256(\"StakingContract.totalAvailableValidators\");\n\n function getTotalAvailableValidators() internal view returns (uint256) {\n return getUint256(TOTAL_AVAILABLE_VALIDATORS_SLOT);\n }\n\n function setTotalAvailableValidators(uint256 _newTotal) internal {\n setUint256(TOTAL_AVAILABLE_VALIDATORS_SLOT, _newTotal);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant WITHDRAWERS_SLOT = keccak256(\"StakingContract.withdrawers\");\n\n struct WithdrawersSlot {\n mapping(bytes32 => address) value;\n }\n\n function getWithdrawers() internal pure returns (WithdrawersSlot storage p) {\n bytes32 slot = WITHDRAWERS_SLOT;\n assembly {\n p.slot := slot\n }\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n struct OperatorIndex {\n bool enabled;\n uint32 operatorIndex;\n }\n\n struct OperatorIndexPerValidatorSlot {\n mapping(bytes32 => OperatorIndex) value;\n }\n\n bytes32 internal constant OPERATOR_INDEX_PER_VALIDATOR_SLOT =\n keccak256(\"StakingContract.operatorIndexPerValidator\");\n\n function getOperatorIndexPerValidator() internal pure returns (OperatorIndexPerValidatorSlot storage p) {\n bytes32 slot = OPERATOR_INDEX_PER_VALIDATOR_SLOT;\n assembly {\n p.slot := slot\n }\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant GLOBAL_FEE_SLOT = keccak256(\"StakingContract.globalFee\");\n\n function getGlobalFee() internal view returns (uint256) {\n return getUint256(GLOBAL_FEE_SLOT);\n }\n\n function setGlobalFee(uint256 _newTreasuryFee) internal {\n setUint256(GLOBAL_FEE_SLOT, _newTreasuryFee);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant OPERATOR_FEE_SLOT = keccak256(\"StakingContract.operatorFee\");\n\n function getOperatorFee() internal view returns (uint256) {\n return getUint256(OPERATOR_FEE_SLOT);\n }\n\n function setOperatorFee(uint256 _newOperatorFee) internal {\n setUint256(OPERATOR_FEE_SLOT, _newOperatorFee);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant EL_DISPATCHER_SLOT = keccak256(\"StakingContract.executionLayerDispatcher\");\n\n function getELDispatcher() internal view returns (address) {\n return getAddress(EL_DISPATCHER_SLOT);\n }\n\n function setELDispatcher(address _newElDispatcher) internal {\n setAddress(EL_DISPATCHER_SLOT, _newElDispatcher);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant CL_DISPATCHER_SLOT = keccak256(\"StakingContract.consensusLayerDispatcher\");\n\n function getCLDispatcher() internal view returns (address) {\n return getAddress(CL_DISPATCHER_SLOT);\n }\n\n function setCLDispatcher(address _newClDispatcher) internal {\n setAddress(CL_DISPATCHER_SLOT, _newClDispatcher);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant FEE_RECIPIENT_IMPLEMENTATION_SLOT =\n keccak256(\"StakingContract.feeRecipientImplementation\");\n\n function getFeeRecipientImplementation() internal view returns (address) {\n return getAddress(FEE_RECIPIENT_IMPLEMENTATION_SLOT);\n }\n\n function setFeeRecipientImplementation(address _newFeeRecipientImplementation) internal {\n setAddress(FEE_RECIPIENT_IMPLEMENTATION_SLOT, _newFeeRecipientImplementation);\n }\n\n /* ========================================\n ===========================================\n =========================================*/\n\n bytes32 internal constant WITHDRAWER_CUSTOMIZATION_ENABLED_SLOT =\n keccak256(\"StakingContract.withdrawerCustomizationEnabled\");\n\n function getWithdrawerCustomizationEnabled() internal view returns (bool) {\n return getBool(WITHDRAWER_CUSTOMIZATION_ENABLED_SLOT);\n }\n\n function setWithdrawerCustomizationEnabled(bool _enabled) internal {\n setBool(WITHDRAWER_CUSTOMIZATION_ENABLED_SLOT, _enabled);\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Clones.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create(0, ptr, 0x37)\n }\n require(instance != address(0), \"ERC1167: create failed\");\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create2(0, ptr, 0x37, salt)\n }\n require(instance != address(0), \"ERC1167: create2 failed\");\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\n mstore(add(ptr, 0x38), shl(0x60, deployer))\n mstore(add(ptr, 0x4c), salt)\n mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\n predicted := keccak256(add(ptr, 0x37), 0x55)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(address implementation, bytes32 salt)\n internal\n view\n returns (address predicted)\n {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates", + "devdoc", + "userdoc" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file