@keep-network/tbtc-v2 1.8.0-dev.0 → 1.8.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/artifacts/BLS.json +6 -6
  2. package/artifacts/Bank.json +11 -11
  3. package/artifacts/BeaconAuthorization.json +11 -11
  4. package/artifacts/BeaconDkg.json +9 -9
  5. package/artifacts/BeaconDkgValidator.json +12 -12
  6. package/artifacts/BeaconInactivity.json +11 -11
  7. package/artifacts/BeaconSortitionPool.json +16 -16
  8. package/artifacts/Bridge.json +32 -32
  9. package/artifacts/BridgeGovernance.json +14 -14
  10. package/artifacts/BridgeGovernanceParameters.json +6 -6
  11. package/artifacts/Deposit.json +6 -6
  12. package/artifacts/DepositSweep.json +6 -6
  13. package/artifacts/DonationVault.json +7 -7
  14. package/artifacts/EcdsaDkgValidator.json +7 -7
  15. package/artifacts/EcdsaInactivity.json +6 -6
  16. package/artifacts/EcdsaSortitionPool.json +16 -16
  17. package/artifacts/Fraud.json +6 -6
  18. package/artifacts/LightRelay.json +11 -11
  19. package/artifacts/LightRelayMaintainerProxy.json +13 -13
  20. package/artifacts/MaintainerProxy.json +13 -13
  21. package/artifacts/MovingFunds.json +6 -6
  22. package/artifacts/NuCypherToken.json +11 -11
  23. package/artifacts/RandomBeacon.json +126 -126
  24. package/artifacts/RandomBeaconChaosnet.json +13 -13
  25. package/artifacts/RandomBeaconGovernance.json +66 -66
  26. package/artifacts/Redemption.json +6 -6
  27. package/artifacts/RedemptionWatchtower.json +26 -26
  28. package/artifacts/ReimbursementPool.json +19 -19
  29. package/artifacts/T.json +11 -11
  30. package/artifacts/TBTC.json +11 -11
  31. package/artifacts/TBTCToken.json +11 -11
  32. package/artifacts/TBTCVault.json +14 -14
  33. package/artifacts/Timelock.json +80 -80
  34. package/artifacts/TokenStaking.json +156 -308
  35. package/artifacts/TokenholderGovernor.json +47 -47
  36. package/artifacts/TokenholderTimelock.json +36 -36
  37. package/artifacts/VendingMachine.json +13 -13
  38. package/artifacts/VendingMachineNuCypher.json +9 -9
  39. package/artifacts/VendingMachineV2.json +13 -13
  40. package/artifacts/VendingMachineV3.json +13 -13
  41. package/artifacts/WalletProposalValidator.json +7 -7
  42. package/artifacts/WalletRegistry.json +31 -31
  43. package/artifacts/WalletRegistryGovernance.json +56 -56
  44. package/artifacts/Wallets.json +6 -6
  45. package/export/artifacts/@keep-network/ecdsa/contracts/WalletRegistry.sol/WalletRegistry.json +4999 -4814
  46. package/export/typechain/factories/EcdsaAuthorization__factory.js +1 -1
  47. package/export/typechain/factories/IStaking__factory.js +24 -103
  48. package/export/typechain/factories/WalletRegistry__factory.js +1 -1
  49. package/package.json +4 -4
  50. package/artifacts/KeepRegistry.json +0 -99
  51. package/artifacts/KeepStake.json +0 -286
  52. package/artifacts/KeepToken.json +0 -711
  53. package/artifacts/KeepTokenStaking.json +0 -483
  54. package/artifacts/NuCypherStakingEscrow.json +0 -287
  55. package/artifacts/VendingMachineKeep.json +0 -400
@@ -1,5 +1,5 @@
1
1
  {
2
- "address": "0x677df0cb865368207999F2862Ece576dC56D8dF6",
2
+ "address": "0x85C5Dd61585773423e378146D4bEC6f8D149E248",
3
3
  "abi": [
4
4
  {
5
5
  "inputs": [],
@@ -89,27 +89,27 @@
89
89
  "type": "function"
90
90
  }
91
91
  ],
92
- "transactionHash": "0x703deff229f2851163471c5f06af45f53db3b9b2a89bd9d1ccee60a8620e5359",
92
+ "transactionHash": "0xb57cb15b604fd8678338635f72ebd05cfafc099429b53e32a036ba0098e19200",
93
93
  "receipt": {
94
94
  "to": null,
95
95
  "from": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
96
- "contractAddress": "0x677df0cb865368207999F2862Ece576dC56D8dF6",
96
+ "contractAddress": "0x85C5Dd61585773423e378146D4bEC6f8D149E248",
97
97
  "transactionIndex": 0,
98
- "gasUsed": "938214",
98
+ "gasUsed": "970416",
99
99
  "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
100
- "blockHash": "0xec9a07e6f5630da3dfa36817a3a51a1464200fd71c5cdb3cb10f84f97c9e8e1d",
101
- "transactionHash": "0x703deff229f2851163471c5f06af45f53db3b9b2a89bd9d1ccee60a8620e5359",
100
+ "blockHash": "0x10bb4c0d8e7dde6a0b91e8bb50591b94be197b79af0f23d8f124add183f6a4bf",
101
+ "transactionHash": "0xb57cb15b604fd8678338635f72ebd05cfafc099429b53e32a036ba0098e19200",
102
102
  "logs": [],
103
- "blockNumber": 29,
104
- "cumulativeGasUsed": "938214",
103
+ "blockNumber": 20,
104
+ "cumulativeGasUsed": "970416",
105
105
  "status": 1,
106
106
  "byzantium": true
107
107
  },
108
108
  "args": [],
109
109
  "numDeployments": 1,
110
- "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"groupThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"signatureByteSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"sortitionPool\",\"type\":\"SortitionPool\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"internalType\":\"uint256[]\",\"name\":\"inactiveMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"}],\"internalType\":\"struct BeaconInactivity.Claim\",\"name\":\"claim\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"verifyClaim\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"inactiveMembers\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"verifyClaim(SortitionPool,BeaconInactivity.Claim,bytes,uint256,uint32[])\":{\"details\":\"Group members hash is validated upstream in RandomBeacon.notifyOperatorInactivity()\",\"params\":{\"claim\":\"Inactivity claim\",\"groupMembers\":\"Identifiers of group members\",\"groupPubKey\":\"Public key of the group raising the claim\",\"nonce\":\"Current nonce for group used in the claim\",\"sortitionPool\":\"Sortition pool reference\"},\"returns\":{\"inactiveMembers\":\"Identifiers of members who are inactive\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"groupThreshold()\":{\"notice\":\"The minimum number of group members needed to interact according to the protocol to produce a valid inactivity claim.\"},\"signatureByteSize()\":{\"notice\":\"Size in bytes of a single signature produced by member supporting the inactivity claim.\"},\"verifyClaim(SortitionPool,BeaconInactivity.Claim,bytes,uint256,uint32[])\":{\"notice\":\"Verifies the inactivity claim according to the rules defined in `Claim` struct documentation. Reverts if verification fails.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libraries/BeaconInactivity.sol\":\"BeaconInactivity\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./math/Math.sol\\\";\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n uint256 length = Math.log10(value) + 1;\\n string memory buffer = new string(length);\\n uint256 ptr;\\n /// @solidity memory-safe-assembly\\n assembly {\\n ptr := add(buffer, add(32, length))\\n }\\n while (true) {\\n ptr--;\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\\n }\\n value /= 10;\\n if (value == 0) break;\\n }\\n return buffer;\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n return toHexString(value, Math.log256(value) + 1);\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xa4d1d62251f8574deb032a35fc948386a9b4de74b812d4f545a1ac120486b48a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV // Deprecated in v4.8\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xda898fa084aa1ddfdb346e6a40459e00a59d87071cce7c315a46d648dd71d0ba\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa1e8e83cd0087785df04ac79fb395d9f3684caeaf973d9e2c71caef723a3a5d6\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"},\"contracts/libraries/BeaconInactivity.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./BytesLib.sol\\\";\\nimport \\\"./Groups.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\n\\nlibrary BeaconInactivity {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Claim {\\n // ID of the group raising the inactivity claim.\\n uint64 groupId;\\n // Indices of members accused of being inactive. Indices must be in\\n // range [1, groupMembers.length], unique, and sorted in ascending order.\\n uint256[] inactiveMembersIndices;\\n // Concatenation of signatures from members supporting the claim.\\n // The message to be signed by each member is keccak256 hash of the\\n // concatenation of the chain ID, inactivity claim nonce for the given\\n // group, group public key, and inactive members indices. The calculated\\n // hash should be prefixed with `\\\\x19Ethereum signed message:\\\\n` before\\n // signing, so the message to sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // chainID | nonce | groupPubKey | inactiveMembersIndices\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // in range [1, groupMembers.length], unique, and sorted in ascending\\n // order.\\n uint256[] signingMembersIndices;\\n }\\n\\n /// @notice The minimum number of group members needed to interact according\\n /// to the protocol to produce a valid inactivity claim.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @notice Size in bytes of a single signature produced by member\\n /// supporting the inactivity claim.\\n uint256 public constant signatureByteSize = 65;\\n\\n /// @notice Verifies the inactivity claim according to the rules defined in\\n /// `Claim` struct documentation. Reverts if verification fails.\\n /// @dev Group members hash is validated upstream in\\n /// RandomBeacon.notifyOperatorInactivity()\\n /// @param sortitionPool Sortition pool reference\\n /// @param claim Inactivity claim\\n /// @param groupPubKey Public key of the group raising the claim\\n /// @param nonce Current nonce for group used in the claim\\n /// @param groupMembers Identifiers of group members\\n /// @return inactiveMembers Identifiers of members who are inactive\\n function verifyClaim(\\n SortitionPool sortitionPool,\\n Claim calldata claim,\\n bytes memory groupPubKey,\\n uint256 nonce,\\n uint32[] calldata groupMembers\\n ) external view returns (uint32[] memory inactiveMembers) {\\n // Validate inactive members indices. Maximum indices count is equal to\\n // the group size and is not limited deliberately to leave a theoretical\\n // possibility to accuse more members than `groupSize - groupThreshold`.\\n validateMembersIndices(\\n claim.inactiveMembersIndices,\\n groupMembers.length\\n );\\n\\n // Validate signatures array is properly formed and number of\\n // signatures and signers is correct.\\n uint256 signaturesCount = claim.signatures.length / signatureByteSize;\\n require(claim.signatures.length != 0, \\\"No signatures provided\\\");\\n require(\\n claim.signatures.length % signatureByteSize == 0,\\n \\\"Malformed signatures array\\\"\\n );\\n require(\\n signaturesCount == claim.signingMembersIndices.length,\\n \\\"Unexpected signatures count\\\"\\n );\\n require(signaturesCount >= groupThreshold, \\\"Too few signatures\\\");\\n require(signaturesCount <= groupMembers.length, \\\"Too many signatures\\\");\\n\\n // Validate signing members indices. Note that `signingMembersIndices`\\n // were already partially validated during `signatures` parameter\\n // validation.\\n validateMembersIndices(\\n claim.signingMembersIndices,\\n groupMembers.length\\n );\\n\\n // Usage of group public key and not group ID is important because it\\n // provides uniqueness of signed messages and prevent against reusing\\n // them in future in case some other application has a group with the\\n // same ID and subset of members.\\n bytes32 signedMessageHash = keccak256(\\n abi.encode(\\n block.chainid,\\n nonce,\\n groupPubKey,\\n claim.inactiveMembersIndices\\n )\\n ).toEthSignedMessageHash();\\n\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n // Verify each signature.\\n bytes memory checkedSignature;\\n bool senderSignatureExists = false;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n uint256 memberIndex = claim.signingMembersIndices[i];\\n checkedSignature = claim.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = signedMessageHash.recover(\\n checkedSignature\\n );\\n\\n require(\\n groupMembersAddresses[memberIndex - 1] == recoveredAddress,\\n \\\"Invalid signature\\\"\\n );\\n\\n if (!senderSignatureExists && msg.sender == recoveredAddress) {\\n senderSignatureExists = true;\\n }\\n }\\n\\n require(senderSignatureExists, \\\"Sender must be claim signer\\\");\\n\\n inactiveMembers = new uint32[](claim.inactiveMembersIndices.length);\\n for (uint256 i = 0; i < claim.inactiveMembersIndices.length; i++) {\\n uint256 memberIndex = claim.inactiveMembersIndices[i];\\n inactiveMembers[i] = groupMembers[memberIndex - 1];\\n }\\n\\n return inactiveMembers;\\n }\\n\\n /// @notice Validates members indices array. Array is considered valid\\n /// if its size and each single index are in [1, groupSize] range,\\n /// indexes are unique, and sorted in an ascending order.\\n /// Reverts if validation fails.\\n /// @param indices Array to validate\\n /// @param groupSize Group size used as reference\\n function validateMembersIndices(\\n uint256[] calldata indices,\\n uint256 groupSize\\n ) internal pure {\\n require(\\n indices.length > 0 && indices.length <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n // Check if first and last indices are in range [1, groupSize].\\n // This check combined with the loop below makes sure every single\\n // index is in the correct range.\\n require(\\n indices[0] > 0 && indices[indices.length - 1] <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n for (uint256 i = 0; i < indices.length - 1; i++) {\\n // Check whether given index is smaller than the next one. This\\n // way we are sure indexes are ordered in the ascending order\\n // and there are no duplicates.\\n require(indices[i] < indices[i + 1], \\\"Corrupted members indices\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8dffb20eb4ffd2e388080c5fbcb648e33480aca3dab4be2254cf30c5e72413bf\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BytesLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/*\\nVersion pulled from keep-core v1:\\nhttps://github.com/keep-network/keep-core/blob/f297202db00c027978ad8e7103a356503de5773c/solidity-v1/contracts/utils/BytesLib.sol\\n\\nTo compile it with solidity 0.8 `_preBytes_slot` was replaced with `_preBytes.slot`.\\n*/\\n\\n/*\\nhttps://github.com/GNSPS/solidity-bytes-utils/\\nThis is free and unencumbered software released into the public domain.\\nAnyone is free to copy, modify, publish, use, compile, sell, or\\ndistribute this software, either in source code form or as a compiled\\nbinary, for any purpose, commercial or non-commercial, and by any\\nmeans.\\nIn jurisdictions that recognize copyright laws, the author or authors\\nof this software dedicate any and all copyright interest in the\\nsoftware to the public domain. We make this dedication for the benefit\\nof the public at large and to the detriment of our heirs and\\nsuccessors. We intend this dedication to be an overt act of\\nrelinquishment in perpetuity of all present and future rights to this\\nsoftware under copyright law.\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND,\\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\\nOTHER DEALINGS IN THE SOFTWARE.\\nFor more information, please refer to <https://unlicense.org>\\n*/\\n\\n/** @title BytesLib **/\\n/** @author https://github.com/GNSPS **/\\n\\nlibrary BytesLib {\\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n {\\n assembly {\\n // Read the first 32 bytes of _preBytes storage, which is the length\\n // of the array. (We don't need to use the offset into the slot\\n // because arrays use the entire slot.)\\n let fslot := sload(_preBytes.slot)\\n // Arrays of 31 bytes or less have an even value in their slot,\\n // while longer arrays have an odd value. The actual length is\\n // the slot divided by two for odd values, and the lowest order\\n // byte divided by two for even values.\\n // If the slot is even, bitwise and the slot with 255 and divide by\\n // two to get the length. If the slot is odd, bitwise and the slot\\n // with -1 and divide by two.\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n let newlength := add(slength, mlength)\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n switch add(lt(slength, 32), lt(newlength, 32))\\n case 2 {\\n // Since the new array still fits in the slot, we just need to\\n // update the contents of the slot.\\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\\n sstore(\\n _preBytes.slot,\\n // all the modifications to the slot are inside this\\n // next block\\n add(\\n // we can just add to the slot contents because the\\n // bytes we want to change are the LSBs\\n fslot,\\n add(\\n mul(\\n div(\\n // load the bytes from memory\\n mload(add(_postBytes, 0x20)),\\n // zero all bytes to the right\\n exp(0x100, sub(32, mlength))\\n ),\\n // and now shift left the number of bytes to\\n // leave space for the length in the slot\\n exp(0x100, sub(32, newlength))\\n ),\\n // increase length by the double of the memory\\n // bytes length\\n mul(mlength, 2)\\n )\\n )\\n )\\n }\\n case 1 {\\n // The stored value fits in the slot, but the combined value\\n // will exceed it.\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // The contents of the _postBytes array start 32 bytes into\\n // the structure. Our first read should obtain the `submod`\\n // bytes that can fit into the unused space in the last word\\n // of the stored array. To get this, we read 32 bytes starting\\n // from `submod`, so the data we read overlaps with the array\\n // contents by `submod` bytes. Masking the lowest-order\\n // `submod` bytes allows us to add that value directly to the\\n // stored value.\\n\\n let submod := sub(32, slength)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(\\n sc,\\n add(\\n and(\\n fslot,\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\\n ),\\n and(mload(mc), mask)\\n )\\n )\\n\\n for {\\n mc := add(mc, 0x20)\\n sc := add(sc, 1)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n default {\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n // Start copying to the last used word of the stored array.\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // Copy over the first `submod` bytes of the new data as in\\n // case 1 above.\\n let slengthmod := mod(slength, 32)\\n let submod := sub(32, slengthmod)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\\n\\n for {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n }\\n }\\n\\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n view\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n // we know _preBytes_offset is 0\\n let fslot := sload(_preBytes.slot)\\n // Decode the length of the stored array like in concatStorage().\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(slength, mlength)\\n case 1 {\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n if iszero(iszero(slength)) {\\n switch lt(slength, 32)\\n case 1 {\\n // blank the last byte which is the length\\n fslot := mul(div(fslot, 0x100), 0x100)\\n\\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\\n // unsuccess:\\n success := 0\\n }\\n }\\n default {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := keccak256(0x0, 0x20)\\n\\n let mc := add(_postBytes, 0x20)\\n let end := add(mc, mlength)\\n\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n for {\\n\\n } eq(add(lt(mc, end), cb), 2) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n if iszero(eq(sload(sc), mload(mc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bytes memory)\\n {\\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 res) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n // Alloc bytes array with additional 32 bytes afterspace and assign it's size\\n res := mload(0x40)\\n mstore(0x40, add(add(res, 64), _length))\\n mstore(res, _length)\\n\\n // Compute distance between source and destination pointers\\n let diff := sub(res, add(_bytes, _start))\\n\\n for {\\n let src := add(add(_bytes, 32), _start)\\n let end := add(src, _length)\\n } lt(src, end) {\\n src := add(src, 32)\\n } {\\n mstore(add(src, diff), mload(src))\\n }\\n }\\n }\\n\\n function toAddress(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (address)\\n {\\n uint256 _totalLen = _start + 20;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Address conversion out of bounds.\\\"\\n );\\n address tempAddress;\\n\\n assembly {\\n tempAddress := div(\\n mload(add(add(_bytes, 0x20), _start)),\\n 0x1000000000000000000000000\\n )\\n }\\n\\n return tempAddress;\\n }\\n\\n function toUint8(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint8)\\n {\\n require(\\n _bytes.length >= (_start + 1),\\n \\\"Uint8 conversion out of bounds.\\\"\\n );\\n uint8 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x1), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function toUint(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint256)\\n {\\n uint256 _totalLen = _start + 32;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Uint conversion out of bounds.\\\"\\n );\\n uint256 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x20), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function equal(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n let length := mload(_preBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(length, mload(_postBytes))\\n case 1 {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n let mc := add(_preBytes, 0x20)\\n let end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n } eq(add(lt(mc, end), cb), 2) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // if any of these checks fails then arrays are not equal\\n if iszero(eq(mload(mc), mload(cc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function toBytes32(bytes memory _source)\\n internal\\n pure\\n returns (bytes32 result)\\n {\\n if (_source.length == 0) {\\n return 0x0;\\n }\\n\\n assembly {\\n result := mload(add(_source, 32))\\n }\\n }\\n\\n function keccak256Slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes32 result) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n result := keccak256(add(add(_bytes, 32), _start), _length)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b76e2fe36eb777440250dcf2ea7a689375e8af22f3cc33521095ff6954becdb\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Groups.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/// @notice This library is used as a registry of created groups.\\n/// @dev This library should be used along with DKG library that ensures linear\\n/// groups creation (only one group creation happens at a time). A candidate\\n/// group has to be popped or activated before adding a new candidate group.\\nlibrary Groups {\\n struct Group {\\n bytes groupPubKey;\\n uint256 registrationBlockNumber;\\n // Keccak256 hash of group members identifiers array. Group members do not\\n // include operators selected by the sortition pool that misbehaved during DKG.\\n // See how `misbehavedMembersIndices` are used in `hashGroupMembers` function.\\n bytes32 membersHash;\\n // When selected group does not create a relay entry on-time it should\\n // be marked as terminated.\\n bool terminated;\\n }\\n\\n struct Data {\\n // Mapping of keccak256 hashes of group public keys to groups details.\\n mapping(bytes32 => Group) groupsData;\\n // Holds keccak256 hashes of group public keys in the order of registration.\\n bytes32[] groupsRegistry;\\n // Group ids that were active but failed creating a relay entry. When an\\n // active-terminated group qualifies to become 'expired', then it will\\n // be removed from this array.\\n uint64[] activeTerminatedGroups;\\n // Points to the first active group, it is also the expired groups counter.\\n uint64 expiredGroupOffset;\\n // Group lifetime in blocks. When a group reached its lifetime, it\\n // is no longer selected for new relay requests but may still be\\n // responsible for submitting relay entry if relay request assigned\\n // to that group is still pending.\\n uint256 groupLifetime;\\n }\\n\\n event GroupRegistered(uint64 indexed groupId, bytes indexed groupPubKey);\\n\\n /// @notice Performs preliminary validation of a new group public key.\\n /// The group public key must be unique and have 128 bytes in length.\\n /// If the validation fails, the function reverts. This function\\n /// must be called first for a public key of a group added with\\n /// `addGroup` function.\\n /// @param groupPubKey Candidate group public key\\n function validatePublicKey(Data storage self, bytes calldata groupPubKey)\\n internal\\n view\\n {\\n require(groupPubKey.length == 128, \\\"Invalid length of the public key\\\");\\n\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n require(\\n self.groupsData[groupPubKeyHash].registrationBlockNumber == 0,\\n \\\"Group with this public key was already registered\\\"\\n );\\n }\\n\\n /// @notice Adds a new candidate group. The group is stored with group public\\n /// key and group members, but is not yet activated.\\n /// @dev The group members list is stored with all misbehaved members filtered out.\\n /// The code calling this function should ensure that the number of\\n /// candidate (not activated) groups is never more than one.\\n /// @param groupPubKey Generated candidate group public key\\n /// @param membersHash Keccak256 hash of members that actively took part in DKG.\\n function addGroup(\\n Data storage self,\\n bytes calldata groupPubKey,\\n bytes32 membersHash\\n ) internal {\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n // We use group from storage that is assumed to be a struct set to the\\n // default values. We need to remember to overwrite fields in case a\\n // candidate group was already registered before and popped.\\n Group storage group = self.groupsData[groupPubKeyHash];\\n group.groupPubKey = groupPubKey;\\n group.membersHash = membersHash;\\n group.registrationBlockNumber = block.number;\\n\\n self.groupsRegistry.push(groupPubKeyHash);\\n\\n emit GroupRegistered(\\n uint64(self.groupsRegistry.length - 1),\\n groupPubKey\\n );\\n }\\n\\n /// @notice Goes through groups starting from the oldest one that is still\\n /// active and checks if it hasn't expired. If so, updates the information\\n /// about expired groups so that all expired groups are marked as such.\\n function expireOldGroups(Data storage self) internal {\\n // Move expiredGroupOffset as long as there are some groups that should\\n // be marked as expired. It is possible that expired group offset will\\n // move out of the groups array by one position. It means that all groups\\n // are expired (it points to the first active group) and that place in\\n // groups array - currently empty - will be possibly filled later by\\n // a new group.\\n while (\\n self.expiredGroupOffset < self.groupsRegistry.length &&\\n groupLifetimeOf(\\n self,\\n self.groupsRegistry[self.expiredGroupOffset]\\n ) <\\n block.number\\n ) {\\n self.expiredGroupOffset++;\\n }\\n\\n // Go through all activeTerminatedGroups and if some of the terminated\\n // groups are expired, remove them from activeTerminatedGroups collection\\n // and rearrange the array to preserve the original order.\\n // This is needed because we evaluate the shift of selected group index\\n // based on how many non-expired groups have been terminated. Hence it is\\n // important that a number of terminated groups matches the length of\\n // activeTerminatedGroups[].\\n uint256 i = 0;\\n while (i < self.activeTerminatedGroups.length) {\\n if (self.expiredGroupOffset > self.activeTerminatedGroups[i]) {\\n // When 'i'th group qualifies for expiration, we need to remove\\n // it from the activeTerminatedGroups array manually by rearranging\\n // the order starting from 'i'th group.\\n for (\\n uint256 j = i;\\n j < self.activeTerminatedGroups.length - 1;\\n j++\\n ) {\\n self.activeTerminatedGroups[j] = self\\n .activeTerminatedGroups[j + 1];\\n }\\n // Resizing the array length by 1. The last element was copied\\n // over in the loop above to an index \\\"second to last\\\". This is\\n // why we can safely remove it from here.\\n self.activeTerminatedGroups.pop();\\n } else {\\n i++;\\n }\\n }\\n }\\n\\n /// @notice Terminates group with the provided index. Reverts if the group\\n /// is already terminated.\\n /// @param groupId Index in the groupRegistry array.\\n function terminateGroup(Data storage self, uint64 groupId) internal {\\n require(\\n !isGroupTerminated(self, groupId),\\n \\\"Group has been already terminated\\\"\\n );\\n self.groupsData[self.groupsRegistry[groupId]].terminated = true;\\n // Expanding array for a new terminated group that is added below during\\n // sortition in ascending order.\\n self.activeTerminatedGroups.push();\\n\\n // Sorting activeTerminatedGroups by groupId in ascending order so a\\n // non-terminated group is properly selected.\\n uint256 i;\\n for (\\n i = self.activeTerminatedGroups.length - 1;\\n i > 0 && self.activeTerminatedGroups[i - 1] > groupId;\\n i--\\n ) {\\n self.activeTerminatedGroups[i] = self.activeTerminatedGroups[i - 1];\\n }\\n self.activeTerminatedGroups[i] = groupId;\\n }\\n\\n /// @notice Returns an index of a randomly selected active group. Terminated\\n /// and expired groups are not considered as active.\\n /// Before new group is selected, information about expired groups\\n /// is updated. At least one active group needs to be present for this\\n /// function to succeed.\\n /// @param seed Random number used as a group selection seed.\\n function selectGroup(Data storage self, uint256 seed)\\n internal\\n returns (uint64)\\n {\\n expireOldGroups(self);\\n\\n require(numberOfActiveGroups(self) > 0, \\\"No active groups\\\");\\n\\n uint64 selectedGroup = uint64(seed % numberOfActiveGroups(self));\\n uint64 result = shiftByTerminatedGroups(\\n self,\\n shiftByExpiredGroups(self, selectedGroup)\\n );\\n return result;\\n }\\n\\n /// @notice Setter for group lifetime.\\n /// @param lifetime Lifetime of a group in blocks.\\n function setGroupLifetime(Data storage self, uint256 lifetime) internal {\\n self.groupLifetime = lifetime;\\n }\\n\\n /// @notice Checks if group with the given index is terminated.\\n function isGroupTerminated(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]].terminated;\\n }\\n\\n /// @notice Gets the cutoff time until which the given group is considered\\n /// to be active assuming it hasn't been terminated before.\\n function groupLifetimeOf(Data storage self, bytes32 groupPubKeyHash)\\n internal\\n view\\n returns (uint256)\\n {\\n return\\n self.groupsData[groupPubKeyHash].registrationBlockNumber +\\n self.groupLifetime;\\n }\\n\\n /// @notice Checks if group with the given index is active and non-terminated.\\n function isGroupActive(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return\\n groupLifetimeOf(self, self.groupsRegistry[groupId]) >=\\n block.number &&\\n !isGroupTerminated(self, groupId);\\n }\\n\\n function getGroup(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]];\\n }\\n\\n function getGroup(Data storage self, bytes memory groupPubKey)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[keccak256(groupPubKey)];\\n }\\n\\n /// @notice Gets the number of active groups. Expired and terminated\\n /// groups are not counted as active.\\n function numberOfActiveGroups(Data storage self)\\n internal\\n view\\n returns (uint64)\\n {\\n if (self.groupsRegistry.length == 0) {\\n return 0;\\n }\\n\\n uint256 activeGroups = self.groupsRegistry.length -\\n self.expiredGroupOffset -\\n self.activeTerminatedGroups.length;\\n\\n return uint64(activeGroups);\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of expired groups.\\n function shiftByExpiredGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n return self.expiredGroupOffset + selectedIndex;\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of non-expired but terminated groups.\\n function shiftByTerminatedGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n uint64 shiftedIndex = selectedIndex;\\n for (uint64 i = 0; i < self.activeTerminatedGroups.length; i++) {\\n if (self.activeTerminatedGroups[i] <= shiftedIndex) {\\n shiftedIndex++;\\n }\\n }\\n\\n return shiftedIndex;\\n }\\n}\\n\",\"keccak256\":\"0x27a3cee268e5afa5ee3a00089aa82faffff7c3882aa94919499de4ef55dcfb0c\",\"license\":\"GPL-3.0-only\"}},\"version\":1}",
111
- "bytecode": "0x61100361003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80636dcc64f81461005057806389ef44b01461006b578063fc21976b14610073575b600080fd5b610058602181565b6040519081526020015b60405180910390f35b610058604181565b610086610081366004610b1a565b610093565b6040516100629190610c20565b60606100ab6100a56020880188610c6a565b8461063f565b600060416100bc6040890189610cb4565b6100c7929150610d27565b90506100d66040880188610cb4565b90506000036101255760405162461bcd60e51b8152602060048201526016602482015275139bc81cda59db985d1d5c995cc81c1c9bdd9a59195960521b60448201526064015b60405180910390fd5b60416101346040890189610cb4565b61013f929150610d3b565b1561018c5760405162461bcd60e51b815260206004820152601a60248201527f4d616c666f726d6564207369676e617475726573206172726179000000000000604482015260640161011c565b6101996060880188610c6a565b905081146101e95760405162461bcd60e51b815260206004820152601b60248201527f556e6578706563746564207369676e61747572657320636f756e740000000000604482015260640161011c565b602181101561022f5760405162461bcd60e51b8152602060048201526012602482015271546f6f20666577207369676e61747572657360701b604482015260640161011c565b828111156102755760405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e79207369676e61747572657360681b604482015260640161011c565b61028b6102856060890189610c6a565b8561063f565b60006103144687896102a060208d018d610c6a565b6040516020016102b4959493929190610d4f565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90506000896001600160a01b031663f7f9a8fa87876040518363ffffffff1660e01b8152600401610346929190610df7565b600060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261038b9190810190610e40565b905060606000805b858110156104e05760006103aa60608e018e610c6a565b838181106103ba576103ba610ef2565b9050602002013590506104238260416103d39190610f08565b60418f80604001906103e59190610cb4565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506107579050565b9350600061043187866107fd565b90506001600160a01b03811686610449600185610f1f565b8151811061045957610459610ef2565b60200260200101516001600160a01b0316146104ab5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b604482015260640161011c565b831580156104c15750336001600160a01b038216145b156104cb57600193505b505080806104d890610f32565b915050610393565b508061052e5760405162461bcd60e51b815260206004820152601b60248201527f53656e646572206d75737420626520636c61696d207369676e65720000000000604482015260640161011c565b61053b60208c018c610c6a565b905067ffffffffffffffff81111561055557610555610a8e565b60405190808252806020026020018201604052801561057e578160200160208202803683370190505b50955060005b61059160208d018d610c6a565b905081101561062f5760006105a960208e018e610c6a565b838181106105b9576105b9610ef2565b90506020020135905089896001836105d19190610f1f565b8181106105e0576105e0610ef2565b90506020020160208101906105f59190610f4b565b88838151811061060757610607610ef2565b63ffffffff90921660209283029190910190910152508061062781610f32565b915050610584565b5050505050509695505050505050565b811580159061064e5750808211155b61066a5760405162461bcd60e51b815260040161011c90610f6d565b60008383600081811061067f5761067f610ef2565b905060200201351180156106b5575080838361069c600182610f1f565b8181106106ab576106ab610ef2565b9050602002013511155b6106d15760405162461bcd60e51b815260040161011c90610f6d565b60005b6106df600184610f1f565b8110156107515783836106f3836001610fa4565b81811061070257610702610ef2565b9050602002013584848381811061071b5761071b610ef2565b905060200201351061073f5760405162461bcd60e51b815260040161011c90610f6d565b8061074981610f32565b9150506106d4565b50505050565b606060006107658385610fa4565b90508381118015610777575080855110155b6107b95760405162461bcd60e51b8152602060048201526013602482015272536c696365206f7574206f6620626f756e647360681b604482015260640161011c565b604051915082604083010160405282825283850182038460208701018481015b808210156107f2578151838301526020820191506107d9565b505050509392505050565b600080600061080c8585610823565b9150915061081981610868565b5090505b92915050565b60008082516041036108595760208301516040840151606085015160001a61084d878285856109b5565b94509450505050610861565b506000905060025b9250929050565b600081600481111561087c5761087c610fb7565b036108845750565b600181600481111561089857610898610fb7565b036108e55760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161011c565b60028160048111156108f9576108f9610fb7565b036109465760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161011c565b600381600481111561095a5761095a610fb7565b036109b25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161011c565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156109ec5750600090506003610a70565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610a40573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610a6957600060019250925050610a70565b9150600090505b94509492505050565b6001600160a01b03811681146109b257600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610acd57610acd610a8e565b604052919050565b60008083601f840112610ae757600080fd5b50813567ffffffffffffffff811115610aff57600080fd5b6020830191508360208260051b850101111561086157600080fd5b60008060008060008060a08789031215610b3357600080fd5b8635610b3e81610a79565b955060208781013567ffffffffffffffff80821115610b5c57600080fd5b908901906080828c031215610b7057600080fd5b90965060408901359080821115610b8657600080fd5b818a0191508a601f830112610b9a57600080fd5b813581811115610bac57610bac610a8e565b610bbe601f8201601f19168501610aa4565b8181528c85838601011115610bd257600080fd5b81858501868301376000918101909401529195506060890135945060808901359180831115610c0057600080fd5b5050610c0e89828a01610ad5565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b81811015610c5e57835163ffffffff1683529284019291840191600101610c3c565b50909695505050505050565b6000808335601e19843603018112610c8157600080fd5b83018035915067ffffffffffffffff821115610c9c57600080fd5b6020019150600581901b360382131561086157600080fd5b6000808335601e19843603018112610ccb57600080fd5b83018035915067ffffffffffffffff821115610ce657600080fd5b60200191503681900382131561086157600080fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082610d3657610d36610cfb565b500490565b600082610d4a57610d4a610cfb565b500690565b85815260006020868184015260806040840152855180608085015260005b81811015610d895787810183015185820160a001528201610d6d565b50600060a08286010152601f19601f820116840191505060a08382030160608401528360a082015260018060fb1b03841115610dc457600080fd5b8360051b808660c08401370160c001979650505050505050565b803563ffffffff81168114610df257600080fd5b919050565b60208082528181018390526000908460408401835b86811015610e355763ffffffff610e2284610dde565b1682529183019190830190600101610e0c565b509695505050505050565b60006020808385031215610e5357600080fd5b825167ffffffffffffffff80821115610e6b57600080fd5b818501915085601f830112610e7f57600080fd5b815181811115610e9157610e91610a8e565b8060051b9150610ea2848301610aa4565b8181529183018401918481019088841115610ebc57600080fd5b938501935b83851015610ee65784519250610ed683610a79565b8282529385019390850190610ec1565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b808202811582820484141761081d5761081d610d11565b8181038181111561081d5761081d610d11565b600060018201610f4457610f44610d11565b5060010190565b600060208284031215610f5d57600080fd5b610f6682610dde565b9392505050565b60208082526019908201527f436f72727570746564206d656d6265727320696e646963657300000000000000604082015260600190565b8082018082111561081d5761081d610d11565b634e487b7160e01b600052602160045260246000fdfea2646970667358221220fbf129e92b864de20967442d272ac6c914d443e567a1850285eb7934de44847764736f6c63430008110033",
112
- "deployedBytecode": "0x730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80636dcc64f81461005057806389ef44b01461006b578063fc21976b14610073575b600080fd5b610058602181565b6040519081526020015b60405180910390f35b610058604181565b610086610081366004610b1a565b610093565b6040516100629190610c20565b60606100ab6100a56020880188610c6a565b8461063f565b600060416100bc6040890189610cb4565b6100c7929150610d27565b90506100d66040880188610cb4565b90506000036101255760405162461bcd60e51b8152602060048201526016602482015275139bc81cda59db985d1d5c995cc81c1c9bdd9a59195960521b60448201526064015b60405180910390fd5b60416101346040890189610cb4565b61013f929150610d3b565b1561018c5760405162461bcd60e51b815260206004820152601a60248201527f4d616c666f726d6564207369676e617475726573206172726179000000000000604482015260640161011c565b6101996060880188610c6a565b905081146101e95760405162461bcd60e51b815260206004820152601b60248201527f556e6578706563746564207369676e61747572657320636f756e740000000000604482015260640161011c565b602181101561022f5760405162461bcd60e51b8152602060048201526012602482015271546f6f20666577207369676e61747572657360701b604482015260640161011c565b828111156102755760405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e79207369676e61747572657360681b604482015260640161011c565b61028b6102856060890189610c6a565b8561063f565b60006103144687896102a060208d018d610c6a565b6040516020016102b4959493929190610d4f565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90506000896001600160a01b031663f7f9a8fa87876040518363ffffffff1660e01b8152600401610346929190610df7565b600060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261038b9190810190610e40565b905060606000805b858110156104e05760006103aa60608e018e610c6a565b838181106103ba576103ba610ef2565b9050602002013590506104238260416103d39190610f08565b60418f80604001906103e59190610cb4565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506107579050565b9350600061043187866107fd565b90506001600160a01b03811686610449600185610f1f565b8151811061045957610459610ef2565b60200260200101516001600160a01b0316146104ab5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b604482015260640161011c565b831580156104c15750336001600160a01b038216145b156104cb57600193505b505080806104d890610f32565b915050610393565b508061052e5760405162461bcd60e51b815260206004820152601b60248201527f53656e646572206d75737420626520636c61696d207369676e65720000000000604482015260640161011c565b61053b60208c018c610c6a565b905067ffffffffffffffff81111561055557610555610a8e565b60405190808252806020026020018201604052801561057e578160200160208202803683370190505b50955060005b61059160208d018d610c6a565b905081101561062f5760006105a960208e018e610c6a565b838181106105b9576105b9610ef2565b90506020020135905089896001836105d19190610f1f565b8181106105e0576105e0610ef2565b90506020020160208101906105f59190610f4b565b88838151811061060757610607610ef2565b63ffffffff90921660209283029190910190910152508061062781610f32565b915050610584565b5050505050509695505050505050565b811580159061064e5750808211155b61066a5760405162461bcd60e51b815260040161011c90610f6d565b60008383600081811061067f5761067f610ef2565b905060200201351180156106b5575080838361069c600182610f1f565b8181106106ab576106ab610ef2565b9050602002013511155b6106d15760405162461bcd60e51b815260040161011c90610f6d565b60005b6106df600184610f1f565b8110156107515783836106f3836001610fa4565b81811061070257610702610ef2565b9050602002013584848381811061071b5761071b610ef2565b905060200201351061073f5760405162461bcd60e51b815260040161011c90610f6d565b8061074981610f32565b9150506106d4565b50505050565b606060006107658385610fa4565b90508381118015610777575080855110155b6107b95760405162461bcd60e51b8152602060048201526013602482015272536c696365206f7574206f6620626f756e647360681b604482015260640161011c565b604051915082604083010160405282825283850182038460208701018481015b808210156107f2578151838301526020820191506107d9565b505050509392505050565b600080600061080c8585610823565b9150915061081981610868565b5090505b92915050565b60008082516041036108595760208301516040840151606085015160001a61084d878285856109b5565b94509450505050610861565b506000905060025b9250929050565b600081600481111561087c5761087c610fb7565b036108845750565b600181600481111561089857610898610fb7565b036108e55760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161011c565b60028160048111156108f9576108f9610fb7565b036109465760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161011c565b600381600481111561095a5761095a610fb7565b036109b25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161011c565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156109ec5750600090506003610a70565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610a40573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610a6957600060019250925050610a70565b9150600090505b94509492505050565b6001600160a01b03811681146109b257600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610acd57610acd610a8e565b604052919050565b60008083601f840112610ae757600080fd5b50813567ffffffffffffffff811115610aff57600080fd5b6020830191508360208260051b850101111561086157600080fd5b60008060008060008060a08789031215610b3357600080fd5b8635610b3e81610a79565b955060208781013567ffffffffffffffff80821115610b5c57600080fd5b908901906080828c031215610b7057600080fd5b90965060408901359080821115610b8657600080fd5b818a0191508a601f830112610b9a57600080fd5b813581811115610bac57610bac610a8e565b610bbe601f8201601f19168501610aa4565b8181528c85838601011115610bd257600080fd5b81858501868301376000918101909401529195506060890135945060808901359180831115610c0057600080fd5b5050610c0e89828a01610ad5565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b81811015610c5e57835163ffffffff1683529284019291840191600101610c3c565b50909695505050505050565b6000808335601e19843603018112610c8157600080fd5b83018035915067ffffffffffffffff821115610c9c57600080fd5b6020019150600581901b360382131561086157600080fd5b6000808335601e19843603018112610ccb57600080fd5b83018035915067ffffffffffffffff821115610ce657600080fd5b60200191503681900382131561086157600080fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082610d3657610d36610cfb565b500490565b600082610d4a57610d4a610cfb565b500690565b85815260006020868184015260806040840152855180608085015260005b81811015610d895787810183015185820160a001528201610d6d565b50600060a08286010152601f19601f820116840191505060a08382030160608401528360a082015260018060fb1b03841115610dc457600080fd5b8360051b808660c08401370160c001979650505050505050565b803563ffffffff81168114610df257600080fd5b919050565b60208082528181018390526000908460408401835b86811015610e355763ffffffff610e2284610dde565b1682529183019190830190600101610e0c565b509695505050505050565b60006020808385031215610e5357600080fd5b825167ffffffffffffffff80821115610e6b57600080fd5b818501915085601f830112610e7f57600080fd5b815181811115610e9157610e91610a8e565b8060051b9150610ea2848301610aa4565b8181529183018401918481019088841115610ebc57600080fd5b938501935b83851015610ee65784519250610ed683610a79565b8282529385019390850190610ec1565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b808202811582820484141761081d5761081d610d11565b8181038181111561081d5761081d610d11565b600060018201610f4457610f44610d11565b5060010190565b600060208284031215610f5d57600080fd5b610f6682610dde565b9392505050565b60208082526019908201527f436f72727570746564206d656d6265727320696e646963657300000000000000604082015260600190565b8082018082111561081d5761081d610d11565b634e487b7160e01b600052602160045260246000fdfea2646970667358221220fbf129e92b864de20967442d272ac6c914d443e567a1850285eb7934de44847764736f6c63430008110033",
110
+ "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"groupThreshold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"signatureByteSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract SortitionPool\",\"name\":\"sortitionPool\",\"type\":\"SortitionPool\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"groupId\",\"type\":\"uint64\"},{\"internalType\":\"uint256[]\",\"name\":\"inactiveMembersIndices\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"signatures\",\"type\":\"bytes\"},{\"internalType\":\"uint256[]\",\"name\":\"signingMembersIndices\",\"type\":\"uint256[]\"}],\"internalType\":\"struct BeaconInactivity.Claim\",\"name\":\"claim\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"groupPubKey\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint32[]\",\"name\":\"groupMembers\",\"type\":\"uint32[]\"}],\"name\":\"verifyClaim\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"inactiveMembers\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"verifyClaim(SortitionPool,BeaconInactivity.Claim,bytes,uint256,uint32[])\":{\"details\":\"Group members hash is validated upstream in RandomBeacon.notifyOperatorInactivity()\",\"params\":{\"claim\":\"Inactivity claim\",\"groupMembers\":\"Identifiers of group members\",\"groupPubKey\":\"Public key of the group raising the claim\",\"nonce\":\"Current nonce for group used in the claim\",\"sortitionPool\":\"Sortition pool reference\"},\"returns\":{\"inactiveMembers\":\"Identifiers of members who are inactive\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"groupThreshold()\":{\"notice\":\"The minimum number of group members needed to interact according to the protocol to produce a valid inactivity claim.\"},\"signatureByteSize()\":{\"notice\":\"Size in bytes of a single signature produced by member supporting the inactivity claim.\"},\"verifyClaim(SortitionPool,BeaconInactivity.Claim,bytes,uint256,uint32[])\":{\"notice\":\"Verifies the inactivity claim according to the rules defined in `Claim` struct documentation. Reverts if verification fails.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libraries/BeaconInactivity.sol\":\"BeaconInactivity\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@keep-network/sortition-pools/contracts/Branch.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\n/// @notice The implicit 8-ary trees of the sortition pool\\n/// rely on packing 8 \\\"slots\\\" of 32-bit values into each uint256.\\n/// The Branch library permits efficient calculations on these slots.\\nlibrary Branch {\\n /// @notice Calculate the right shift required\\n /// to make the 32 least significant bits of an uint256\\n /// be the bits of the `position`th slot\\n /// when treating the uint256 as a uint32[8].\\n ///\\n /// @dev Not used for efficiency reasons,\\n /// but left to illustrate the meaning of a common pattern.\\n /// I wish solidity had macros, even C macros.\\n function slotShift(uint256 position) internal pure returns (uint256) {\\n unchecked {\\n return position * Constants.SLOT_WIDTH;\\n }\\n }\\n\\n /// @notice Return the `position`th slot of the `node`,\\n /// treating `node` as a uint32[32].\\n function getSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Doing a bitwise AND with `SLOT_MAX`\\n // clears all but the 32 least significant bits.\\n // Because of the right shift by `slotShift(position)` bits,\\n // those 32 bits contain the 32 bits in the `position`th slot of `node`.\\n return (node >> shiftBits) & Constants.SLOT_MAX;\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to zero.\\n function clearSlot(uint256 node, uint256 position)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Shifting `SLOT_MAX` left by `slotShift(position)` bits\\n // gives us a number where all bits of the `position`th slot are set,\\n // and all other bits are unset.\\n //\\n // Using a bitwise NOT on this number,\\n // we get a uint256 where all bits are set\\n // except for those of the `position`th slot.\\n //\\n // Bitwise ANDing the original `node` with this number\\n // sets the bits of `position`th slot to zero,\\n // leaving all other bits unchanged.\\n return node & ~(Constants.SLOT_MAX << shiftBits);\\n }\\n }\\n\\n /// @notice Return `node` with the `position`th slot set to `weight`.\\n ///\\n /// @param weight The weight of of the node.\\n /// Safely truncated to a 32-bit number,\\n /// but this should never be called with an overflowing weight regardless.\\n function setSlot(\\n uint256 node,\\n uint256 position,\\n uint256 weight\\n ) internal pure returns (uint256) {\\n unchecked {\\n uint256 shiftBits = position * Constants.SLOT_WIDTH;\\n // Clear the `position`th slot like in `clearSlot()`.\\n uint256 clearedNode = node & ~(Constants.SLOT_MAX << shiftBits);\\n // Bitwise AND `weight` with `SLOT_MAX`\\n // to clear all but the 32 least significant bits.\\n //\\n // Shift this left by `slotShift(position)` bits\\n // to obtain a uint256 with all bits unset\\n // except in the `position`th slot\\n // which contains the 32-bit value of `weight`.\\n uint256 shiftedWeight = (weight & Constants.SLOT_MAX) << shiftBits;\\n // When we bitwise OR these together,\\n // all other slots except the `position`th one come from the left argument,\\n // and the `position`th gets filled with `weight` from the right argument.\\n return clearedNode | shiftedWeight;\\n }\\n }\\n\\n /// @notice Calculate the summed weight of all slots in the `node`.\\n function sumWeight(uint256 node) internal pure returns (uint256 sum) {\\n unchecked {\\n sum = node & Constants.SLOT_MAX;\\n // Iterate through each slot\\n // by shifting `node` right in increments of 32 bits,\\n // and adding the 32 least significant bits to the `sum`.\\n uint256 newNode = node >> Constants.SLOT_WIDTH;\\n while (newNode > 0) {\\n sum += (newNode & Constants.SLOT_MAX);\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n }\\n return sum;\\n }\\n }\\n\\n /// @notice Pick a slot in `node` that corresponds to `index`.\\n /// Treats the node like an array of virtual stakers,\\n /// the number of virtual stakers in each slot corresponding to its weight,\\n /// and picks which slot contains the `index`th virtual staker.\\n ///\\n /// @dev Requires that `index` be lower than `sumWeight(node)`.\\n /// However, this is not enforced for performance reasons.\\n /// If `index` exceeds the permitted range,\\n /// `pickWeightedSlot()` returns the rightmost slot\\n /// and an excessively high `newIndex`.\\n ///\\n /// @return slot The slot of `node` containing the `index`th virtual staker.\\n ///\\n /// @return newIndex The index of the `index`th virtual staker of `node`\\n /// within the returned slot.\\n function pickWeightedSlot(uint256 node, uint256 index)\\n internal\\n pure\\n returns (uint256 slot, uint256 newIndex)\\n {\\n unchecked {\\n newIndex = index;\\n uint256 newNode = node;\\n uint256 currentSlotWeight = newNode & Constants.SLOT_MAX;\\n while (newIndex >= currentSlotWeight) {\\n newIndex -= currentSlotWeight;\\n slot++;\\n newNode = newNode >> Constants.SLOT_WIDTH;\\n currentSlotWeight = newNode & Constants.SLOT_MAX;\\n }\\n return (slot, newIndex);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa7fb1c9c9789f30493e9a40e24a24f46875dc5e7630b4f67478167759f6d1882\"},\"@keep-network/sortition-pools/contracts/Chaosnet.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Chaosnet\\n/// @notice This is a beta staker program for stakers willing to go the extra\\n/// mile with monitoring, share their logs with the dev team, and allow to more\\n/// carefully monitor the bootstrapping network. As the network matures, the\\n/// beta program will be ended.\\ncontract Chaosnet {\\n /// @notice Indicates if the chaosnet is active. The chaosnet is active\\n /// after the contract deployment and can be ended with a call to\\n /// `deactivateChaosnet()`. Once deactivated chaosnet can not be activated\\n /// again.\\n bool public isChaosnetActive;\\n\\n /// @notice Indicates if the given operator is a beta operator for chaosnet.\\n mapping(address => bool) public isBetaOperator;\\n\\n /// @notice Address controlling chaosnet status and beta operator addresses.\\n address public chaosnetOwner;\\n\\n event BetaOperatorsAdded(address[] operators);\\n\\n event ChaosnetOwnerRoleTransferred(\\n address oldChaosnetOwner,\\n address newChaosnetOwner\\n );\\n\\n event ChaosnetDeactivated();\\n\\n constructor() {\\n _transferChaosnetOwner(msg.sender);\\n isChaosnetActive = true;\\n }\\n\\n modifier onlyChaosnetOwner() {\\n require(msg.sender == chaosnetOwner, \\\"Not the chaosnet owner\\\");\\n _;\\n }\\n\\n modifier onlyOnChaosnet() {\\n require(isChaosnetActive, \\\"Chaosnet is not active\\\");\\n _;\\n }\\n\\n /// @notice Adds beta operator to chaosnet. Can be called only by the\\n /// chaosnet owner when the chaosnet is active. Once the operator is added\\n /// as a beta operator, it can not be removed.\\n function addBetaOperators(address[] calldata operators)\\n public\\n onlyOnChaosnet\\n onlyChaosnetOwner\\n {\\n for (uint256 i = 0; i < operators.length; i++) {\\n isBetaOperator[operators[i]] = true;\\n }\\n\\n emit BetaOperatorsAdded(operators);\\n }\\n\\n /// @notice Deactivates the chaosnet. Can be called only by the chaosnet\\n /// owner. Once deactivated chaosnet can not be activated again.\\n function deactivateChaosnet() public onlyOnChaosnet onlyChaosnetOwner {\\n isChaosnetActive = false;\\n emit ChaosnetDeactivated();\\n }\\n\\n /// @notice Transfers the chaosnet owner role to another non-zero address.\\n function transferChaosnetOwnerRole(address newChaosnetOwner)\\n public\\n onlyChaosnetOwner\\n {\\n require(\\n newChaosnetOwner != address(0),\\n \\\"New chaosnet owner must not be zero address\\\"\\n );\\n _transferChaosnetOwner(newChaosnetOwner);\\n }\\n\\n function _transferChaosnetOwner(address newChaosnetOwner) internal {\\n address oldChaosnetOwner = chaosnetOwner;\\n chaosnetOwner = newChaosnetOwner;\\n emit ChaosnetOwnerRoleTransferred(oldChaosnetOwner, newChaosnetOwner);\\n }\\n}\\n\",\"keccak256\":\"0xeaf7bdd5626f88c329793a012621039692ce1b6e1f13013997ddb13d7e3032df\"},\"@keep-network/sortition-pools/contracts/Constants.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nlibrary Constants {\\n ////////////////////////////////////////////////////////////////////////////\\n // Parameters for configuration\\n\\n // How many bits a position uses per level of the tree;\\n // each branch of the tree contains 2**SLOT_BITS slots.\\n uint256 constant SLOT_BITS = 3;\\n uint256 constant LEVELS = 7;\\n ////////////////////////////////////////////////////////////////////////////\\n\\n ////////////////////////////////////////////////////////////////////////////\\n // Derived constants, do not touch\\n uint256 constant SLOT_COUNT = 2**SLOT_BITS;\\n uint256 constant SLOT_WIDTH = 256 / SLOT_COUNT;\\n uint256 constant LAST_SLOT = SLOT_COUNT - 1;\\n uint256 constant SLOT_MAX = (2**SLOT_WIDTH) - 1;\\n uint256 constant POOL_CAPACITY = SLOT_COUNT**LEVELS;\\n\\n uint256 constant ID_WIDTH = SLOT_WIDTH;\\n uint256 constant ID_MAX = SLOT_MAX;\\n\\n uint256 constant BLOCKHEIGHT_WIDTH = 96 - ID_WIDTH;\\n uint256 constant BLOCKHEIGHT_MAX = (2**BLOCKHEIGHT_WIDTH) - 1;\\n\\n uint256 constant SLOT_POINTER_MAX = (2**SLOT_BITS) - 1;\\n uint256 constant LEAF_FLAG = 1 << 255;\\n\\n uint256 constant WEIGHT_WIDTH = 256 / SLOT_COUNT;\\n ////////////////////////////////////////////////////////////////////////////\\n}\\n\",\"keccak256\":\"0xaef690ced707935745ff1482b7bb9bd9eb77bf6a39c717465e64cf12db8a7d39\"},\"@keep-network/sortition-pools/contracts/Leaf.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Leaf {\\n function make(\\n address _operator,\\n uint256 _creationBlock,\\n uint256 _id\\n ) internal pure returns (uint256) {\\n assert(_creationBlock <= type(uint64).max);\\n assert(_id <= type(uint32).max);\\n // Converting a bytesX type into a larger type\\n // adds zero bytes on the right.\\n uint256 op = uint256(bytes32(bytes20(_operator)));\\n // Bitwise AND the id to erase\\n // all but the 32 least significant bits\\n uint256 uid = _id & Constants.ID_MAX;\\n // Erase all but the 64 least significant bits,\\n // then shift left by 32 bits to make room for the id\\n uint256 cb = (_creationBlock & Constants.BLOCKHEIGHT_MAX) <<\\n Constants.ID_WIDTH;\\n // Bitwise OR them all together to get\\n // [address operator || uint64 creationBlock || uint32 id]\\n return (op | cb | uid);\\n }\\n\\n function operator(uint256 leaf) internal pure returns (address) {\\n // Converting a bytesX type into a smaller type\\n // truncates it on the right.\\n return address(bytes20(bytes32(leaf)));\\n }\\n\\n /// @notice Return the block number the leaf was created in.\\n function creationBlock(uint256 leaf) internal pure returns (uint256) {\\n return ((leaf >> Constants.ID_WIDTH) & Constants.BLOCKHEIGHT_MAX);\\n }\\n\\n function id(uint256 leaf) internal pure returns (uint32) {\\n // Id is stored in the 32 least significant bits.\\n // Bitwise AND ensures that we only get the contents of those bits.\\n return uint32(leaf & Constants.ID_MAX);\\n }\\n}\\n\",\"keccak256\":\"0xbd107a1a43e48884885e5e966ffcbcd8fa5e89863715d717bb4006e9f89cdc2b\"},\"@keep-network/sortition-pools/contracts/Position.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary Position {\\n // Return the last 3 bits of a position number,\\n // corresponding to its slot in its parent\\n function slot(uint256 a) internal pure returns (uint256) {\\n return a & Constants.SLOT_POINTER_MAX;\\n }\\n\\n // Return the parent of a position number\\n function parent(uint256 a) internal pure returns (uint256) {\\n return a >> Constants.SLOT_BITS;\\n }\\n\\n // Return the location of the child of a at the given slot\\n function child(uint256 a, uint256 s) internal pure returns (uint256) {\\n return (a << Constants.SLOT_BITS) | (s & Constants.SLOT_POINTER_MAX); // slot(s)\\n }\\n\\n // Return the uint p as a flagged position uint:\\n // the least significant 21 bits contain the position\\n // and the 22nd bit is set as a flag\\n // to distinguish the position 0x000000 from an empty field.\\n function setFlag(uint256 p) internal pure returns (uint256) {\\n return p | Constants.LEAF_FLAG;\\n }\\n\\n // Turn a flagged position into an unflagged position\\n // by removing the flag at the 22nd least significant bit.\\n //\\n // We shouldn't _actually_ need this\\n // as all position-manipulating code should ignore non-position bits anyway\\n // but it's cheap to call so might as well do it.\\n function unsetFlag(uint256 p) internal pure returns (uint256) {\\n return p & (~Constants.LEAF_FLAG);\\n }\\n}\\n\",\"keccak256\":\"0xd3a927908080ac21353a92a6bce3d69e94a5c30f6b51f16b271b6cc679f110e2\"},\"@keep-network/sortition-pools/contracts/RNG.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\nlibrary RNG {\\n /// @notice Get an index in the range `[0 .. range-1]`\\n /// and the new state of the RNG,\\n /// using the provided `state` of the RNG.\\n ///\\n /// @param range The upper bound of the index, exclusive.\\n ///\\n /// @param state The previous state of the RNG.\\n /// The initial state needs to be obtained\\n /// from a trusted randomness oracle (the random beacon),\\n /// or from a chain of earlier calls to `RNG.getIndex()`\\n /// on an originally trusted seed.\\n ///\\n /// @dev Calculates the number of bits required for the desired range,\\n /// takes the least significant bits of `state`\\n /// and checks if the obtained index is within the desired range.\\n /// The original state is hashed with `keccak256` to get a new state.\\n /// If the index is outside the range,\\n /// the function retries until it gets a suitable index.\\n ///\\n /// @return index A random integer between `0` and `range - 1`, inclusive.\\n ///\\n /// @return newState The new state of the RNG.\\n /// When `getIndex()` is called one or more times,\\n /// care must be taken to always use the output `state`\\n /// of the most recent call as the input `state` of a subsequent call.\\n /// At the end of a transaction calling `RNG.getIndex()`,\\n /// the previous stored state must be overwritten with the latest output.\\n function getIndex(\\n uint256 range,\\n bytes32 state,\\n uint256 bits\\n ) internal view returns (uint256, bytes32) {\\n bool found = false;\\n uint256 index = 0;\\n bytes32 newState = state;\\n while (!found) {\\n index = truncate(bits, uint256(newState));\\n newState = keccak256(abi.encodePacked(newState, address(this)));\\n if (index < range) {\\n found = true;\\n }\\n }\\n return (index, newState);\\n }\\n\\n /// @notice Calculate how many bits are required\\n /// for an index in the range `[0 .. range-1]`.\\n ///\\n /// @param range The upper bound of the desired range, exclusive.\\n ///\\n /// @return uint The smallest number of bits\\n /// that can contain the number `range-1`.\\n function bitsRequired(uint256 range) internal pure returns (uint256) {\\n unchecked {\\n if (range == 1) {\\n return 0;\\n }\\n\\n uint256 bits = Constants.WEIGHT_WIDTH - 1;\\n\\n // Left shift by `bits`,\\n // so we have a 1 in the (bits + 1)th least significant bit\\n // and 0 in other bits.\\n // If this number is equal or greater than `range`,\\n // the range [0, range-1] fits in `bits` bits.\\n //\\n // Because we loop from high bits to low bits,\\n // we find the highest number of bits that doesn't fit the range,\\n // and return that number + 1.\\n while (1 << bits >= range) {\\n bits--;\\n }\\n\\n return bits + 1;\\n }\\n }\\n\\n /// @notice Truncate `input` to the `bits` least significant bits.\\n function truncate(uint256 bits, uint256 input)\\n internal\\n pure\\n returns (uint256)\\n {\\n unchecked {\\n return input & ((1 << bits) - 1);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x67f87f589cd5123ffa32f883ea2f09b0e56258508bae82b8c655b3c27c71eb5e\"},\"@keep-network/sortition-pools/contracts/Rewards.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\n/// @title Rewards\\n/// @notice Rewards are allocated proportionally to operators\\n/// present in the pool at payout based on their weight in the pool.\\n///\\n/// To facilitate this, we use a global accumulator value\\n/// to track the total rewards one unit of weight would've earned\\n/// since the creation of the pool.\\n///\\n/// Whenever a reward is paid, the accumulator is increased\\n/// by the size of the reward divided by the total weight\\n/// of all eligible operators in the pool.\\n///\\n/// Each operator has an individual accumulator value,\\n/// set to equal the global accumulator when the operator joins the pool.\\n/// This accumulator reflects the amount of rewards\\n/// that have already been accounted for with that operator.\\n///\\n/// Whenever an operator's weight in the pool changes,\\n/// we can update the amount of rewards the operator has earned\\n/// by subtracting the operator's accumulator from the global accumulator.\\n/// This gives us the amount of rewards one unit of weight has earned\\n/// since the last time the operator's rewards have been updated.\\n/// Then we multiply that by the operator's previous (pre-change) weight\\n/// to determine how much rewards in total the operator has earned,\\n/// and add this to the operator's earned rewards.\\n/// Finally, we set the operator's accumulator to the global accumulator value.\\ncontract Rewards {\\n struct OperatorRewards {\\n // The state of the global accumulator\\n // when the operator's rewards were last updated\\n uint96 accumulated;\\n // The amount of rewards collected by the operator after the latest update.\\n // The amount the operator could withdraw may equal `available`\\n // or it may be greater, if more rewards have been paid in since then.\\n // To evaulate the most recent amount including rewards potentially paid\\n // since the last update, use `availableRewards` function.\\n uint96 available;\\n // If nonzero, the operator is ineligible for rewards\\n // and may only re-enable rewards after the specified timestamp.\\n // XXX: unsigned 32-bit integer unix seconds, will break around 2106\\n uint32 ineligibleUntil;\\n // Locally cached weight of the operator,\\n // used to reduce the cost of setting operators ineligible.\\n uint32 weight;\\n }\\n\\n // The global accumulator of how much rewards\\n // a hypothetical operator of weight 1 would have earned\\n // since the creation of the pool.\\n uint96 internal globalRewardAccumulator;\\n // If the amount of reward tokens paid in\\n // does not divide cleanly by pool weight,\\n // the difference is recorded as rounding dust\\n // and added to the next reward.\\n uint96 internal rewardRoundingDust;\\n\\n // The amount of rewards that would've been earned by ineligible operators\\n // had they not been ineligible.\\n uint96 public ineligibleEarnedRewards;\\n\\n // Ineligibility times are calculated from this offset,\\n // set at contract creation.\\n uint256 internal immutable ineligibleOffsetStart;\\n\\n mapping(uint32 => OperatorRewards) internal operatorRewards;\\n\\n constructor() {\\n // solhint-disable-next-line not-rely-on-time\\n ineligibleOffsetStart = block.timestamp;\\n }\\n\\n /// @notice Return whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(uint32 operator) internal view returns (bool) {\\n return operatorRewards[operator].ineligibleUntil == 0;\\n }\\n\\n /// @notice Return the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(uint32 operator)\\n internal\\n view\\n returns (uint256)\\n {\\n uint32 until = operatorRewards[operator].ineligibleUntil;\\n require(until != 0, \\\"Operator already eligible\\\");\\n return (uint256(until) + ineligibleOffsetStart);\\n }\\n\\n /// @notice Return whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(uint32 operator)\\n internal\\n view\\n returns (bool)\\n {\\n // solhint-disable-next-line not-rely-on-time\\n return rewardsEligibilityRestorableAt(operator) <= block.timestamp;\\n }\\n\\n /// @notice Internal function for updating the global state of rewards.\\n function addRewards(uint96 rewardAmount, uint32 currentPoolWeight) internal {\\n require(currentPoolWeight > 0, \\\"No recipients in pool\\\");\\n\\n uint96 totalAmount = rewardAmount + rewardRoundingDust;\\n uint96 perWeightReward = totalAmount / currentPoolWeight;\\n uint96 newRoundingDust = totalAmount % currentPoolWeight;\\n\\n globalRewardAccumulator += perWeightReward;\\n rewardRoundingDust = newRoundingDust;\\n }\\n\\n /// @notice Internal function for updating the operator's reward state.\\n function updateOperatorRewards(uint32 operator, uint32 newWeight) internal {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, update their earned rewards\\n o.available += accruedRewards;\\n } else {\\n // If ineligible, put the rewards into the ineligible pot\\n ineligibleEarnedRewards += accruedRewards;\\n }\\n // In any case, update their accumulator and weight\\n o.accumulated = acc;\\n o.weight = newWeight;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Set the amount of withdrawable tokens to zero\\n /// and return the previous withdrawable amount.\\n /// @dev Does not update the withdrawable amount,\\n /// but should usually be accompanied by an update.\\n function withdrawOperatorRewards(uint32 operator)\\n internal\\n returns (uint96 withdrawable)\\n {\\n OperatorRewards storage o = operatorRewards[operator];\\n withdrawable = o.available;\\n o.available = 0;\\n }\\n\\n /// @notice Set the amount of ineligible-earned tokens to zero\\n /// and return the previous amount.\\n function withdrawIneligibleRewards() internal returns (uint96 withdrawable) {\\n withdrawable = ineligibleEarnedRewards;\\n ineligibleEarnedRewards = 0;\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setIneligible(uint32[] memory operators, uint256 until) internal {\\n OperatorRewards memory o = OperatorRewards(0, 0, 0, 0);\\n uint96 globalAcc = globalRewardAccumulator;\\n uint96 accrued = 0;\\n // Record ineligibility as seconds after contract creation\\n uint32 _until = uint32(until - ineligibleOffsetStart);\\n\\n for (uint256 i = 0; i < operators.length; i++) {\\n uint32 operator = operators[i];\\n OperatorRewards storage r = operatorRewards[operator];\\n o.available = r.available;\\n o.accumulated = r.accumulated;\\n o.ineligibleUntil = r.ineligibleUntil;\\n o.weight = r.weight;\\n\\n if (o.ineligibleUntil != 0) {\\n // If operator is already ineligible,\\n // don't earn rewards or shorten its ineligibility\\n if (o.ineligibleUntil < _until) {\\n o.ineligibleUntil = _until;\\n }\\n } else {\\n // The operator becomes ineligible -> earn rewards\\n o.ineligibleUntil = _until;\\n accrued = (globalAcc - o.accumulated) * uint96(o.weight);\\n o.available += accrued;\\n }\\n o.accumulated = globalAcc;\\n\\n r.available = o.available;\\n r.accumulated = o.accumulated;\\n r.ineligibleUntil = o.ineligibleUntil;\\n r.weight = o.weight;\\n }\\n }\\n\\n /// @notice Restore the given operator's eligibility for rewards.\\n function restoreEligibility(uint32 operator) internal {\\n // solhint-disable-next-line not-rely-on-time\\n require(canRestoreRewardEligibility(operator), \\\"Operator still ineligible\\\");\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n ineligibleEarnedRewards += accruedRewards;\\n o.accumulated = acc;\\n o.ineligibleUntil = 0;\\n operatorRewards[operator] = o;\\n }\\n\\n /// @notice Returns the amount of rewards currently available for withdrawal\\n /// for the given operator.\\n function availableRewards(uint32 operator) internal view returns (uint96) {\\n uint96 acc = globalRewardAccumulator;\\n OperatorRewards memory o = operatorRewards[operator];\\n if (o.ineligibleUntil == 0) {\\n // If operator is not ineligible, calculate newly accrued rewards and add\\n // them to the available ones, calculated during the last update.\\n uint96 accruedRewards = (acc - o.accumulated) * uint96(o.weight);\\n return o.available + accruedRewards;\\n } else {\\n // If ineligible, return only the rewards calculated during the last\\n // update.\\n return o.available;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a10abb408b44335a092387b2c7ee01db3b27997f1f2c888d9b7a2d92934c4e2\"},\"@keep-network/sortition-pools/contracts/SortitionPool.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\\\";\\nimport \\\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\\\";\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\n\\nimport \\\"./RNG.sol\\\";\\nimport \\\"./SortitionTree.sol\\\";\\nimport \\\"./Rewards.sol\\\";\\nimport \\\"./Chaosnet.sol\\\";\\n\\n/// @title Sortition Pool\\n/// @notice A logarithmic data structure used to store the pool of eligible\\n/// operators weighted by their stakes. It allows to select a group of operators\\n/// based on the provided pseudo-random seed.\\ncontract SortitionPool is\\n SortitionTree,\\n Rewards,\\n Ownable,\\n Chaosnet,\\n IReceiveApproval\\n{\\n using Branch for uint256;\\n using Leaf for uint256;\\n using Position for uint256;\\n\\n IERC20WithPermit public immutable rewardToken;\\n\\n uint256 public immutable poolWeightDivisor;\\n\\n bool public isLocked;\\n\\n event IneligibleForRewards(uint32[] ids, uint256 until);\\n\\n event RewardEligibilityRestored(address indexed operator, uint32 indexed id);\\n\\n /// @notice Reverts if called while pool is locked.\\n modifier onlyUnlocked() {\\n require(!isLocked, \\\"Sortition pool locked\\\");\\n _;\\n }\\n\\n /// @notice Reverts if called while pool is unlocked.\\n modifier onlyLocked() {\\n require(isLocked, \\\"Sortition pool unlocked\\\");\\n _;\\n }\\n\\n constructor(IERC20WithPermit _rewardToken, uint256 _poolWeightDivisor) {\\n rewardToken = _rewardToken;\\n poolWeightDivisor = _poolWeightDivisor;\\n }\\n\\n function receiveApproval(\\n address sender,\\n uint256 amount,\\n address token,\\n bytes calldata\\n ) external override {\\n require(token == address(rewardToken), \\\"Unsupported token\\\");\\n rewardToken.transferFrom(sender, address(this), amount);\\n Rewards.addRewards(uint96(amount), uint32(root.sumWeight()));\\n }\\n\\n /// @notice Withdraws all available rewards for the given operator to the\\n /// given beneficiary.\\n /// @dev Can be called only be the owner. Does not validate if the provided\\n /// beneficiary is associated with the provided operator - this needs to\\n /// be done by the owner calling this function.\\n /// @return The amount of rewards withdrawn in this call.\\n function withdrawRewards(address operator, address beneficiary)\\n public\\n onlyOwner\\n returns (uint96)\\n {\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(getPoolWeight(operator)));\\n uint96 earned = Rewards.withdrawOperatorRewards(id);\\n rewardToken.transfer(beneficiary, uint256(earned));\\n return earned;\\n }\\n\\n /// @notice Withdraws rewards not allocated to operators marked as ineligible\\n /// to the given recipient address.\\n /// @dev Can be called only by the owner.\\n function withdrawIneligible(address recipient) public onlyOwner {\\n uint96 earned = Rewards.withdrawIneligibleRewards();\\n rewardToken.transfer(recipient, uint256(earned));\\n }\\n\\n /// @notice Locks the sortition pool. In locked state, members cannot be\\n /// inserted and removed from the pool. Members statuses cannot\\n /// be updated as well.\\n /// @dev Can be called only by the contract owner.\\n function lock() public onlyOwner {\\n isLocked = true;\\n }\\n\\n /// @notice Unlocks the sortition pool. Removes all restrictions set by\\n /// the `lock` method.\\n /// @dev Can be called only by the contract owner.\\n function unlock() public onlyOwner {\\n isLocked = false;\\n }\\n\\n /// @notice Inserts an operator to the pool. Reverts if the operator is\\n /// already present. Reverts if the operator is not eligible because of their\\n /// authorized stake. Reverts if the chaosnet is active and the operator is\\n /// not a beta operator.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the inserted operator.\\n /// @param authorizedStake Inserted operator's authorized stake for the application.\\n function insertOperator(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n require(weight > 0, \\\"Operator not eligible\\\");\\n\\n if (isChaosnetActive) {\\n require(isBetaOperator[operator], \\\"Not beta operator for chaosnet\\\");\\n }\\n\\n _insertOperator(operator, weight);\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n }\\n\\n /// @notice Update the operator's weight if present and eligible,\\n /// or remove from the pool if present and ineligible.\\n /// @dev Can be called only by the contract owner.\\n /// @param operator Address of the updated operator.\\n /// @param authorizedStake Operator's authorized stake for the application.\\n function updateOperatorStatus(address operator, uint256 authorizedStake)\\n public\\n onlyOwner\\n onlyUnlocked\\n {\\n uint256 weight = getWeight(authorizedStake);\\n\\n uint32 id = getOperatorID(operator);\\n Rewards.updateOperatorRewards(id, uint32(weight));\\n\\n if (weight == 0) {\\n _removeOperator(operator);\\n } else {\\n updateOperator(operator, weight);\\n }\\n }\\n\\n /// @notice Set the given operators as ineligible for rewards.\\n /// The operators can restore their eligibility at the given time.\\n function setRewardIneligibility(uint32[] calldata operators, uint256 until)\\n public\\n onlyOwner\\n {\\n Rewards.setIneligible(operators, until);\\n emit IneligibleForRewards(operators, until);\\n }\\n\\n /// @notice Restores reward eligibility for the operator.\\n function restoreRewardEligibility(address operator) public {\\n uint32 id = getOperatorID(operator);\\n Rewards.restoreEligibility(id);\\n emit RewardEligibilityRestored(operator, id);\\n }\\n\\n /// @notice Returns whether the operator is eligible for rewards or not.\\n function isEligibleForRewards(address operator) public view returns (bool) {\\n uint32 id = getOperatorID(operator);\\n return Rewards.isEligibleForRewards(id);\\n }\\n\\n /// @notice Returns the time the operator's reward eligibility can be restored.\\n function rewardsEligibilityRestorableAt(address operator)\\n public\\n view\\n returns (uint256)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.rewardsEligibilityRestorableAt(id);\\n }\\n\\n /// @notice Returns whether the operator is able to restore their eligibility\\n /// for rewards right away.\\n function canRestoreRewardEligibility(address operator)\\n public\\n view\\n returns (bool)\\n {\\n uint32 id = getOperatorID(operator);\\n return Rewards.canRestoreRewardEligibility(id);\\n }\\n\\n /// @notice Returns the amount of rewards withdrawable for the given operator.\\n function getAvailableRewards(address operator) public view returns (uint96) {\\n uint32 id = getOperatorID(operator);\\n return availableRewards(id);\\n }\\n\\n /// @notice Return whether the operator is present in the pool.\\n function isOperatorInPool(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Return whether the operator's weight in the pool\\n /// matches their eligible weight.\\n function isOperatorUpToDate(address operator, uint256 authorizedStake)\\n public\\n view\\n returns (bool)\\n {\\n return getWeight(authorizedStake) == getPoolWeight(operator);\\n }\\n\\n /// @notice Return the weight of the operator in the pool,\\n /// which may or may not be out of date.\\n function getPoolWeight(address operator) public view returns (uint256) {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n if (flaggedPosition == 0) {\\n return 0;\\n } else {\\n uint256 leafPosition = flaggedPosition.unsetFlag();\\n uint256 leafWeight = getLeafWeight(leafPosition);\\n return leafWeight;\\n }\\n }\\n\\n /// @notice Selects a new group of operators of the provided size based on\\n /// the provided pseudo-random seed. At least one operator has to be\\n /// registered in the pool, otherwise the function fails reverting the\\n /// transaction.\\n /// @param groupSize Size of the requested group\\n /// @param seed Pseudo-random number used to select operators to group\\n /// @return selected Members of the selected group\\n function selectGroup(uint256 groupSize, bytes32 seed)\\n public\\n view\\n onlyLocked\\n returns (uint32[] memory)\\n {\\n uint256 _root = root;\\n\\n bytes32 rngState = seed;\\n uint256 rngRange = _root.sumWeight();\\n require(rngRange > 0, \\\"Not enough operators in pool\\\");\\n uint256 currentIndex;\\n\\n uint256 bits = RNG.bitsRequired(rngRange);\\n\\n uint32[] memory selected = new uint32[](groupSize);\\n\\n for (uint256 i = 0; i < groupSize; i++) {\\n (currentIndex, rngState) = RNG.getIndex(rngRange, rngState, bits);\\n\\n uint256 leafPosition = pickWeightedLeaf(currentIndex, _root);\\n\\n uint256 leaf = leaves[leafPosition];\\n selected[i] = leaf.id();\\n }\\n return selected;\\n }\\n\\n function getWeight(uint256 authorization) internal view returns (uint256) {\\n return authorization / poolWeightDivisor;\\n }\\n}\\n\",\"keccak256\":\"0xab42e7c5b1828f42a73f699eb2dc96d4f793572a6323b8b1fbd7c5e0c065bda7\"},\"@keep-network/sortition-pools/contracts/SortitionTree.sol\":{\"content\":\"pragma solidity 0.8.17;\\n\\nimport \\\"./Branch.sol\\\";\\nimport \\\"./Position.sol\\\";\\nimport \\\"./Leaf.sol\\\";\\nimport \\\"./Constants.sol\\\";\\n\\ncontract SortitionTree {\\n using Branch for uint256;\\n using Position for uint256;\\n using Leaf for uint256;\\n\\n // implicit tree\\n // root 8\\n // level2 64\\n // level3 512\\n // level4 4k\\n // level5 32k\\n // level6 256k\\n // level7 2M\\n uint256 internal root;\\n\\n // A 2-index mapping from layer => (index (0-index) => branch). For example,\\n // to access the 6th branch in the 2nd layer (right below the root node; the\\n // first branch layer), call branches[2][5]. Mappings are used in place of\\n // arrays for efficiency. The root is the first layer, the branches occupy\\n // layers 2 through 7, and layer 8 is for the leaves. Following this\\n // convention, the first index in `branches` is `2`, and the last index is\\n // `7`.\\n mapping(uint256 => mapping(uint256 => uint256)) internal branches;\\n\\n // A 0-index mapping from index => leaf, acting as an array. For example, to\\n // access the 42nd leaf, call leaves[41].\\n mapping(uint256 => uint256) internal leaves;\\n\\n // the flagged (see setFlag() and unsetFlag() in Position.sol) positions\\n // of all operators present in the pool\\n mapping(address => uint256) internal flaggedLeafPosition;\\n\\n // the leaf after the rightmost occupied leaf of each stack\\n uint256 internal rightmostLeaf;\\n\\n // the empty leaves in each stack\\n // between 0 and the rightmost occupied leaf\\n uint256[] internal emptyLeaves;\\n\\n // Each operator has an uint32 ID number\\n // which is allocated when they first join the pool\\n // and remains unchanged even if they leave and rejoin the pool.\\n mapping(address => uint32) internal operatorID;\\n\\n // The idAddress array records the address corresponding to each ID number.\\n // The ID number 0 is initialized with a zero address and is not used.\\n address[] internal idAddress;\\n\\n constructor() {\\n root = 0;\\n rightmostLeaf = 0;\\n idAddress.push();\\n }\\n\\n /// @notice Return the ID number of the given operator address. An ID number\\n /// of 0 means the operator has not been allocated an ID number yet.\\n /// @param operator Address of the operator.\\n /// @return the ID number of the given operator address\\n function getOperatorID(address operator) public view returns (uint32) {\\n return operatorID[operator];\\n }\\n\\n /// @notice Get the operator address corresponding to the given ID number. A\\n /// zero address means the ID number has not been allocated yet.\\n /// @param id ID of the operator\\n /// @return the address of the operator\\n function getIDOperator(uint32 id) public view returns (address) {\\n return idAddress.length > id ? idAddress[id] : address(0);\\n }\\n\\n /// @notice Gets the operator addresses corresponding to the given ID\\n /// numbers. A zero address means the ID number has not been allocated yet.\\n /// This function works just like getIDOperator except that it allows to fetch\\n /// operator addresses for multiple IDs in one call.\\n /// @param ids the array of the operator ids\\n /// @return an array of the associated operator addresses\\n function getIDOperators(uint32[] calldata ids)\\n public\\n view\\n returns (address[] memory)\\n {\\n uint256 idCount = idAddress.length;\\n\\n address[] memory operators = new address[](ids.length);\\n for (uint256 i = 0; i < ids.length; i++) {\\n uint32 id = ids[i];\\n operators[i] = idCount > id ? idAddress[id] : address(0);\\n }\\n return operators;\\n }\\n\\n /// @notice Checks if operator is already registered in the pool.\\n /// @param operator the address of the operator\\n /// @return whether or not the operator is already registered in the pool\\n function isOperatorRegistered(address operator) public view returns (bool) {\\n return getFlaggedLeafPosition(operator) != 0;\\n }\\n\\n /// @notice Sum the number of operators in each trunk.\\n /// @return the number of operators in the pool\\n function operatorsInPool() public view returns (uint256) {\\n // Get the number of leaves that might be occupied;\\n // if `rightmostLeaf` equals `firstLeaf()` the tree must be empty,\\n // otherwise the difference between these numbers\\n // gives the number of leaves that may be occupied.\\n uint256 nPossiblyUsedLeaves = rightmostLeaf;\\n // Get the number of empty leaves\\n // not accounted for by the `rightmostLeaf`\\n uint256 nEmptyLeaves = emptyLeaves.length;\\n\\n return (nPossiblyUsedLeaves - nEmptyLeaves);\\n }\\n\\n /// @notice Convenience method to return the total weight of the pool\\n /// @return the total weight of the pool\\n function totalWeight() public view returns (uint256) {\\n return root.sumWeight();\\n }\\n\\n /// @notice Give the operator a new ID number.\\n /// Does not check if the operator already has an ID number.\\n /// @param operator the address of the operator\\n /// @return a new ID for that operator\\n function allocateOperatorID(address operator) internal returns (uint256) {\\n uint256 id = idAddress.length;\\n\\n require(id <= type(uint32).max, \\\"Pool capacity exceeded\\\");\\n\\n operatorID[operator] = uint32(id);\\n idAddress.push(operator);\\n return id;\\n }\\n\\n /// @notice Inserts an operator into the sortition pool\\n /// @param operator the address of an operator to insert\\n /// @param weight how much weight that operator has in the pool\\n function _insertOperator(address operator, uint256 weight) internal {\\n require(\\n !isOperatorRegistered(operator),\\n \\\"Operator is already registered in the pool\\\"\\n );\\n\\n // Fetch the operator's ID, and if they don't have one, allocate them one.\\n uint256 id = getOperatorID(operator);\\n if (id == 0) {\\n id = allocateOperatorID(operator);\\n }\\n\\n // Determine which leaf to insert them into\\n uint256 position = getEmptyLeafPosition();\\n // Record the block the operator was inserted in\\n uint256 theLeaf = Leaf.make(operator, block.number, id);\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = setLeaf(position, theLeaf, weight, root);\\n\\n // Without position flags,\\n // the position 0x000000 would be treated as empty\\n flaggedLeafPosition[operator] = position.setFlag();\\n }\\n\\n /// @notice Remove an operator (and their weight) from the pool.\\n /// @param operator the address of the operator to remove\\n function _removeOperator(address operator) internal {\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n require(flaggedPosition != 0, \\\"Operator is not registered in the pool\\\");\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n\\n // Update the leaf, and propagate the weight changes all the way up to the\\n // root.\\n root = removeLeaf(unflaggedPosition, root);\\n removeLeafPositionRecord(operator);\\n }\\n\\n /// @notice Update an operator's weight in the pool.\\n /// @param operator the address of the operator to update\\n /// @param weight the new weight\\n function updateOperator(address operator, uint256 weight) internal {\\n require(\\n isOperatorRegistered(operator),\\n \\\"Operator is not registered in the pool\\\"\\n );\\n\\n uint256 flaggedPosition = getFlaggedLeafPosition(operator);\\n uint256 unflaggedPosition = flaggedPosition.unsetFlag();\\n root = updateLeaf(unflaggedPosition, weight, root);\\n }\\n\\n /// @notice Helper method to remove a leaf position record for an operator.\\n /// @param operator the address of the operator to remove the record for\\n function removeLeafPositionRecord(address operator) internal {\\n flaggedLeafPosition[operator] = 0;\\n }\\n\\n /// @notice Removes the data and weight from a particular leaf.\\n /// @param position the leaf index to remove\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function removeLeaf(uint256 position, uint256 _root)\\n internal\\n returns (uint256)\\n {\\n uint256 rightmostSubOne = rightmostLeaf - 1;\\n bool isRightmost = position == rightmostSubOne;\\n\\n // Clears out the data in the leaf node, and then propagates the weight\\n // changes all the way up to the root.\\n uint256 newRoot = setLeaf(position, 0, 0, _root);\\n\\n // Infer if need to fall back on emptyLeaves yet\\n if (isRightmost) {\\n rightmostLeaf = rightmostSubOne;\\n } else {\\n emptyLeaves.push(position);\\n }\\n return newRoot;\\n }\\n\\n /// @notice Updates the tree to give a particular leaf a new weight.\\n /// @param position the index of the leaf to update\\n /// @param weight the new weight\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateLeaf(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n if (getLeafWeight(position) != weight) {\\n return updateTree(position, weight, _root);\\n } else {\\n return _root;\\n }\\n }\\n\\n /// @notice Places a leaf into a particular position, with a given weight and\\n /// propagates that change.\\n /// @param position the index to place the leaf in\\n /// @param theLeaf the new leaf to place in the position\\n /// @param leafWeight the weight of the leaf\\n /// @param _root the root containing the new leaf\\n /// @return the updated root node\\n function setLeaf(\\n uint256 position,\\n uint256 theLeaf,\\n uint256 leafWeight,\\n uint256 _root\\n ) internal returns (uint256) {\\n // set leaf\\n leaves[position] = theLeaf;\\n\\n return (updateTree(position, leafWeight, _root));\\n }\\n\\n /// @notice Propagates a weight change at a position through the tree,\\n /// eventually returning the updated root.\\n /// @param position the index of leaf to update\\n /// @param weight the new weight of the leaf\\n /// @param _root the root node containing the leaf\\n /// @return the updated root node\\n function updateTree(\\n uint256 position,\\n uint256 weight,\\n uint256 _root\\n ) internal returns (uint256) {\\n uint256 childSlot;\\n uint256 treeNode;\\n uint256 newNode;\\n uint256 nodeWeight = weight;\\n\\n uint256 parent = position;\\n // set levels 7 to 2\\n for (uint256 level = Constants.LEVELS; level >= 2; level--) {\\n childSlot = parent.slot();\\n parent = parent.parent();\\n treeNode = branches[level][parent];\\n newNode = treeNode.setSlot(childSlot, nodeWeight);\\n branches[level][parent] = newNode;\\n nodeWeight = newNode.sumWeight();\\n }\\n\\n // set level Root\\n childSlot = parent.slot();\\n return _root.setSlot(childSlot, nodeWeight);\\n }\\n\\n /// @notice Retrieves the next available empty leaf position. Tries to fill\\n /// left to right first, ignoring leaf removals, and then fills\\n /// most-recent-removals first.\\n /// @return the position of the empty leaf\\n function getEmptyLeafPosition() internal returns (uint256) {\\n uint256 rLeaf = rightmostLeaf;\\n bool spaceOnRight = (rLeaf + 1) < Constants.POOL_CAPACITY;\\n if (spaceOnRight) {\\n rightmostLeaf = rLeaf + 1;\\n return rLeaf;\\n } else {\\n uint256 emptyLeafCount = emptyLeaves.length;\\n require(emptyLeafCount > 0, \\\"Pool is full\\\");\\n uint256 emptyLeaf = emptyLeaves[emptyLeafCount - 1];\\n emptyLeaves.pop();\\n return emptyLeaf;\\n }\\n }\\n\\n /// @notice Gets the flagged leaf position for an operator.\\n /// @param operator the address of the operator\\n /// @return the leaf position of that operator\\n function getFlaggedLeafPosition(address operator)\\n internal\\n view\\n returns (uint256)\\n {\\n return flaggedLeafPosition[operator];\\n }\\n\\n /// @notice Gets the weight of a leaf at a particular position.\\n /// @param position the index of the leaf\\n /// @return the weight of the leaf at that position\\n function getLeafWeight(uint256 position) internal view returns (uint256) {\\n uint256 slot = position.slot();\\n uint256 parent = position.parent();\\n\\n // A leaf's weight information is stored a 32-bit slot in the branch layer\\n // directly above the leaf layer. To access it, we calculate that slot and\\n // parent position, and always know the hard-coded layer index.\\n uint256 node = branches[Constants.LEVELS][parent];\\n return node.getSlot(slot);\\n }\\n\\n /// @notice Picks a leaf given a random index.\\n /// @param index a number in `[0, _root.totalWeight())` used to decide\\n /// between leaves\\n /// @param _root the root of the tree\\n function pickWeightedLeaf(uint256 index, uint256 _root)\\n internal\\n view\\n returns (uint256 leafPosition)\\n {\\n uint256 currentIndex = index;\\n uint256 currentNode = _root;\\n uint256 currentPosition = 0;\\n uint256 currentSlot;\\n\\n require(index < currentNode.sumWeight(), \\\"Index exceeds weight\\\");\\n\\n // get root slot\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n\\n // get slots from levels 2 to 7\\n for (uint256 level = 2; level <= Constants.LEVELS; level++) {\\n currentPosition = currentPosition.child(currentSlot);\\n currentNode = branches[level][currentPosition];\\n (currentSlot, currentIndex) = currentNode.pickWeightedSlot(currentIndex);\\n }\\n\\n // get leaf position\\n leafPosition = currentPosition.child(currentSlot);\\n }\\n}\\n\",\"keccak256\":\"0x51daeca62ef52be78a1a9de4d2a1c5900c873165f59eda14d5965d7d7da90a03\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n // Inspired by OraclizeAPI's implementation - MIT licence\\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint256 temp = value;\\n uint256 digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0x00\\\";\\n }\\n uint256 temp = value;\\n uint256 length = 0;\\n while (temp != 0) {\\n length++;\\n temp >>= 8;\\n }\\n return toHexString(value, length);\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xaf159a8b1923ad2a26d516089bceca9bdeaeacd04be50983ea00ba63070f08a3\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n } else if (error == RecoverError.InvalidSignatureV) {\\n revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n if (v != 27 && v != 28) {\\n return (address(0), RecoverError.InvalidSignatureV);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xdb7f5c28fc61cda0bd8ab60ce288e206b791643bcd3ba464a70cbec18895a2f5\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by tokens supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IApproveAndCall {\\n /// @notice Executes `receiveApproval` function on spender as specified in\\n /// `IReceiveApproval` interface. Approves spender to withdraw from\\n /// the caller multiple times, up to the `amount`. If this\\n /// function is called again, it overwrites the current allowance\\n /// with `amount`. Reverts if the approval reverted or if\\n /// `receiveApproval` call on the spender reverted.\\n function approveAndCall(\\n address spender,\\n uint256 amount,\\n bytes memory extraData\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x393d18ef81a57dcc96fff4c340cc2945deaebb37b9796c322cf2bc96872c3df8\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IERC20WithPermit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\n\\nimport \\\"./IApproveAndCall.sol\\\";\\n\\n/// @title IERC20WithPermit\\n/// @notice Burnable ERC20 token with EIP2612 permit functionality. User can\\n/// authorize a transfer of their token with a signature conforming\\n/// EIP712 standard instead of an on-chain transaction from their\\n/// address. Anyone can submit this signature on the user's behalf by\\n/// calling the permit function, as specified in EIP2612 standard,\\n/// paying gas fees, and possibly performing other actions in the same\\n/// transaction.\\ninterface IERC20WithPermit is IERC20, IERC20Metadata, IApproveAndCall {\\n /// @notice EIP2612 approval made with secp256k1 signature.\\n /// Users can authorize a transfer of their tokens with a signature\\n /// conforming EIP712 standard, rather than an on-chain transaction\\n /// from their address. Anyone can submit this signature on the\\n /// user's behalf by calling the permit function, paying gas fees,\\n /// and possibly performing other actions in the same transaction.\\n /// @dev The deadline argument can be set to `type(uint256).max to create\\n /// permits that effectively never expire.\\n function permit(\\n address owner,\\n address spender,\\n uint256 amount,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /// @notice Destroys `amount` tokens from the caller.\\n function burn(uint256 amount) external;\\n\\n /// @notice Destroys `amount` of tokens from `account`, deducting the amount\\n /// from caller's allowance.\\n function burnFrom(address account, uint256 amount) external;\\n\\n /// @notice Returns hash of EIP712 Domain struct with the token name as\\n /// a signing domain and token contract as a verifying contract.\\n /// Used to construct EIP2612 signature provided to `permit`\\n /// function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n /// @notice Returns the current nonce for EIP2612 permission for the\\n /// provided token owner for a replay protection. Used to construct\\n /// EIP2612 signature provided to `permit` function.\\n function nonce(address owner) external view returns (uint256);\\n\\n /// @notice Returns EIP2612 Permit message hash. Used to construct EIP2612\\n /// signature provided to `permit` function.\\n /* solhint-disable-next-line func-name-mixedcase */\\n function PERMIT_TYPEHASH() external pure returns (bytes32);\\n}\\n\",\"keccak256\":\"0xdac9a5086c19a7128b505a7be1ab0ac1aa314f6989cb88d2417e9d7383f89fa9\",\"license\":\"MIT\"},\"@thesis/solidity-contracts/contracts/token/IReceiveApproval.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.4;\\n\\n/// @notice An interface that should be implemented by contracts supporting\\n/// `approveAndCall`/`receiveApproval` pattern.\\ninterface IReceiveApproval {\\n /// @notice Receives approval to spend tokens. Called as a result of\\n /// `approveAndCall` call on the token.\\n function receiveApproval(\\n address from,\\n uint256 amount,\\n address token,\\n bytes calldata extraData\\n ) external;\\n}\\n\",\"keccak256\":\"0x6a30d83ad230548b1e7839737affc8489a035314209de14b89dbef7fb0f66395\",\"license\":\"MIT\"},\"contracts/libraries/BeaconInactivity.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n// Trust math, not hardware.\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./BytesLib.sol\\\";\\nimport \\\"./Groups.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@keep-network/sortition-pools/contracts/SortitionPool.sol\\\";\\n\\nlibrary BeaconInactivity {\\n using BytesLib for bytes;\\n using ECDSA for bytes32;\\n\\n struct Claim {\\n // ID of the group raising the inactivity claim.\\n uint64 groupId;\\n // Indices of members accused of being inactive. Indices must be in\\n // range [1, groupMembers.length], unique, and sorted in ascending order.\\n uint256[] inactiveMembersIndices;\\n // Concatenation of signatures from members supporting the claim.\\n // The message to be signed by each member is keccak256 hash of the\\n // concatenation of the chain ID, inactivity claim nonce for the given\\n // group, group public key, and inactive members indices. The calculated\\n // hash should be prefixed with `\\\\x19Ethereum signed message:\\\\n` before\\n // signing, so the message to sign is:\\n // `\\\\x19Ethereum signed message:\\\\n${keccak256(\\n // chainID | nonce | groupPubKey | inactiveMembersIndices\\n // )}`\\n bytes signatures;\\n // Indices of members corresponding to each signature. Indices must be\\n // in range [1, groupMembers.length], unique, and sorted in ascending\\n // order.\\n uint256[] signingMembersIndices;\\n }\\n\\n /// @notice The minimum number of group members needed to interact according\\n /// to the protocol to produce a valid inactivity claim.\\n uint256 public constant groupThreshold = 33;\\n\\n /// @notice Size in bytes of a single signature produced by member\\n /// supporting the inactivity claim.\\n uint256 public constant signatureByteSize = 65;\\n\\n /// @notice Verifies the inactivity claim according to the rules defined in\\n /// `Claim` struct documentation. Reverts if verification fails.\\n /// @dev Group members hash is validated upstream in\\n /// RandomBeacon.notifyOperatorInactivity()\\n /// @param sortitionPool Sortition pool reference\\n /// @param claim Inactivity claim\\n /// @param groupPubKey Public key of the group raising the claim\\n /// @param nonce Current nonce for group used in the claim\\n /// @param groupMembers Identifiers of group members\\n /// @return inactiveMembers Identifiers of members who are inactive\\n function verifyClaim(\\n SortitionPool sortitionPool,\\n Claim calldata claim,\\n bytes memory groupPubKey,\\n uint256 nonce,\\n uint32[] calldata groupMembers\\n ) external view returns (uint32[] memory inactiveMembers) {\\n // Validate inactive members indices. Maximum indices count is equal to\\n // the group size and is not limited deliberately to leave a theoretical\\n // possibility to accuse more members than `groupSize - groupThreshold`.\\n validateMembersIndices(\\n claim.inactiveMembersIndices,\\n groupMembers.length\\n );\\n\\n // Validate signatures array is properly formed and number of\\n // signatures and signers is correct.\\n uint256 signaturesCount = claim.signatures.length / signatureByteSize;\\n require(claim.signatures.length != 0, \\\"No signatures provided\\\");\\n require(\\n claim.signatures.length % signatureByteSize == 0,\\n \\\"Malformed signatures array\\\"\\n );\\n require(\\n signaturesCount == claim.signingMembersIndices.length,\\n \\\"Unexpected signatures count\\\"\\n );\\n require(signaturesCount >= groupThreshold, \\\"Too few signatures\\\");\\n require(signaturesCount <= groupMembers.length, \\\"Too many signatures\\\");\\n\\n // Validate signing members indices. Note that `signingMembersIndices`\\n // were already partially validated during `signatures` parameter\\n // validation.\\n validateMembersIndices(\\n claim.signingMembersIndices,\\n groupMembers.length\\n );\\n\\n // Usage of group public key and not group ID is important because it\\n // provides uniqueness of signed messages and prevent against reusing\\n // them in future in case some other application has a group with the\\n // same ID and subset of members.\\n bytes32 signedMessageHash = keccak256(\\n abi.encode(\\n block.chainid,\\n nonce,\\n groupPubKey,\\n claim.inactiveMembersIndices\\n )\\n ).toEthSignedMessageHash();\\n\\n address[] memory groupMembersAddresses = sortitionPool.getIDOperators(\\n groupMembers\\n );\\n\\n // Verify each signature.\\n bytes memory checkedSignature;\\n bool senderSignatureExists = false;\\n for (uint256 i = 0; i < signaturesCount; i++) {\\n uint256 memberIndex = claim.signingMembersIndices[i];\\n checkedSignature = claim.signatures.slice(\\n signatureByteSize * i,\\n signatureByteSize\\n );\\n address recoveredAddress = signedMessageHash.recover(\\n checkedSignature\\n );\\n\\n require(\\n groupMembersAddresses[memberIndex - 1] == recoveredAddress,\\n \\\"Invalid signature\\\"\\n );\\n\\n if (!senderSignatureExists && msg.sender == recoveredAddress) {\\n senderSignatureExists = true;\\n }\\n }\\n\\n require(senderSignatureExists, \\\"Sender must be claim signer\\\");\\n\\n inactiveMembers = new uint32[](claim.inactiveMembersIndices.length);\\n for (uint256 i = 0; i < claim.inactiveMembersIndices.length; i++) {\\n uint256 memberIndex = claim.inactiveMembersIndices[i];\\n inactiveMembers[i] = groupMembers[memberIndex - 1];\\n }\\n\\n return inactiveMembers;\\n }\\n\\n /// @notice Validates members indices array. Array is considered valid\\n /// if its size and each single index are in [1, groupSize] range,\\n /// indexes are unique, and sorted in an ascending order.\\n /// Reverts if validation fails.\\n /// @param indices Array to validate\\n /// @param groupSize Group size used as reference\\n function validateMembersIndices(\\n uint256[] calldata indices,\\n uint256 groupSize\\n ) internal pure {\\n require(\\n indices.length > 0 && indices.length <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n // Check if first and last indices are in range [1, groupSize].\\n // This check combined with the loop below makes sure every single\\n // index is in the correct range.\\n require(\\n indices[0] > 0 && indices[indices.length - 1] <= groupSize,\\n \\\"Corrupted members indices\\\"\\n );\\n\\n for (uint256 i = 0; i < indices.length - 1; i++) {\\n // Check whether given index is smaller than the next one. This\\n // way we are sure indexes are ordered in the ascending order\\n // and there are no duplicates.\\n require(indices[i] < indices[i + 1], \\\"Corrupted members indices\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8dffb20eb4ffd2e388080c5fbcb648e33480aca3dab4be2254cf30c5e72413bf\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/BytesLib.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/*\\nVersion pulled from keep-core v1:\\nhttps://github.com/keep-network/keep-core/blob/f297202db00c027978ad8e7103a356503de5773c/solidity-v1/contracts/utils/BytesLib.sol\\n\\nTo compile it with solidity 0.8 `_preBytes_slot` was replaced with `_preBytes.slot`.\\n*/\\n\\n/*\\nhttps://github.com/GNSPS/solidity-bytes-utils/\\nThis is free and unencumbered software released into the public domain.\\nAnyone is free to copy, modify, publish, use, compile, sell, or\\ndistribute this software, either in source code form or as a compiled\\nbinary, for any purpose, commercial or non-commercial, and by any\\nmeans.\\nIn jurisdictions that recognize copyright laws, the author or authors\\nof this software dedicate any and all copyright interest in the\\nsoftware to the public domain. We make this dedication for the benefit\\nof the public at large and to the detriment of our heirs and\\nsuccessors. We intend this dedication to be an overt act of\\nrelinquishment in perpetuity of all present and future rights to this\\nsoftware under copyright law.\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND,\\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\\nOTHER DEALINGS IN THE SOFTWARE.\\nFor more information, please refer to <https://unlicense.org>\\n*/\\n\\n/** @title BytesLib **/\\n/** @author https://github.com/GNSPS **/\\n\\nlibrary BytesLib {\\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n {\\n assembly {\\n // Read the first 32 bytes of _preBytes storage, which is the length\\n // of the array. (We don't need to use the offset into the slot\\n // because arrays use the entire slot.)\\n let fslot := sload(_preBytes.slot)\\n // Arrays of 31 bytes or less have an even value in their slot,\\n // while longer arrays have an odd value. The actual length is\\n // the slot divided by two for odd values, and the lowest order\\n // byte divided by two for even values.\\n // If the slot is even, bitwise and the slot with 255 and divide by\\n // two to get the length. If the slot is odd, bitwise and the slot\\n // with -1 and divide by two.\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n let newlength := add(slength, mlength)\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n switch add(lt(slength, 32), lt(newlength, 32))\\n case 2 {\\n // Since the new array still fits in the slot, we just need to\\n // update the contents of the slot.\\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\\n sstore(\\n _preBytes.slot,\\n // all the modifications to the slot are inside this\\n // next block\\n add(\\n // we can just add to the slot contents because the\\n // bytes we want to change are the LSBs\\n fslot,\\n add(\\n mul(\\n div(\\n // load the bytes from memory\\n mload(add(_postBytes, 0x20)),\\n // zero all bytes to the right\\n exp(0x100, sub(32, mlength))\\n ),\\n // and now shift left the number of bytes to\\n // leave space for the length in the slot\\n exp(0x100, sub(32, newlength))\\n ),\\n // increase length by the double of the memory\\n // bytes length\\n mul(mlength, 2)\\n )\\n )\\n )\\n }\\n case 1 {\\n // The stored value fits in the slot, but the combined value\\n // will exceed it.\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // The contents of the _postBytes array start 32 bytes into\\n // the structure. Our first read should obtain the `submod`\\n // bytes that can fit into the unused space in the last word\\n // of the stored array. To get this, we read 32 bytes starting\\n // from `submod`, so the data we read overlaps with the array\\n // contents by `submod` bytes. Masking the lowest-order\\n // `submod` bytes allows us to add that value directly to the\\n // stored value.\\n\\n let submod := sub(32, slength)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(\\n sc,\\n add(\\n and(\\n fslot,\\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\\n ),\\n and(mload(mc), mask)\\n )\\n )\\n\\n for {\\n mc := add(mc, 0x20)\\n sc := add(sc, 1)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n default {\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n // Start copying to the last used word of the stored array.\\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\\n\\n // save new length\\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\\n\\n // Copy over the first `submod` bytes of the new data as in\\n // case 1 above.\\n let slengthmod := mod(slength, 32)\\n let submod := sub(32, slengthmod)\\n let mc := add(_postBytes, submod)\\n let end := add(_postBytes, mlength)\\n let mask := sub(exp(0x100, submod), 1)\\n\\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\\n\\n for {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } lt(mc, end) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n sstore(sc, mload(mc))\\n }\\n\\n mask := exp(0x100, sub(mc, end))\\n\\n sstore(sc, mul(div(mload(mc), mask), mask))\\n }\\n }\\n }\\n\\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes)\\n internal\\n view\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n // we know _preBytes_offset is 0\\n let fslot := sload(_preBytes.slot)\\n // Decode the length of the stored array like in concatStorage().\\n let slength := div(\\n and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)),\\n 2\\n )\\n let mlength := mload(_postBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(slength, mlength)\\n case 1 {\\n // slength can contain both the length and contents of the array\\n // if length < 32 bytes so let's prepare for that\\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\\n if iszero(iszero(slength)) {\\n switch lt(slength, 32)\\n case 1 {\\n // blank the last byte which is the length\\n fslot := mul(div(fslot, 0x100), 0x100)\\n\\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\\n // unsuccess:\\n success := 0\\n }\\n }\\n default {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n // get the keccak hash to get the contents of the array\\n mstore(0x0, _preBytes.slot)\\n let sc := keccak256(0x0, 0x20)\\n\\n let mc := add(_postBytes, 0x20)\\n let end := add(mc, mlength)\\n\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n for {\\n\\n } eq(add(lt(mc, end), cb), 2) {\\n sc := add(sc, 1)\\n mc := add(mc, 0x20)\\n } {\\n if iszero(eq(sload(sc), mload(mc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function concat(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bytes memory)\\n {\\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 res) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n // Alloc bytes array with additional 32 bytes afterspace and assign it's size\\n res := mload(0x40)\\n mstore(0x40, add(add(res, 64), _length))\\n mstore(res, _length)\\n\\n // Compute distance between source and destination pointers\\n let diff := sub(res, add(_bytes, _start))\\n\\n for {\\n let src := add(add(_bytes, 32), _start)\\n let end := add(src, _length)\\n } lt(src, end) {\\n src := add(src, 32)\\n } {\\n mstore(add(src, diff), mload(src))\\n }\\n }\\n }\\n\\n function toAddress(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (address)\\n {\\n uint256 _totalLen = _start + 20;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Address conversion out of bounds.\\\"\\n );\\n address tempAddress;\\n\\n assembly {\\n tempAddress := div(\\n mload(add(add(_bytes, 0x20), _start)),\\n 0x1000000000000000000000000\\n )\\n }\\n\\n return tempAddress;\\n }\\n\\n function toUint8(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint8)\\n {\\n require(\\n _bytes.length >= (_start + 1),\\n \\\"Uint8 conversion out of bounds.\\\"\\n );\\n uint8 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x1), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function toUint(bytes memory _bytes, uint256 _start)\\n internal\\n pure\\n returns (uint256)\\n {\\n uint256 _totalLen = _start + 32;\\n require(\\n _totalLen > _start && _bytes.length >= _totalLen,\\n \\\"Uint conversion out of bounds.\\\"\\n );\\n uint256 tempUint;\\n\\n assembly {\\n tempUint := mload(add(add(_bytes, 0x20), _start))\\n }\\n\\n return tempUint;\\n }\\n\\n function equal(bytes memory _preBytes, bytes memory _postBytes)\\n internal\\n pure\\n returns (bool)\\n {\\n bool success = true;\\n\\n assembly {\\n let length := mload(_preBytes)\\n\\n // if lengths don't match the arrays are not equal\\n switch eq(length, mload(_postBytes))\\n case 1 {\\n // cb is a circuit breaker in the for loop since there's\\n // no said feature for inline assembly loops\\n // cb = 1 - don't breaker\\n // cb = 0 - break\\n let cb := 1\\n\\n let mc := add(_preBytes, 0x20)\\n let end := add(mc, length)\\n\\n for {\\n let cc := add(_postBytes, 0x20)\\n // the next line is the loop condition:\\n // while(uint(mc < end) + cb == 2)\\n } eq(add(lt(mc, end), cb), 2) {\\n mc := add(mc, 0x20)\\n cc := add(cc, 0x20)\\n } {\\n // if any of these checks fails then arrays are not equal\\n if iszero(eq(mload(mc), mload(cc))) {\\n // unsuccess:\\n success := 0\\n cb := 0\\n }\\n }\\n }\\n default {\\n // unsuccess:\\n success := 0\\n }\\n }\\n\\n return success;\\n }\\n\\n function toBytes32(bytes memory _source)\\n internal\\n pure\\n returns (bytes32 result)\\n {\\n if (_source.length == 0) {\\n return 0x0;\\n }\\n\\n assembly {\\n result := mload(add(_source, 32))\\n }\\n }\\n\\n function keccak256Slice(\\n bytes memory _bytes,\\n uint256 _start,\\n uint256 _length\\n ) internal pure returns (bytes32 result) {\\n uint256 _end = _start + _length;\\n require(_end > _start && _bytes.length >= _end, \\\"Slice out of bounds\\\");\\n\\n assembly {\\n result := keccak256(add(add(_bytes, 32), _start), _length)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b76e2fe36eb777440250dcf2ea7a689375e8af22f3cc33521095ff6954becdb\",\"license\":\"GPL-3.0-only\"},\"contracts/libraries/Groups.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n//\\n// \\u2593\\u2593\\u258c \\u2593\\u2593 \\u2590\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584\\u2584\\u2584\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\u2580\\u2580\\u2580 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2580\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2580\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2584 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u258c\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2588\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2590\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\n//\\n//\\n\\npragma solidity 0.8.17;\\n\\n/// @notice This library is used as a registry of created groups.\\n/// @dev This library should be used along with DKG library that ensures linear\\n/// groups creation (only one group creation happens at a time). A candidate\\n/// group has to be popped or activated before adding a new candidate group.\\nlibrary Groups {\\n struct Group {\\n bytes groupPubKey;\\n uint256 registrationBlockNumber;\\n // Keccak256 hash of group members identifiers array. Group members do not\\n // include operators selected by the sortition pool that misbehaved during DKG.\\n // See how `misbehavedMembersIndices` are used in `hashGroupMembers` function.\\n bytes32 membersHash;\\n // When selected group does not create a relay entry on-time it should\\n // be marked as terminated.\\n bool terminated;\\n }\\n\\n struct Data {\\n // Mapping of keccak256 hashes of group public keys to groups details.\\n mapping(bytes32 => Group) groupsData;\\n // Holds keccak256 hashes of group public keys in the order of registration.\\n bytes32[] groupsRegistry;\\n // Group ids that were active but failed creating a relay entry. When an\\n // active-terminated group qualifies to become 'expired', then it will\\n // be removed from this array.\\n uint64[] activeTerminatedGroups;\\n // Points to the first active group, it is also the expired groups counter.\\n uint64 expiredGroupOffset;\\n // Group lifetime in blocks. When a group reached its lifetime, it\\n // is no longer selected for new relay requests but may still be\\n // responsible for submitting relay entry if relay request assigned\\n // to that group is still pending.\\n uint256 groupLifetime;\\n }\\n\\n event GroupRegistered(uint64 indexed groupId, bytes indexed groupPubKey);\\n\\n /// @notice Performs preliminary validation of a new group public key.\\n /// The group public key must be unique and have 128 bytes in length.\\n /// If the validation fails, the function reverts. This function\\n /// must be called first for a public key of a group added with\\n /// `addGroup` function.\\n /// @param groupPubKey Candidate group public key\\n function validatePublicKey(Data storage self, bytes calldata groupPubKey)\\n internal\\n view\\n {\\n require(groupPubKey.length == 128, \\\"Invalid length of the public key\\\");\\n\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n require(\\n self.groupsData[groupPubKeyHash].registrationBlockNumber == 0,\\n \\\"Group with this public key was already registered\\\"\\n );\\n }\\n\\n /// @notice Adds a new candidate group. The group is stored with group public\\n /// key and group members, but is not yet activated.\\n /// @dev The group members list is stored with all misbehaved members filtered out.\\n /// The code calling this function should ensure that the number of\\n /// candidate (not activated) groups is never more than one.\\n /// @param groupPubKey Generated candidate group public key\\n /// @param membersHash Keccak256 hash of members that actively took part in DKG.\\n function addGroup(\\n Data storage self,\\n bytes calldata groupPubKey,\\n bytes32 membersHash\\n ) internal {\\n bytes32 groupPubKeyHash = keccak256(groupPubKey);\\n\\n // We use group from storage that is assumed to be a struct set to the\\n // default values. We need to remember to overwrite fields in case a\\n // candidate group was already registered before and popped.\\n Group storage group = self.groupsData[groupPubKeyHash];\\n group.groupPubKey = groupPubKey;\\n group.membersHash = membersHash;\\n group.registrationBlockNumber = block.number;\\n\\n self.groupsRegistry.push(groupPubKeyHash);\\n\\n emit GroupRegistered(\\n uint64(self.groupsRegistry.length - 1),\\n groupPubKey\\n );\\n }\\n\\n /// @notice Goes through groups starting from the oldest one that is still\\n /// active and checks if it hasn't expired. If so, updates the information\\n /// about expired groups so that all expired groups are marked as such.\\n function expireOldGroups(Data storage self) internal {\\n // Move expiredGroupOffset as long as there are some groups that should\\n // be marked as expired. It is possible that expired group offset will\\n // move out of the groups array by one position. It means that all groups\\n // are expired (it points to the first active group) and that place in\\n // groups array - currently empty - will be possibly filled later by\\n // a new group.\\n while (\\n self.expiredGroupOffset < self.groupsRegistry.length &&\\n groupLifetimeOf(\\n self,\\n self.groupsRegistry[self.expiredGroupOffset]\\n ) <\\n block.number\\n ) {\\n self.expiredGroupOffset++;\\n }\\n\\n // Go through all activeTerminatedGroups and if some of the terminated\\n // groups are expired, remove them from activeTerminatedGroups collection\\n // and rearrange the array to preserve the original order.\\n // This is needed because we evaluate the shift of selected group index\\n // based on how many non-expired groups have been terminated. Hence it is\\n // important that a number of terminated groups matches the length of\\n // activeTerminatedGroups[].\\n uint256 i = 0;\\n while (i < self.activeTerminatedGroups.length) {\\n if (self.expiredGroupOffset > self.activeTerminatedGroups[i]) {\\n // When 'i'th group qualifies for expiration, we need to remove\\n // it from the activeTerminatedGroups array manually by rearranging\\n // the order starting from 'i'th group.\\n for (\\n uint256 j = i;\\n j < self.activeTerminatedGroups.length - 1;\\n j++\\n ) {\\n self.activeTerminatedGroups[j] = self\\n .activeTerminatedGroups[j + 1];\\n }\\n // Resizing the array length by 1. The last element was copied\\n // over in the loop above to an index \\\"second to last\\\". This is\\n // why we can safely remove it from here.\\n self.activeTerminatedGroups.pop();\\n } else {\\n i++;\\n }\\n }\\n }\\n\\n /// @notice Terminates group with the provided index. Reverts if the group\\n /// is already terminated.\\n /// @param groupId Index in the groupRegistry array.\\n function terminateGroup(Data storage self, uint64 groupId) internal {\\n require(\\n !isGroupTerminated(self, groupId),\\n \\\"Group has been already terminated\\\"\\n );\\n self.groupsData[self.groupsRegistry[groupId]].terminated = true;\\n // Expanding array for a new terminated group that is added below during\\n // sortition in ascending order.\\n self.activeTerminatedGroups.push();\\n\\n // Sorting activeTerminatedGroups by groupId in ascending order so a\\n // non-terminated group is properly selected.\\n uint256 i;\\n for (\\n i = self.activeTerminatedGroups.length - 1;\\n i > 0 && self.activeTerminatedGroups[i - 1] > groupId;\\n i--\\n ) {\\n self.activeTerminatedGroups[i] = self.activeTerminatedGroups[i - 1];\\n }\\n self.activeTerminatedGroups[i] = groupId;\\n }\\n\\n /// @notice Returns an index of a randomly selected active group. Terminated\\n /// and expired groups are not considered as active.\\n /// Before new group is selected, information about expired groups\\n /// is updated. At least one active group needs to be present for this\\n /// function to succeed.\\n /// @param seed Random number used as a group selection seed.\\n function selectGroup(Data storage self, uint256 seed)\\n internal\\n returns (uint64)\\n {\\n expireOldGroups(self);\\n\\n require(numberOfActiveGroups(self) > 0, \\\"No active groups\\\");\\n\\n uint64 selectedGroup = uint64(seed % numberOfActiveGroups(self));\\n uint64 result = shiftByTerminatedGroups(\\n self,\\n shiftByExpiredGroups(self, selectedGroup)\\n );\\n return result;\\n }\\n\\n /// @notice Setter for group lifetime.\\n /// @param lifetime Lifetime of a group in blocks.\\n function setGroupLifetime(Data storage self, uint256 lifetime) internal {\\n self.groupLifetime = lifetime;\\n }\\n\\n /// @notice Checks if group with the given index is terminated.\\n function isGroupTerminated(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]].terminated;\\n }\\n\\n /// @notice Gets the cutoff time until which the given group is considered\\n /// to be active assuming it hasn't been terminated before.\\n function groupLifetimeOf(Data storage self, bytes32 groupPubKeyHash)\\n internal\\n view\\n returns (uint256)\\n {\\n return\\n self.groupsData[groupPubKeyHash].registrationBlockNumber +\\n self.groupLifetime;\\n }\\n\\n /// @notice Checks if group with the given index is active and non-terminated.\\n function isGroupActive(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (bool)\\n {\\n return\\n groupLifetimeOf(self, self.groupsRegistry[groupId]) >=\\n block.number &&\\n !isGroupTerminated(self, groupId);\\n }\\n\\n function getGroup(Data storage self, uint64 groupId)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[self.groupsRegistry[groupId]];\\n }\\n\\n function getGroup(Data storage self, bytes memory groupPubKey)\\n internal\\n view\\n returns (Group storage)\\n {\\n return self.groupsData[keccak256(groupPubKey)];\\n }\\n\\n /// @notice Gets the number of active groups. Expired and terminated\\n /// groups are not counted as active.\\n function numberOfActiveGroups(Data storage self)\\n internal\\n view\\n returns (uint64)\\n {\\n if (self.groupsRegistry.length == 0) {\\n return 0;\\n }\\n\\n uint256 activeGroups = self.groupsRegistry.length -\\n self.expiredGroupOffset -\\n self.activeTerminatedGroups.length;\\n\\n return uint64(activeGroups);\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of expired groups.\\n function shiftByExpiredGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n return self.expiredGroupOffset + selectedIndex;\\n }\\n\\n /// @notice Evaluates the shift of a selected group index based on the number\\n /// of non-expired but terminated groups.\\n function shiftByTerminatedGroups(Data storage self, uint64 selectedIndex)\\n internal\\n view\\n returns (uint64)\\n {\\n uint64 shiftedIndex = selectedIndex;\\n for (uint64 i = 0; i < self.activeTerminatedGroups.length; i++) {\\n if (self.activeTerminatedGroups[i] <= shiftedIndex) {\\n shiftedIndex++;\\n }\\n }\\n\\n return shiftedIndex;\\n }\\n}\\n\",\"keccak256\":\"0x27a3cee268e5afa5ee3a00089aa82faffff7c3882aa94919499de4ef55dcfb0c\",\"license\":\"GPL-3.0-only\"}},\"version\":1}",
111
+ "bytecode": "0x61109861003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80636dcc64f81461005057806389ef44b01461006b578063fc21976b14610073575b600080fd5b610058602181565b6040519081526020015b60405180910390f35b610058604181565b610086610081366004610baf565b610093565b6040516100629190610cb5565b60606100ab6100a56020880188610cff565b8461063f565b600060416100bc6040890189610d49565b6100c7929150610dbc565b90506100d66040880188610d49565b90506000036101255760405162461bcd60e51b8152602060048201526016602482015275139bc81cda59db985d1d5c995cc81c1c9bdd9a59195960521b60448201526064015b60405180910390fd5b60416101346040890189610d49565b61013f929150610dd0565b1561018c5760405162461bcd60e51b815260206004820152601a60248201527f4d616c666f726d6564207369676e617475726573206172726179000000000000604482015260640161011c565b6101996060880188610cff565b905081146101e95760405162461bcd60e51b815260206004820152601b60248201527f556e6578706563746564207369676e61747572657320636f756e740000000000604482015260640161011c565b602181101561022f5760405162461bcd60e51b8152602060048201526012602482015271546f6f20666577207369676e61747572657360701b604482015260640161011c565b828111156102755760405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e79207369676e61747572657360681b604482015260640161011c565b61028b6102856060890189610cff565b8561063f565b60006103144687896102a060208d018d610cff565b6040516020016102b4959493929190610de4565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90506000896001600160a01b031663f7f9a8fa87876040518363ffffffff1660e01b8152600401610346929190610e8c565b600060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261038b9190810190610ed5565b905060606000805b858110156104e05760006103aa60608e018e610cff565b838181106103ba576103ba610f87565b9050602002013590506104238260416103d39190610f9d565b60418f80604001906103e59190610d49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506107579050565b9350600061043187866107fd565b90506001600160a01b03811686610449600185610fb4565b8151811061045957610459610f87565b60200260200101516001600160a01b0316146104ab5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b604482015260640161011c565b831580156104c15750336001600160a01b038216145b156104cb57600193505b505080806104d890610fc7565b915050610393565b508061052e5760405162461bcd60e51b815260206004820152601b60248201527f53656e646572206d75737420626520636c61696d207369676e65720000000000604482015260640161011c565b61053b60208c018c610cff565b905067ffffffffffffffff81111561055557610555610b23565b60405190808252806020026020018201604052801561057e578160200160208202803683370190505b50955060005b61059160208d018d610cff565b905081101561062f5760006105a960208e018e610cff565b838181106105b9576105b9610f87565b90506020020135905089896001836105d19190610fb4565b8181106105e0576105e0610f87565b90506020020160208101906105f59190610fe0565b88838151811061060757610607610f87565b63ffffffff90921660209283029190910190910152508061062781610fc7565b915050610584565b5050505050509695505050505050565b811580159061064e5750808211155b61066a5760405162461bcd60e51b815260040161011c90611002565b60008383600081811061067f5761067f610f87565b905060200201351180156106b5575080838361069c600182610fb4565b8181106106ab576106ab610f87565b9050602002013511155b6106d15760405162461bcd60e51b815260040161011c90611002565b60005b6106df600184610fb4565b8110156107515783836106f3836001611039565b81811061070257610702610f87565b9050602002013584848381811061071b5761071b610f87565b905060200201351061073f5760405162461bcd60e51b815260040161011c90611002565b8061074981610fc7565b9150506106d4565b50505050565b606060006107658385611039565b90508381118015610777575080855110155b6107b95760405162461bcd60e51b8152602060048201526013602482015272536c696365206f7574206f6620626f756e647360681b604482015260640161011c565b604051915082604083010160405282825283850182038460208701018481015b808210156107f2578151838301526020820191506107d9565b505050509392505050565b600080600061080c8585610823565b9150915061081981610868565b5090505b92915050565b60008082516041036108595760208301516040840151606085015160001a61084d87828585610a21565b94509450505050610861565b506000905060025b9250929050565b600081600481111561087c5761087c61104c565b036108845750565b60018160048111156108985761089861104c565b036108e55760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161011c565b60028160048111156108f9576108f961104c565b036109465760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161011c565b600381600481111561095a5761095a61104c565b036109b25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161011c565b60048160048111156109c6576109c661104c565b03610a1e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161011c565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610a585750600090506003610b05565b8460ff16601b14158015610a7057508460ff16601c14155b15610a815750600090506004610b05565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ad5573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610afe57600060019250925050610b05565b9150600090505b94509492505050565b6001600160a01b0381168114610a1e57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610b6257610b62610b23565b604052919050565b60008083601f840112610b7c57600080fd5b50813567ffffffffffffffff811115610b9457600080fd5b6020830191508360208260051b850101111561086157600080fd5b60008060008060008060a08789031215610bc857600080fd5b8635610bd381610b0e565b955060208781013567ffffffffffffffff80821115610bf157600080fd5b908901906080828c031215610c0557600080fd5b90965060408901359080821115610c1b57600080fd5b818a0191508a601f830112610c2f57600080fd5b813581811115610c4157610c41610b23565b610c53601f8201601f19168501610b39565b8181528c85838601011115610c6757600080fd5b81858501868301376000918101909401529195506060890135945060808901359180831115610c9557600080fd5b5050610ca389828a01610b6a565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b81811015610cf357835163ffffffff1683529284019291840191600101610cd1565b50909695505050505050565b6000808335601e19843603018112610d1657600080fd5b83018035915067ffffffffffffffff821115610d3157600080fd5b6020019150600581901b360382131561086157600080fd5b6000808335601e19843603018112610d6057600080fd5b83018035915067ffffffffffffffff821115610d7b57600080fd5b60200191503681900382131561086157600080fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082610dcb57610dcb610d90565b500490565b600082610ddf57610ddf610d90565b500690565b85815260006020868184015260806040840152855180608085015260005b81811015610e1e5787810183015185820160a001528201610e02565b50600060a08286010152601f19601f820116840191505060a08382030160608401528360a082015260018060fb1b03841115610e5957600080fd5b8360051b808660c08401370160c001979650505050505050565b803563ffffffff81168114610e8757600080fd5b919050565b60208082528181018390526000908460408401835b86811015610eca5763ffffffff610eb784610e73565b1682529183019190830190600101610ea1565b509695505050505050565b60006020808385031215610ee857600080fd5b825167ffffffffffffffff80821115610f0057600080fd5b818501915085601f830112610f1457600080fd5b815181811115610f2657610f26610b23565b8060051b9150610f37848301610b39565b8181529183018401918481019088841115610f5157600080fd5b938501935b83851015610f7b5784519250610f6b83610b0e565b8282529385019390850190610f56565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b808202811582820484141761081d5761081d610da6565b8181038181111561081d5761081d610da6565b600060018201610fd957610fd9610da6565b5060010190565b600060208284031215610ff257600080fd5b610ffb82610e73565b9392505050565b60208082526019908201527f436f72727570746564206d656d6265727320696e646963657300000000000000604082015260600190565b8082018082111561081d5761081d610da6565b634e487b7160e01b600052602160045260246000fdfea264697066735822122035df3a09b3a39447ac5429e9aa66850b441e978913349f8a4672594eb649d54b64736f6c63430008110033",
112
+ "deployedBytecode": "0x730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80636dcc64f81461005057806389ef44b01461006b578063fc21976b14610073575b600080fd5b610058602181565b6040519081526020015b60405180910390f35b610058604181565b610086610081366004610baf565b610093565b6040516100629190610cb5565b60606100ab6100a56020880188610cff565b8461063f565b600060416100bc6040890189610d49565b6100c7929150610dbc565b90506100d66040880188610d49565b90506000036101255760405162461bcd60e51b8152602060048201526016602482015275139bc81cda59db985d1d5c995cc81c1c9bdd9a59195960521b60448201526064015b60405180910390fd5b60416101346040890189610d49565b61013f929150610dd0565b1561018c5760405162461bcd60e51b815260206004820152601a60248201527f4d616c666f726d6564207369676e617475726573206172726179000000000000604482015260640161011c565b6101996060880188610cff565b905081146101e95760405162461bcd60e51b815260206004820152601b60248201527f556e6578706563746564207369676e61747572657320636f756e740000000000604482015260640161011c565b602181101561022f5760405162461bcd60e51b8152602060048201526012602482015271546f6f20666577207369676e61747572657360701b604482015260640161011c565b828111156102755760405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e79207369676e61747572657360681b604482015260640161011c565b61028b6102856060890189610cff565b8561063f565b60006103144687896102a060208d018d610cff565b6040516020016102b4959493929190610de4565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90506000896001600160a01b031663f7f9a8fa87876040518363ffffffff1660e01b8152600401610346929190610e8c565b600060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261038b9190810190610ed5565b905060606000805b858110156104e05760006103aa60608e018e610cff565b838181106103ba576103ba610f87565b9050602002013590506104238260416103d39190610f9d565b60418f80604001906103e59190610d49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294939250506107579050565b9350600061043187866107fd565b90506001600160a01b03811686610449600185610fb4565b8151811061045957610459610f87565b60200260200101516001600160a01b0316146104ab5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b604482015260640161011c565b831580156104c15750336001600160a01b038216145b156104cb57600193505b505080806104d890610fc7565b915050610393565b508061052e5760405162461bcd60e51b815260206004820152601b60248201527f53656e646572206d75737420626520636c61696d207369676e65720000000000604482015260640161011c565b61053b60208c018c610cff565b905067ffffffffffffffff81111561055557610555610b23565b60405190808252806020026020018201604052801561057e578160200160208202803683370190505b50955060005b61059160208d018d610cff565b905081101561062f5760006105a960208e018e610cff565b838181106105b9576105b9610f87565b90506020020135905089896001836105d19190610fb4565b8181106105e0576105e0610f87565b90506020020160208101906105f59190610fe0565b88838151811061060757610607610f87565b63ffffffff90921660209283029190910190910152508061062781610fc7565b915050610584565b5050505050509695505050505050565b811580159061064e5750808211155b61066a5760405162461bcd60e51b815260040161011c90611002565b60008383600081811061067f5761067f610f87565b905060200201351180156106b5575080838361069c600182610fb4565b8181106106ab576106ab610f87565b9050602002013511155b6106d15760405162461bcd60e51b815260040161011c90611002565b60005b6106df600184610fb4565b8110156107515783836106f3836001611039565b81811061070257610702610f87565b9050602002013584848381811061071b5761071b610f87565b905060200201351061073f5760405162461bcd60e51b815260040161011c90611002565b8061074981610fc7565b9150506106d4565b50505050565b606060006107658385611039565b90508381118015610777575080855110155b6107b95760405162461bcd60e51b8152602060048201526013602482015272536c696365206f7574206f6620626f756e647360681b604482015260640161011c565b604051915082604083010160405282825283850182038460208701018481015b808210156107f2578151838301526020820191506107d9565b505050509392505050565b600080600061080c8585610823565b9150915061081981610868565b5090505b92915050565b60008082516041036108595760208301516040840151606085015160001a61084d87828585610a21565b94509450505050610861565b506000905060025b9250929050565b600081600481111561087c5761087c61104c565b036108845750565b60018160048111156108985761089861104c565b036108e55760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161011c565b60028160048111156108f9576108f961104c565b036109465760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161011c565b600381600481111561095a5761095a61104c565b036109b25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161011c565b60048160048111156109c6576109c661104c565b03610a1e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161011c565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610a585750600090506003610b05565b8460ff16601b14158015610a7057508460ff16601c14155b15610a815750600090506004610b05565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ad5573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610afe57600060019250925050610b05565b9150600090505b94509492505050565b6001600160a01b0381168114610a1e57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610b6257610b62610b23565b604052919050565b60008083601f840112610b7c57600080fd5b50813567ffffffffffffffff811115610b9457600080fd5b6020830191508360208260051b850101111561086157600080fd5b60008060008060008060a08789031215610bc857600080fd5b8635610bd381610b0e565b955060208781013567ffffffffffffffff80821115610bf157600080fd5b908901906080828c031215610c0557600080fd5b90965060408901359080821115610c1b57600080fd5b818a0191508a601f830112610c2f57600080fd5b813581811115610c4157610c41610b23565b610c53601f8201601f19168501610b39565b8181528c85838601011115610c6757600080fd5b81858501868301376000918101909401529195506060890135945060808901359180831115610c9557600080fd5b5050610ca389828a01610b6a565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b81811015610cf357835163ffffffff1683529284019291840191600101610cd1565b50909695505050505050565b6000808335601e19843603018112610d1657600080fd5b83018035915067ffffffffffffffff821115610d3157600080fd5b6020019150600581901b360382131561086157600080fd5b6000808335601e19843603018112610d6057600080fd5b83018035915067ffffffffffffffff821115610d7b57600080fd5b60200191503681900382131561086157600080fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082610dcb57610dcb610d90565b500490565b600082610ddf57610ddf610d90565b500690565b85815260006020868184015260806040840152855180608085015260005b81811015610e1e5787810183015185820160a001528201610e02565b50600060a08286010152601f19601f820116840191505060a08382030160608401528360a082015260018060fb1b03841115610e5957600080fd5b8360051b808660c08401370160c001979650505050505050565b803563ffffffff81168114610e8757600080fd5b919050565b60208082528181018390526000908460408401835b86811015610eca5763ffffffff610eb784610e73565b1682529183019190830190600101610ea1565b509695505050505050565b60006020808385031215610ee857600080fd5b825167ffffffffffffffff80821115610f0057600080fd5b818501915085601f830112610f1457600080fd5b815181811115610f2657610f26610b23565b8060051b9150610f37848301610b39565b8181529183018401918481019088841115610f5157600080fd5b938501935b83851015610f7b5784519250610f6b83610b0e565b8282529385019390850190610f56565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b808202811582820484141761081d5761081d610da6565b8181038181111561081d5761081d610da6565b600060018201610fd957610fd9610da6565b5060010190565b600060208284031215610ff257600080fd5b610ffb82610e73565b9392505050565b60208082526019908201527f436f72727570746564206d656d6265727320696e646963657300000000000000604082015260600190565b8082018082111561081d5761081d610da6565b634e487b7160e01b600052602160045260246000fdfea264697066735822122035df3a09b3a39447ac5429e9aa66850b441e978913349f8a4672594eb649d54b64736f6c63430008110033",
113
113
  "devdoc": {
114
114
  "kind": "dev",
115
115
  "methods": {