Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 3,429 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Unstake | 21465983 | 13 mins ago | IN | 0 ETH | 0.00328957 | ||||
Unstake | 21465485 | 1 hr ago | IN | 0 ETH | 0.00108601 | ||||
Unstake | 21464905 | 3 hrs ago | IN | 0 ETH | 0.00091881 | ||||
Unstake | 21464853 | 4 hrs ago | IN | 0 ETH | 0.00097247 | ||||
Unstake | 21464461 | 5 hrs ago | IN | 0 ETH | 0.00135289 | ||||
Unbond | 21462028 | 13 hrs ago | IN | 0 ETH | 0.0003065 | ||||
Unstake | 21461121 | 16 hrs ago | IN | 0 ETH | 0.00085691 | ||||
Unstake | 21460795 | 17 hrs ago | IN | 0 ETH | 0.00117835 | ||||
Unstake | 21460729 | 17 hrs ago | IN | 0 ETH | 0.00090133 | ||||
Unstake | 21460093 | 20 hrs ago | IN | 0 ETH | 0.00127188 | ||||
Unstake | 21459139 | 23 hrs ago | IN | 0 ETH | 0.00123828 | ||||
Unstake | 21458648 | 24 hrs ago | IN | 0 ETH | 0.0015936 | ||||
Unstake | 21458102 | 26 hrs ago | IN | 0 ETH | 0.00111793 | ||||
Unstake | 21457723 | 27 hrs ago | IN | 0 ETH | 0.00073404 | ||||
Unbond | 21457711 | 28 hrs ago | IN | 0 ETH | 0.0002297 | ||||
Unbond | 21457660 | 28 hrs ago | IN | 0 ETH | 0.00035979 | ||||
Unbond | 21457628 | 28 hrs ago | IN | 0 ETH | 0.00030933 | ||||
Unstake | 21457146 | 29 hrs ago | IN | 0 ETH | 0.00078974 | ||||
Unstake | 21456674 | 31 hrs ago | IN | 0 ETH | 0.00084242 | ||||
Unbond | 21454803 | 37 hrs ago | IN | 0 ETH | 0.00043932 | ||||
Unbond | 21454672 | 38 hrs ago | IN | 0 ETH | 0.00026578 | ||||
Unstake | 21453593 | 41 hrs ago | IN | 0 ETH | 0.00130317 | ||||
Unbond | 21453579 | 41 hrs ago | IN | 0 ETH | 0.00034085 | ||||
Unbond | 21453085 | 43 hrs ago | IN | 0 ETH | 0.00049591 | ||||
Unstake | 21452942 | 44 hrs ago | IN | 0 ETH | 0.0012833 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x6018e8B7...f581bE1B4 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
CommunityStakingPool
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {TypeAndVersionInterface} from "@chainlink/contracts/src/v0.8/interfaces/TypeAndVersionInterface.sol"; import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; import {IMerkleAccessController} from "../interfaces/IMerkleAccessController.sol"; import {OperatorStakingPool} from "./OperatorStakingPool.sol"; import {StakingPoolBase} from "./StakingPoolBase.sol"; /// @notice This contract manages the staking of LINK tokens for the community stakers. /// @dev This contract inherits the StakingPoolBase contract and interacts with the MigrationProxy, /// OperatorStakingPool, and RewardVault contracts. /// @dev invariant Operators cannot stake in the community staking pool. contract CommunityStakingPool is StakingPoolBase, IMerkleAccessController, TypeAndVersionInterface { /// @notice This error is thrown when the pool is opened with an empty /// merkle root error MerkleRootNotSet(); /// @notice This event is emitted when the operator staking pool is changed /// @param oldOperatorStakingPool The old operator staking pool /// @param newOperatorStakingPool The new operator staking pool event OperatorStakingPoolChanged( address indexed oldOperatorStakingPool, address indexed newOperatorStakingPool ); /// @notice This struct defines the params required by the Staking contract's /// constructor. struct ConstructorParams { /// @notice The base staking pool constructor parameters ConstructorParamsBase baseParams; /// @notice The operator staking pool contract OperatorStakingPool operatorStakingPool; } /// @notice The operator staking pool contract OperatorStakingPool private s_operatorStakingPool; /// @notice The merkle root of the merkle tree generated from the list /// of staker addresses with early access. bytes32 private s_merkleRoot; constructor(ConstructorParams memory params) StakingPoolBase(params.baseParams) { if (address(params.operatorStakingPool) == address(0)) { revert InvalidZeroAddress(); } s_operatorStakingPool = params.operatorStakingPool; } // ======================= // IMerkleAccessController // ======================= /// @inheritdoc IMerkleAccessController function hasAccess(address staker, bytes32[] calldata proof) external view returns (bool) { return _hasAccess(staker, proof); } /// @inheritdoc IMerkleAccessController /// @dev precondition The caller must have the initiator admin role. /// @dev precondition Cannot be called after the pool is closed. function setMerkleRoot(bytes32 newMerkleRoot) external onlyRole(INITIATOR_ROLE) whenBeforeClosing { bytes32 oldMerkleRoot = s_merkleRoot; if (oldMerkleRoot == newMerkleRoot) return; s_merkleRoot = newMerkleRoot; emit MerkleRootChanged(oldMerkleRoot, newMerkleRoot); } /// @inheritdoc IMerkleAccessController function getMerkleRoot() external view returns (bytes32) { return s_merkleRoot; } /// @notice This function sets the operator staking pool /// @param newOperatorStakingPool The new operator staking pool /// @dev precondition The caller must have the default admin role. function setOperatorStakingPool(OperatorStakingPool newOperatorStakingPool) external onlyRole(DEFAULT_ADMIN_ROLE) { if (address(newOperatorStakingPool) == address(0)) revert InvalidZeroAddress(); address oldOperatorStakingPool = address(s_operatorStakingPool); if (oldOperatorStakingPool == address(newOperatorStakingPool)) return; s_operatorStakingPool = newOperatorStakingPool; emit OperatorStakingPoolChanged(oldOperatorStakingPool, address(newOperatorStakingPool)); } // ======================= // TypeAndVersionInterface // ======================= /// @inheritdoc TypeAndVersionInterface function typeAndVersion() external pure virtual override returns (string memory) { return "CommunityStakingPool 1.0.0"; } // =============== // StakingPoolBase // =============== /// @inheritdoc StakingPoolBase function _validateOnTokenTransfer( address sender, address staker, bytes calldata data ) internal view override(StakingPoolBase) { // check if staker has access // if the sender is the migration proxy, the staker is allowed to stake // if currently in public phase (merkle root set to empty bytes) data is ignored // if in the access limited phase data is the merkle proof // if in migrations only phase, the merkle root is set to double hash of the migration proxy // address. This is essentially only used as a placeholder to differentiate between the open // phase (empty merkle root) and access limited phase (merkle root generated from allowlist) if ( sender != address(s_migrationProxy) && s_merkleRoot != bytes32(0) && !_hasAccess(staker, abi.decode(data, (bytes32[]))) ) { revert AccessForbidden(); } // check if the sender is an operator if (s_operatorStakingPool.isOperator(staker) || s_operatorStakingPool.isRemoved(staker)) { revert AccessForbidden(); } } /// @inheritdoc StakingPoolBase function _validateBeforeOpen() internal view override(StakingPoolBase) { if (s_merkleRoot == bytes32(0)) { revert MerkleRootNotSet(); } } /// @notice Util function that validates if a community staker has access to an /// access limited community staking pool /// @param staker The community staker's address /// @param proof Merkle proof for the community staker's allowlist /// @return bool True if the community staker has access to the access limited /// community staking pool function _hasAccess(address staker, bytes32[] memory proof) private view returns (bool) { if (s_merkleRoot == bytes32(0)) return true; return MerkleProof.verify({ proof: proof, root: s_merkleRoot, leaf: keccak256(bytes.concat(keccak256(abi.encode(staker)))) }); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract TypeAndVersionInterface { function typeAndVersion() external pure virtual returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates merkle trees that are safe * against this attack out of the box. */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} * * _Available since v4.7._ */ function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} * * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { require(proofPos == proofLen, "MerkleProof: invalid multiproof"); unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { require(proofPos == proofLen, "MerkleProof: invalid multiproof"); unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; interface IMerkleAccessController { /// @notice Emitted when the contract owner updates the staking allowlist /// @param oldMerkleRoot The root of the old Staking allowlist merkle tree /// @param newMerkleRoot The root of a new Staking allowlist merkle tree event MerkleRootChanged(bytes32 oldMerkleRoot, bytes32 newMerkleRoot); /// @notice Validates if a community staker has access to the private staking pool /// @param staker The community staker's address /// @param proof Merkle proof for the community staker's allowlist /// @return true If the staker has access to the private staking pool function hasAccess(address staker, bytes32[] calldata proof) external view returns (bool); /// @notice This function is called to update the staking allowlist in a private staking pool /// @dev Only callable by the contract owner /// @param newMerkleRoot Merkle Tree root, used to prove access for community stakers /// will be required at opening but can be removed at any time by the owner when /// staking access will be granted to the public. function setMerkleRoot(bytes32 newMerkleRoot) external; /// @notice This function returns the current root of the Staking allowlist merkle tree /// @return The current root of the Staking allowlist merkle tree function getMerkleRoot() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {TypeAndVersionInterface} from "@chainlink/contracts/src/v0.8/interfaces/TypeAndVersionInterface.sol"; import {AccessControlDefaultAdminRules} from "@openzeppelin/contracts/access/AccessControlDefaultAdminRules.sol"; import {Checkpoints} from "@openzeppelin/contracts/utils/Checkpoints.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {ISlashable} from "../interfaces/ISlashable.sol"; import {IRewardVault} from "../interfaces/IRewardVault.sol"; import {StakingPoolBase} from "./StakingPoolBase.sol"; /// @notice This contract manages the staking of LINK tokens for the operator stakers. /// @dev This contract inherits the StakingPoolBase contract and interacts with the MigrationProxy, /// PriceFeedAlertsController, CommunityStakingPool, and RewardVault contracts. /// @dev invariant Only addresses added as operators by the contract manager can stake in this pool. /// @dev invariant contract's LINK token balance should be greater than or equal to the sum of /// totalPrincipal and s_alerterRewardFunds. contract OperatorStakingPool is ISlashable, StakingPoolBase, TypeAndVersionInterface { using Checkpoints for Checkpoints.History; using EnumerableSet for EnumerableSet.AddressSet; /// @notice This error is raised when adding the zero address as an operator error InvalidOperator(); /// @notice Error code for when the operator list is invalid error InvalidOperatorList(); /// @notice Error code for when the staker is not an operator error StakerNotOperator(); /// @notice This error is raised when an address is duplicated in the supplied list of operators. /// This can happen in addOperators and setFeedOperators functions. /// @param operator address of the operator error OperatorAlreadyExists(address operator); /// @notice This error is raised when removing an operator that doesn't exist. /// @param operator Address of the operator error OperatorDoesNotExist(address operator); /// @notice This error is raised when an operator to add has been removed previously. /// @param operator Address of the operator error OperatorHasBeenRemoved(address operator); /// @notice This error is raised when an operator to add is already a community staker. error OperatorCannotBeCommunityStaker(address operator); /// @notice This error is thrown whenever the max pool size is less than the /// reserved space for operators /// @param maxPoolSize The maximum pool size of the operator staking pool /// @param maxPrincipalPerStaker The maximum amount an operator can stake in the /// pool /// @param numOperators The number of operators in the pool error InsufficientPoolSpace( uint256 maxPoolSize, uint256 maxPrincipalPerStaker, uint256 numOperators ); /// @notice This error is raised when attempting to open the staking pool with less /// than the minimum required node operators /// @param numOperators The current number of operators in the staking pool /// @param minInitialOperatorCount The minimum required number of operators /// in the staking pool before it can be opened error InadequateInitialOperatorCount(uint256 numOperators, uint256 minInitialOperatorCount); /// @notice This error is thrown when the contract manager tries to add a zero amount /// to the alerter reward funds error InvalidAlerterRewardFundAmount(); /// @notice This error is thrown whenever the contract manager tries to withdraw /// more than the remaining balance in the alerter reward funds /// @param amountToWithdraw The amount that the contract manager tried to withdraw /// @param remainingBalance The remaining balance of the alerter reward funds error InsufficientAlerterRewardFunds(uint256 amountToWithdraw, uint256 remainingBalance); /// @notice This event is emitted when an operator is removed /// @param operator Address of the operator /// @param principal Operator's staked LINK amount /// @param newTotalPrincipal Total amount of staked juels remaining in the pool event OperatorRemoved(address indexed operator, uint256 principal, uint256 newTotalPrincipal); /// @notice This event is emitted when an operator is added /// @param operator Address of the operator event OperatorAdded(address indexed operator); /// @notice This event is emitted whenever the alerter reward funds is funded /// @param amountFunded The amount added to the alerter reward funds /// @param totalBalance The current balance of the alerter reward funds event AlerterRewardDeposited(uint256 amountFunded, uint256 totalBalance); /// @notice This event is emitted whenever the contract manager withdraws from the /// alerter reward funds /// @param amountWithdrawn The amount withdrawn from the alerter reward funds /// @param remainingBalance The remaining balance of the alerter reward funds event AlerterRewardWithdrawn(uint256 amountWithdrawn, uint256 remainingBalance); /// @notice This event is emitted whenever the alerter is paid the full /// alerter reward amount /// @param alerter The address of the alerter /// @param alerterRewardActual The amount of rewards sent to the alerter in juels. /// This can be lower than the expected value, if the reward fund is low or we aren't able to /// slash enough. /// @param alerterRewardExpected The amount of expected rewards for the alerter /// in juels event AlertingRewardPaid( address indexed alerter, uint256 alerterRewardActual, uint256 alerterRewardExpected ); /// @notice This event is emitted when the slasher config is set /// @param slasher The address of the slasher /// @param refillRate The refill rate of the slasher /// @param slashCapacity The slash capacity of the slasher event SlasherConfigSet(address indexed slasher, uint256 refillRate, uint256 slashCapacity); /// @notice This event is emitted when an operator is slashed /// @param operator The address of the operator /// @param slashedAmount The amount slashed from the operator's staked LINK /// amount /// @param updatedStakerPrincipal The operator's updated staked LINK amount /// @param newTotalPrincipal Total amount of staked juels remaining in the pool event Slashed( address indexed operator, uint256 slashedAmount, uint256 updatedStakerPrincipal, uint256 newTotalPrincipal ); /// @notice This struct defines the params required by the Staking contract's /// constructor. struct ConstructorParams { /// @notice The base staking pool constructor parameters ConstructorParamsBase baseParams; /// @notice The minimum number of node operators required to open the /// staking pool. uint256 minInitialOperatorCount; } /// @notice This struct defines the operator-specific states. struct Operator { /// @notice The operator's staked LINK amount when they get removed. uint256 removedPrincipal; /// @notice Flag that signals whether the operator is an operator. bool isOperator; /// @notice Flag that signals whether the operator has been removed. bool isRemoved; } /// @notice This is the ID for the alert rewarder role, which is given to the /// addresses that will deposit and withdraw the alerter reward. /// @dev Hash: 8d2cf17e37ecc80f26d65bcf3868b78960ab38b0762747f6c5e311e75068a88b bytes32 public constant ALERT_REWARDER_ROLE = keccak256("ALERT_REWARDER_ROLE"); /// @notice This is the ID for the operator manager role, which is given to the address that will /// add and remove operators /// @dev Hash: 001fdceeaab2d33566b504ecfe97e6dc3cf82cc816e696d9fe5cce35954bed17 bytes32 public constant OPERATOR_MANAGER_ROLE = keccak256("OPERATOR_MANAGER_ROLE"); /// @notice This is the ID for the slasher role, which will be given to the /// AlertsController contract. /// @dev Hash: 12b42e8a160f6064dc959c6f251e3af0750ad213dbecf573b4710d67d6c28e39 bytes32 public constant SLASHER_ROLE = keccak256("SLASHER_ROLE"); /// @notice Mapping of addresses to the Operator struct. mapping(address operator => Operator) private s_operators; /// @notice Mapping of the slashers to slasher config and state. mapping(address slasher => Slasher) private s_slashers; /// @notice The set of operators that are currently on-feed (slashable). EnumerableSet.AddressSet private s_operatorSet; /// @notice The number of node operators that have been set in the pool uint256 private s_numOperators; /// @notice Tracks the balance of the alerter reward funds. This bucket holds all /// slashed funds and also funds alerter rewards. uint256 private s_alerterRewardFunds; /// @notice The minimum number of node operators required to open the /// staking pool. uint256 private immutable i_minInitialOperatorCount; constructor(ConstructorParams memory params) StakingPoolBase(params.baseParams) { i_minInitialOperatorCount = params.minInitialOperatorCount; } /// @notice Adds LINK to the alerter reward funds /// @param amount The amount of LINK to add to the alerter reward funds /// @dev precondition The caller must have the alert rewarder role. /// @dev precondition The caller must have at least `amount` LINK tokens. /// @dev precondition The caller must have approved this contract for the transfer of at least /// `amount` LINK tokens. function depositAlerterReward(uint256 amount) external onlyRole(ALERT_REWARDER_ROLE) whenBeforeClosing { if (amount == 0) revert InvalidAlerterRewardFundAmount(); uint256 alerterRewardFunds = s_alerterRewardFunds; alerterRewardFunds += amount; s_alerterRewardFunds = alerterRewardFunds; // The return value is not checked since the call will revert if any balance, allowance or // receiver conditions fail. i_LINK.transferFrom({from: msg.sender, to: address(this), value: amount}); emit AlerterRewardDeposited(amount, alerterRewardFunds); } /// @notice Withdraws LINK from the alerter reward funds /// @param amount The amount of LINK withdrawn from the alerter reward funds /// @dev precondition The caller must have the alert rewarder role. /// @dev precondition This contract must have at least `amount` LINK tokens as the alerter reward /// funds. /// @dev precondition This contract must be closed (before opening or after closing). function withdrawAlerterReward(uint256 amount) external onlyRole(ALERT_REWARDER_ROLE) { if (amount == 0) revert InvalidAlerterRewardFundAmount(); if (s_isOpen) revert PoolNotClosed(); uint256 alerterRewardFunds = s_alerterRewardFunds; if (amount > alerterRewardFunds) { revert InsufficientAlerterRewardFunds(amount, alerterRewardFunds); } alerterRewardFunds -= amount; s_alerterRewardFunds = alerterRewardFunds; // The return value is not checked since the call will revert if any balance, allowance or // receiver conditions fail. i_LINK.transfer(msg.sender, amount); emit AlerterRewardWithdrawn(amount, alerterRewardFunds); } /// @notice Returns the balance of the pool's alerter reward funds /// @return uint256 The balance of the pool's alerter reward funds function getAlerterRewardFunds() external view returns (uint256) { return s_alerterRewardFunds; } // =============== // StakingPoolBase // =============== /// @inheritdoc StakingPoolBase /// @dev The access control is done in StakingPoolBase. function setPoolConfig( uint256 maxPoolSize, uint256 maxPrincipalPerStaker ) external override(StakingPoolBase) validatePoolSpace(maxPoolSize, maxPrincipalPerStaker, s_numOperators) whenOpen onlyRole(DEFAULT_ADMIN_ROLE) { _setPoolConfig(maxPoolSize, maxPrincipalPerStaker); } /// @inheritdoc StakingPoolBase /// @dev Removed operators need to go through the unbonding period before they can withdraw. This /// function will check if the operator has removed principal they can unstake. function unbond() external override { Staker storage staker = s_stakers[msg.sender]; uint224 history = staker.history.latest(); uint112 stakerPrincipal = uint112(history >> 112); if (stakerPrincipal == 0 && s_operators[msg.sender].removedPrincipal == 0) { revert StakeNotFound(msg.sender); } _unbond(staker); } /// @notice Registers operators from a list of unique, sorted addresses /// Addresses must be provided in sorted order so that /// address(0xNext) > address(0xPrev) /// @dev Previously removed operators cannot be readded to the pool. /// @dev precondition The caller must have the operator manager role. /// @dev precondition Cannot be called after the pool is closed. /// @param operators The sorted list of operator addresses function addOperators(address[] calldata operators) external whenBeforeClosing validateRewardVaultSet validatePoolSpace( s_pool.configs.maxPoolSize, s_pool.configs.maxPrincipalPerStaker, s_numOperators + operators.length ) onlyRole(OPERATOR_MANAGER_ROLE) { for (uint256 i; i < operators.length; ++i) { address operatorAddress = operators[i]; if (operatorAddress == address(0)) revert InvalidOperator(); IRewardVault.StakerReward memory stakerReward = s_rewardVault.getStoredReward(operatorAddress); if (stakerReward.stakerType == IRewardVault.StakerType.COMMUNITY) { revert OperatorCannotBeCommunityStaker(operatorAddress); } // verify input list is sorted and addresses are unique if (i < operators.length - 1 && operatorAddress >= operators[i + 1]) { revert InvalidOperatorList(); } Operator storage operator = s_operators[operatorAddress]; if (operator.isOperator) revert OperatorAlreadyExists(operatorAddress); if (operator.isRemoved) revert OperatorHasBeenRemoved(operatorAddress); operator.isOperator = true; s_operatorSet.add(operatorAddress); emit OperatorAdded(operatorAddress); } unchecked { s_numOperators += operators.length; } } /// @notice Removes one or more operators from a list of operators. /// @dev Should only be callable by the owner when the pool is open. /// When an operator is removed, we store their staked LINK amount in a separate mapping to /// stop it from accruing rewards. They can withdraw their removedPrincipal and exit the system /// after going through the unbonding period. /// Removed operators are no longer slashable. /// @param operators A list of operator addresses to remove /// @dev precondition The caller must have the operator manager role. /// @dev precondition Cannot be called after the pool is closed. /// @dev precondition The operators must be currently added operators. function removeOperators(address[] calldata operators) external onlyRole(OPERATOR_MANAGER_ROLE) whenBeforeClosing { Operator storage operator; Staker storage staker; uint256 totalPrincipal = s_pool.state.totalPrincipal; for (uint256 i; i < operators.length; ++i) { address operatorAddress = operators[i]; operator = s_operators[operatorAddress]; if (!operator.isOperator) revert OperatorDoesNotExist(operatorAddress); staker = s_stakers[operatorAddress]; uint224 history = staker.history.latest(); uint256 principal = uint256(history >> 112); uint256 stakedAtTime = uint112(history); s_rewardVault.concludeRewardPeriod({ staker: operatorAddress, oldPrincipal: principal, unstakedAmount: principal, shouldForfeit: true, stakedAt: stakedAtTime }); totalPrincipal -= principal; s_pool.state.totalPrincipal = totalPrincipal; delete operator.isOperator; s_operatorSet.remove(operatorAddress); operator.isRemoved = true; // Reset the staker's stakedAtTime to 0 so their multiplier resets to 0. _updateStakerHistory({staker: staker, latestPrincipal: 0, latestStakedAtTime: 0}); // Move the operator's staked LINK amount to removedPrincipal so that // the operator stops earning rewards operator.removedPrincipal = principal; _resetUnbondingPeriod(staker, operatorAddress); emit OperatorRemoved(operatorAddress, principal, totalPrincipal); } s_numOperators -= operators.length; } /// @notice Getter function to check if an address is registered as an operator /// @param staker The address of the staker /// @return bool True if the staker is an operator function isOperator(address staker) external view returns (bool) { return s_operators[staker].isOperator; } /// @notice Getter function to check if an address is a removed operator /// @param staker The address of the staker /// @return bool True if the operator has been removed function isRemoved(address staker) external view returns (bool) { return s_operators[staker].isRemoved; } /// @notice Getter function for a removed operator's total staked LINK amount /// @param staker The address of the staker /// @return uint256 The removed operator's staked LINK amount that hasn't been withdrawn function getRemovedPrincipal(address staker) external view returns (uint256) { return s_operators[staker].removedPrincipal; } /// @notice Called by removed operators to withdraw their removed stake /// @dev precondition The caller must be in the claim period or the pool must be closed or paused. /// @dev precondition The caller must be a removed operator with some removed /// staked LINK amount. function unstakeRemovedPrincipal() external { if (!_canUnstake(s_stakers[msg.sender])) { revert StakerNotInClaimPeriod(msg.sender); } uint256 withdrawableAmount = s_operators[msg.sender].removedPrincipal; if (withdrawableAmount == 0) { revert UnstakeExceedsPrincipal(); } delete s_operators[msg.sender].removedPrincipal; // The return value is not checked since the call will revert if any balance, allowance or // receiver conditions fail. i_LINK.transfer(msg.sender, withdrawableAmount); // Since operator has been removed their total amount staked will be 0 emit Unstaked(msg.sender, withdrawableAmount, 0, s_pool.state.totalPrincipal); } /// @notice Returns the number of operators configured in the pool. /// @return uint256 The number of operators configured in the pool function getNumOperators() external view returns (uint256) { return s_numOperators; } /// @notice Returns the list of operators configured in the pool. /// @return address[] The list of operators configured in the pool function getOperators() external view returns (address[] memory) { return s_operatorSet.values(); } // ======================= // ISlashable // ======================= /// @inheritdoc ISlashable /// @dev precondition The caller must have the default admin role. /// @dev precondition Cannot be called after the pool is closed. function addSlasher( address slasher, SlasherConfig calldata config ) external onlyRole(DEFAULT_ADMIN_ROLE) whenBeforeClosing { _grantRole(SLASHER_ROLE, slasher); _setSlasherConfig(slasher, config); } /// @inheritdoc ISlashable /// @dev precondition The caller must have the default admin role. /// @dev precondition Cannot be called after the pool is closed. function removeSlasher(address slasher) external onlyRole(DEFAULT_ADMIN_ROLE) whenBeforeClosing { if (!hasRole(SLASHER_ROLE, slasher)) { revert InvalidSlasher(); } delete s_slashers[slasher]; _revokeRole(SLASHER_ROLE, slasher); emit SlasherConfigSet(slasher, 0, 0); } /// @inheritdoc ISlashable /// @dev precondition The caller must have the default admin role. /// @dev precondition Cannot be called after the pool is closed. function setSlasherConfig( address slasher, SlasherConfig calldata config ) external onlyRole(DEFAULT_ADMIN_ROLE) whenBeforeClosing { if (!hasRole(SLASHER_ROLE, slasher)) { revert InvalidSlasher(); } _setSlasherConfig(slasher, config); } /// @inheritdoc ISlashable function getSlasherConfig(address slasher) external view returns (SlasherConfig memory) { return s_slashers[slasher].config; } /// @inheritdoc ISlashable function getSlashCapacity(address slasher) external view returns (uint256) { SlasherConfig memory slasherConfig = s_slashers[slasher].config; return _getRemainingSlashCapacity(slasherConfig, slasher); } /// @inheritdoc ISlashable /// @dev In the current implementation, on-feed operators can raise alerts to rescue a portion of /// their slashed staked LINK amount. All operators can raise alerts in the priority period. Note /// that this may change in the future as we add alerting for additional services. /// @dev We will operationally make sure to remove an operator from the slashable (on-feed) /// operators list in alerts controllers if they are removed from the operators list in this /// contract, so there won't be a case where we slash a removed operator. /// @dev precondition The caller must have the slasher role. /// @dev precondition This contract must be active (open and stakers are earning rewards). /// @dev precondition The slasher must have enough capacity to slash. function slashAndReward( address[] calldata stakers, address alerter, uint256 principalAmount, uint256 alerterRewardAmount ) external onlySlasher whenActive whenNotPaused { SlasherConfig storage slasherConfig = s_slashers[msg.sender].config; uint256 combinedSlashAmount = stakers.length * principalAmount; uint256 remainingSlashCapacity = _getRemainingSlashCapacity(slasherConfig, msg.sender); // check if the total slashed amount exceeds the slasher's capacity if (combinedSlashAmount > remainingSlashCapacity) { /// @dev If a slashing occurs with an amount to be slashed that is higher than the remaining /// slashing capacity, only an amount equal to the remaining capacity is slashed. principalAmount = remainingSlashCapacity / stakers.length; } uint256 totalSlashedAmount = _slashOperators(stakers, principalAmount); s_slashers[msg.sender].state.remainingSlashCapacityAmount = remainingSlashCapacity - totalSlashedAmount; s_slashers[msg.sender].state.lastSlashTimestamp = block.timestamp; _payAlerter({ alerter: alerter, totalSlashedAmount: totalSlashedAmount, alerterRewardAmount: alerterRewardAmount }); } // ======================= // TypeAndVersionInterface // ======================= /// @inheritdoc TypeAndVersionInterface function typeAndVersion() external pure virtual override returns (string memory) { return "OperatorStakingPool 1.0.0"; } // ============================== // AccessControlDefaultAdminRules // ============================== /// @inheritdoc AccessControlDefaultAdminRules /// @notice Grants `role` to `account`. Reverts if the contract manager tries to grant the default /// admin or slasher role. /// @dev The default admin role must be granted through `beginDefaultAdminTransfer` and /// `acceptDefaultAdminTransfer`. /// @dev The slasher role must be granted through `addSlasher`. /// @param role The role to grant /// @param account The address to grant the role to function grantRole( bytes32 role, address account ) public virtual override(AccessControlDefaultAdminRules) { if (role == SLASHER_ROLE) revert InvalidRole(); super.grantRole(role, account); } /// @inheritdoc AccessControlDefaultAdminRules /// @notice Grants `role` to `account`. Reverts if the contract manager tries to grant the default /// admin or slasher role. /// @dev The default admin role must be revoked through `beginDefaultAdminTransfer` and /// `acceptDefaultAdminTransfer` to another address. /// @dev The slasher role must be revoked through `removeSlasher`. /// @param role The role to revoke /// @param account The address to revoke the role from function revokeRole( bytes32 role, address account ) public virtual override(AccessControlDefaultAdminRules) { if (role == SLASHER_ROLE) revert InvalidRole(); super.revokeRole(role, account); } // =============== // StakingPoolBase // =============== /// @inheritdoc StakingPoolBase function _validateOnTokenTransfer( address, address staker, bytes calldata ) internal view override(StakingPoolBase) { // check if staker is an operator if (!s_operators[staker].isOperator) revert StakerNotOperator(); } /// @inheritdoc StakingPoolBase function _validateBeforeOpen() internal view override(StakingPoolBase) { if (s_numOperators < i_minInitialOperatorCount) { revert InadequateInitialOperatorCount(s_numOperators, i_minInitialOperatorCount); } } /// @notice Helper function to set the slasher config /// @param slasher The slasher /// @param config The slasher config function _setSlasherConfig(address slasher, SlasherConfig calldata config) private { if (config.slashCapacity == 0 || config.refillRate == 0) { revert ISlashable.InvalidSlasherConfig(); } s_slashers[slasher].config = config; // refill capacity SlasherState storage state = s_slashers[slasher].state; state.remainingSlashCapacityAmount = config.slashCapacity; state.lastSlashTimestamp = block.timestamp; emit SlasherConfigSet(slasher, config.refillRate, config.slashCapacity); } /// @notice Helper function to slash operators /// @param operators The list of operators to slash /// @param principalAmount The amount to slash from each operator's staked /// LINK amount /// @return The total amount slashed from all operators function _slashOperators( address[] calldata operators, uint256 principalAmount ) private returns (uint256) { // perform the slash on all operators and add up the total slashed amount uint256 totalSlashedAmount; Staker storage staker; uint256 totalPrincipal = s_pool.state.totalPrincipal; for (uint256 i; i < operators.length; ++i) { // verify input list is sorted and addresses are unique address operatorAddress = operators[i]; if (i < operators.length - 1 && operatorAddress >= operators[i + 1]) { revert InvalidOperatorList(); } staker = s_stakers[operatorAddress]; uint224 history = staker.history.latest(); uint256 operatorPrincipal = uint112(history >> 112); uint256 stakerStakedAtTime = uint112(history); uint256 slashedAmount = principalAmount > operatorPrincipal ? operatorPrincipal : principalAmount; uint256 updatedPrincipal = operatorPrincipal - slashedAmount; // update the staker's rewards s_rewardVault.updateReward(operatorAddress, operatorPrincipal); _updateStakerHistory({ staker: staker, latestPrincipal: updatedPrincipal, latestStakedAtTime: stakerStakedAtTime }); totalSlashedAmount += slashedAmount; totalPrincipal -= slashedAmount; emit Slashed(operatorAddress, slashedAmount, updatedPrincipal, totalPrincipal); } // update the pool state s_pool.state.totalPrincipal = totalPrincipal; return totalSlashedAmount; } /// @notice Helper function to reward the alerter /// @param alerter The alerter /// @param totalSlashedAmount The total amount slashed from all the operators /// @param alerterRewardAmount The amount to reward the alerter function _payAlerter( address alerter, uint256 totalSlashedAmount, uint256 alerterRewardAmount ) private { uint256 newAlerterRewardFunds = s_alerterRewardFunds + totalSlashedAmount; uint256 alerterRewardActual = newAlerterRewardFunds < alerterRewardAmount ? newAlerterRewardFunds : alerterRewardAmount; s_alerterRewardFunds = newAlerterRewardFunds - alerterRewardActual; // We emit an event here instead of reverting so that the alerter can // immediately receive a portion of their rewards. This event // will allow the contract manager to reimburse any remaining rewards to the // alerter. emit AlertingRewardPaid(alerter, alerterRewardActual, alerterRewardAmount); // The return value is not checked since the call will revert if any balance, allowance or // receiver conditions fail. i_LINK.transfer(alerter, alerterRewardActual); } /// @notice Helper function to return the current remaining slash capacity for a slasher /// @param slasherConfig The slasher's config /// @param slasher The slasher /// @return The remaining slashing capacity function _getRemainingSlashCapacity( SlasherConfig memory slasherConfig, address slasher ) private view returns (uint256) { SlasherState memory slasherState = s_slashers[slasher].state; uint256 refilledAmount = (block.timestamp - slasherState.lastSlashTimestamp) * slasherConfig.refillRate; return Math.min( slasherConfig.slashCapacity, slasherState.remainingSlashCapacityAmount + refilledAmount ); } /// @dev Reverts if the msg.sender doesn't have the rewarder role. modifier onlyRewarder() { if (!hasRole(ALERT_REWARDER_ROLE, msg.sender)) { revert AccessForbidden(); } _; } /// @dev Reverts if not sent by an address that has the SLASHER role modifier onlySlasher() { if (!hasRole(SLASHER_ROLE, msg.sender)) { revert AccessForbidden(); } _; } /// @notice Checks that the maximum pool size is greater than or equal to /// the reserved space for operators. /// @param maxPoolSize The maximum pool size of the operator staking pool /// @param maxPrincipalPerStaker The maximum amount an operator can stake in the /// @param numOperators The number of operators in the pool /// @dev The reserved space is calculated by multiplying the number of /// operators and the maximum staked LINK amount per operator modifier validatePoolSpace( uint256 maxPoolSize, uint256 maxPrincipalPerStaker, uint256 numOperators ) { if (maxPoolSize < maxPrincipalPerStaker * numOperators) { revert InsufficientPoolSpace(maxPoolSize, maxPrincipalPerStaker, numOperators); } _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {ERC677ReceiverInterface} from "@chainlink/contracts/src/v0.8/interfaces/ERC677ReceiverInterface.sol"; import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol"; import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol"; import {Checkpoints} from "@openzeppelin/contracts/utils/Checkpoints.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {IMigratable} from "../interfaces/IMigratable.sol"; import {IRewardVault} from "../interfaces/IRewardVault.sol"; import {IStakingOwner} from "../interfaces/IStakingOwner.sol"; import {IStakingPool} from "../interfaces/IStakingPool.sol"; import {Migratable} from "../Migratable.sol"; import {PausableWithAccessControl} from "../PausableWithAccessControl.sol"; /// @notice This contract is the base contract for staking pools. Each staking pool extends this /// contract. /// @dev This contract is abstract and must be inherited. /// @dev invariant maxPoolSize must be greater than or equal to the totalPrincipal. /// @dev invariant maxPoolSize must be greater than or equal to the maxPrincipalPerStaker. /// @dev invariant contract's LINK token balance should be greater than or equal to the /// totalPrincipal. /// @dev invariant The migrated staked LINK amount must be less than or equal to the staker's staked /// LINK amount + /// rewards from the v0.1 staking pool. /// @dev invariant The migrated staked LINK amount must be less than or equal to the /// maxPrincipalPerStaker. /// @dev We only support LINK token in v0.2 staking. Rebasing tokens, ERC777 tokens, fee-on-transfer /// tokens or tokens that do not have 18 decimal places are not supported. abstract contract StakingPoolBase is ERC677ReceiverInterface, IStakingPool, IStakingOwner, Migratable, PausableWithAccessControl { using Checkpoints for Checkpoints.History; using SafeCast for uint256; /// @notice This error is thrown when the staking pool is not active. error PoolNotActive(); /// @notice This error is thrown when the unbonding period is set to 0 error InvalidUnbondingPeriod(); /// @notice This error is thrown when the claim period is set to 0 error InvalidClaimPeriod(); /// @notice This error is thrown whenever a staker tries to unbond during /// their unbonding period. /// @param unbondingPeriodEndsAt The time the unbonding period is finished error UnbondingOrClaimPeriodActive(uint256 unbondingPeriodEndsAt); /// @notice This error is thrown whenever a staker tries to unstake outside /// the claim period /// @param staker The staker trying to unstake error StakerNotInClaimPeriod(address staker); /// @notice This error is thrown when an invalid claim period range is provided /// @param minClaimPeriod The min claim period /// @param maxClaimPeriod The max claim period error InvalidClaimPeriodRange(uint256 minClaimPeriod, uint256 maxClaimPeriod); /// @notice This error is thrown when an invalid max unbonding period is provided /// @param maxUnbondingPeriod The max unbonding period error InvalidMaxUnbondingPeriod(uint256 maxUnbondingPeriod); /// @notice This error is thrown when a staker tries to stake and the reward vault connected to /// this pool is not open or is paused error RewardVaultNotActive(); /// @notice This error is thrown when admin tries to open the pool and the reward vault connected /// to this pool has not had rewards added to it. error RewardVaultHasNoRewards(); /// @notice This error is thrown when admin tries to set a new reward vault and the old reward /// vault is not closed yet. error RewardVaultNotClosed(); /// @notice This event is emitted whenever a staker initiates the unbonding /// period. /// @param staker The staker that has started their unbonding period. event UnbondingPeriodStarted(address indexed staker); /// @notice This event is emitted when a staker's unbonding period is reset /// @param staker The staker that has reset their unbonding period event UnbondingPeriodReset(address indexed staker); /// @notice This event is emitted when the unbonding period has been changed /// @param oldUnbondingPeriod The old unbonding period /// @param newUnbondingPeriod The new unbonding period event UnbondingPeriodSet(uint256 oldUnbondingPeriod, uint256 newUnbondingPeriod); /// @notice This event is emitted when the claim period is set /// @param oldClaimPeriod The old claim period /// @param newClaimPeriod The new claim period event ClaimPeriodSet(uint256 oldClaimPeriod, uint256 newClaimPeriod); /// @notice This event is emitted when the reward vault is set /// @param oldRewardVault The old reward vault /// @param newRewardVault The new reward vault event RewardVaultSet(address indexed oldRewardVault, address indexed newRewardVault); /// @notice This event is emitted when the staker is migrated to the migration target /// @param migrationTarget The migration target /// @param amount The staker's staked LINK amount that was migrated in juels /// @param migrationData The migration data event StakerMigrated(address indexed migrationTarget, uint256 amount, bytes migrationData); /// @notice This struct defines the params required by the Staking contract's /// constructor. struct ConstructorParamsBase { /// @notice The LINK Token LinkTokenInterface LINKAddress; /// @notice The initial maximum total stake amount for all stakers in the /// pool uint96 initialMaxPoolSize; /// @notice The initial maximum stake amount for a staker uint96 initialMaxPrincipalPerStaker; /// @notice The minimum stake amount that a staker must stake uint96 minPrincipalPerStaker; /// @notice The initial unbonding period uint32 initialUnbondingPeriod; /// @notice The max value that the unbonding period can be set to uint32 maxUnbondingPeriod; /// @notice The initial claim period uint32 initialClaimPeriod; /// @notice The min value that the claim period can be set to uint32 minClaimPeriod; /// @notice The max value that the claim period can be set to uint32 maxClaimPeriod; /// @notice The time it requires to transfer admin role uint48 adminRoleTransferDelay; } /// @notice This struct defines the params that the pool is configured with struct PoolConfigs { /// @notice The max amount of staked LINK allowed in the pool in juels. The max value of this /// field is expected to be less than 1 billion (10^9 * 10^18), which is less than the max value /// that can be represented by a uint96 (~7.9*10^28). uint96 maxPoolSize; /// @notice The max amount of LINK a staker can stake in juels. The max value of this field is /// expected to be less than 1 million (10^6 * 10^18), which is less than the max value that can /// be represented by a uint96 (~7.9*10^28). uint96 maxPrincipalPerStaker; /// @notice The length of the unbonding period in seconds. The max value of this field is /// expected to be less than a year, or 30 million (3.2*10^7), which is less than the max value /// that can be represented by a uint32 (~4.2*10^9). uint32 unbondingPeriod; /// @notice The length of the claim period in seconds. The max value of this field is /// expected to be less than a year, or 30 million (3.2*10^7), which is less than the max value /// that can be represented by a uint32 (~4.2*10^9). uint32 claimPeriod; } /// @notice This struct defines the state of the staking pool struct PoolState { /// @notice The total staked LINK amount amount in the pool uint256 totalPrincipal; /// @notice The time that the pool was closed uint256 closedAt; } /// @notice This struct defines the global state and configuration of the pool struct Pool { /// @notice The pool's configuration PoolConfigs configs; /// @notice The pool's state PoolState state; } /// @notice This is the ID for the initiator role, which is given to the /// addresses that will add open the pools, and set the merkle root for the community pool. /// @dev Hash: 6b8b15f1c11543d8280deaa7c24d12fffba6a357e4428e8c43e4234790186bff bytes32 public constant INITIATOR_ROLE = keccak256("INITIATOR_ROLE"); /// @notice The LINK token LinkTokenInterface internal immutable i_LINK; /// @notice The staking pool state and configuration Pool internal s_pool; /// @notice Mapping of a staker's address to their staker state mapping(address staker => IStakingPool.Staker) internal s_stakers; /// @notice Migration proxy address address internal s_migrationProxy; /// @notice The latest reward vault address IRewardVault internal s_rewardVault; /// @notice The min amount of LINK that a staker can stake uint96 internal immutable i_minPrincipalPerStaker; /// @notice The min value that the claim period can be set to uint32 private immutable i_minClaimPeriod; /// @notice The max value that the claim period can be set to uint32 private immutable i_maxClaimPeriod; /// @notice The max value that the unbonding period can be set to uint32 private immutable i_maxUnbondingPeriod; /// @notice Flag that signals if the staking pool is open for staking bool internal s_isOpen; constructor(ConstructorParamsBase memory params) PausableWithAccessControl(params.adminRoleTransferDelay, msg.sender) { if (address(params.LINKAddress) == address(0)) revert InvalidZeroAddress(); if (params.minPrincipalPerStaker == 0) revert InvalidMinStakeAmount(); if (params.minPrincipalPerStaker >= params.initialMaxPrincipalPerStaker) { revert InvalidMinStakeAmount(); } if (params.maxUnbondingPeriod == 0) { revert InvalidMaxUnbondingPeriod(params.maxUnbondingPeriod); } if (params.minClaimPeriod == 0 || params.minClaimPeriod >= params.maxClaimPeriod) { revert InvalidClaimPeriodRange(params.minClaimPeriod, params.maxClaimPeriod); } i_LINK = params.LINKAddress; i_minPrincipalPerStaker = params.minPrincipalPerStaker; i_maxUnbondingPeriod = params.maxUnbondingPeriod; _setUnbondingPeriod(params.initialUnbondingPeriod); _setPoolConfig(params.initialMaxPoolSize, params.initialMaxPrincipalPerStaker); i_minClaimPeriod = params.minClaimPeriod; i_maxClaimPeriod = params.maxClaimPeriod; _setClaimPeriod(params.initialClaimPeriod); } /// @inheritdoc IMigratable /// @dev This will migrate the staker's staked LINK /// @dev precondition This contract must be closed and upgraded to a new pool. /// @dev precondition The migration target must be set. /// @dev precondition The caller must be staked in the pool. function migrate(bytes calldata data) external whenClosed validateMigrationTargetSet { // must be in storage to get access to latest() IStakingPool.Staker storage staker = s_stakers[msg.sender]; uint224 history = staker.history.latest(); uint112 stakerPrincipal = uint112(history >> 112); uint112 stakerStakedAtTime = uint112(history); if (stakerPrincipal == 0) revert StakeNotFound(msg.sender); bytes memory migrationData = abi.encode(msg.sender, stakerStakedAtTime, data); // Finalize staker's rewards to include any rewards they have earned before resetting the // principal and stakedAtTime. s_rewardVault.concludeRewardPeriod({ staker: msg.sender, oldPrincipal: stakerPrincipal, stakedAt: stakerStakedAtTime, unstakedAmount: stakerPrincipal, shouldForfeit: false }); s_pool.state.totalPrincipal -= stakerPrincipal; // do not reset staked at time to not reset the multiplier because staker is not forfeiting // rewards when migrating _updateStakerHistory({ staker: staker, latestPrincipal: 0, latestStakedAtTime: stakerStakedAtTime }); // The return value is not checked since the call will revert if any balance, allowance or // receiver conditions fail. i_LINK.transferAndCall({to: s_migrationTarget, value: stakerPrincipal, data: migrationData}); emit StakerMigrated(s_migrationTarget, stakerPrincipal, migrationData); } /// @notice Starts the unbonding period for the staker. A staker may unstake /// their staked LINK during the claim period that follows the unbonding period. /// @dev precondition The caller must be staked in the pool. /// @dev precondition The caller must not be in an unbonding period. /// @dev precondition The caller must not be in a claim period. function unbond() external virtual { Staker storage staker = s_stakers[msg.sender]; uint224 history = staker.history.latest(); uint112 stakerPrincipal = uint112(history >> 112); if (stakerPrincipal == 0) revert StakeNotFound(msg.sender); _unbond(staker); } /// @notice Sets the new unbonding period for the pool. Stakers that are /// already unbonding will not be affected. /// @param newUnbondingPeriod The new unbonding period /// @dev precondition The caller must have the default admin role. /// @dev precondition Cannot be called after the pool is closed. function setUnbondingPeriod(uint256 newUnbondingPeriod) external onlyRole(DEFAULT_ADMIN_ROLE) whenBeforeClosing { _setUnbondingPeriod(newUnbondingPeriod); } /// @notice Returns the max unbonding period /// @return uint256 The max value that the unbonding period can be set to function getMaxUnbondingPeriod() external view returns (uint256) { return (i_maxUnbondingPeriod); } /// @notice Set the claim period /// @param claimPeriod The claim period /// @dev precondition Cannot be called after the pool is closed. function setClaimPeriod(uint256 claimPeriod) external onlyRole(DEFAULT_ADMIN_ROLE) whenBeforeClosing { _setClaimPeriod(claimPeriod); } /// @notice Sets the new reward vault for the pool /// @param newRewardVault The new reward vault /// @dev precondition The caller must have the default admin role. /// @dev precondition Cannot be called after the pool is closed. function setRewardVault(IRewardVault newRewardVault) external onlyRole(DEFAULT_ADMIN_ROLE) whenBeforeClosing { if (address(newRewardVault) == address(0)) revert InvalidZeroAddress(); address oldRewardVault = address(s_rewardVault); if (oldRewardVault == address(newRewardVault)) return; if (address(s_rewardVault) != address(0) && s_rewardVault.isOpen()) { revert RewardVaultNotClosed(); } if ( address(s_rewardVault) != address(0) && (!newRewardVault.isOpen() || newRewardVault.isPaused()) ) revert RewardVaultNotActive(); if (address(s_rewardVault) != address(0) && !newRewardVault.hasRewardAdded()) { revert RewardVaultHasNoRewards(); } s_rewardVault = newRewardVault; emit RewardVaultSet(oldRewardVault, address(newRewardVault)); } /// @notice LINK transfer callback function called when transferAndCall is called with this /// contract as a target. /// @param sender staker's address if they stake into the pool by calling transferAndCall on the /// LINK token, or MigrationProxy contract when a staker migrates from V0.1 to V0.2 /// @param amount Amount of LINK token transferred /// @param data Bytes data received, represents migration path /// @inheritdoc ERC677ReceiverInterface /// @dev precondition The migration proxy must be set. /// @dev precondition This contract must be open and not paused. /// @dev precondition The reward vault must be open and not paused. function onTokenTransfer( address sender, uint256 amount, bytes calldata data ) external validateFromLINK validateMigrationProxySet whenOpen whenRewardVaultOpen whenNotPaused { if (amount == 0) return; // Check if this call was forwarded from the migration proxy. address staker = sender == s_migrationProxy ? _getStakerAddress(data) : sender; if (staker == address(0)) revert InvalidZeroAddress(); // includes access check for non migration proxy _validateOnTokenTransfer(sender, staker, data); Staker storage stakerState = s_stakers[staker]; uint224 history = stakerState.history.latest(); uint256 stakerPrincipal = uint256(history >> 112); uint256 stakedAt = uint112(history); _resetUnbondingPeriod(stakerState, staker); s_rewardVault.concludeRewardPeriod({ staker: staker, oldPrincipal: stakerPrincipal, unstakedAmount: 0, shouldForfeit: false, stakedAt: stakedAt }); _increaseStake(staker, stakerPrincipal + amount, amount); } /// @notice Returns the minimum and maximum claim periods that can be set by the owner /// @return uint256 minimum claim period /// @return uint256 maximum claim period function getClaimPeriodLimits() external view returns (uint256, uint256) { return (i_minClaimPeriod, i_maxClaimPeriod); } // ================= // IStakingOwner // ================= /// @inheritdoc IStakingOwner /// @dev precondition The caller must have the default admin role. function setPoolConfig( uint256 maxPoolSize, uint256 maxPrincipalPerStaker ) external virtual onlyRole(DEFAULT_ADMIN_ROLE) whenOpen { _setPoolConfig(maxPoolSize, maxPrincipalPerStaker); } /// @inheritdoc IStakingOwner /// @dev precondition The caller must have the initiator role. function open() external onlyRole(INITIATOR_ROLE) whenBeforeOpening validateRewardVaultSet whenRewardVaultOpen whenRewardVaultHasRewards { _validateBeforeOpen(); s_isOpen = true; emit PoolOpened(); } /// @inheritdoc IStakingOwner /// @dev precondition The caller must have the default admin role. function close() external onlyRole(DEFAULT_ADMIN_ROLE) whenOpen { s_isOpen = false; s_pool.state.closedAt = block.timestamp; emit PoolClosed(); } /// @inheritdoc IStakingOwner /// @dev precondition The caller must have the default admin role. function setMigrationProxy(address migrationProxy) external onlyRole(DEFAULT_ADMIN_ROLE) whenBeforeClosing { if (migrationProxy == address(0)) revert InvalidZeroAddress(); if (s_migrationProxy == migrationProxy) return; address oldMigrationProxy = s_migrationProxy; s_migrationProxy = migrationProxy; emit MigrationProxySet(oldMigrationProxy, migrationProxy); } // ================= // IStakingPool // ================= /// @inheritdoc IStakingPool /// @dev precondition The caller must be staked in the pool. /// @dev precondition The caller must be in the claim period or the pool must be closed or paused. /// @dev There is a possible reentrancy attack here where a malicious admin /// can point this pool to a malicious reward vault that calls unstake on the /// pool again. This reentrancy attack is possible as the pool updates the /// staker's staked LINK amount after it calls concludeRewardPeriod on the configured reward /// vault. This scenario is mitigated by forcing the admin to go through /// a timelock period that is longer than the unbonding period, which will /// provide stakers sufficient time to withdraw their staked LINK from the /// pool before a malicious reward vault is set. function unstake(uint256 amount) external { // cannot unstake 0 if (amount == 0) revert UnstakeZeroAmount(); Staker storage staker = s_stakers[msg.sender]; if (!_canUnstake(staker)) { revert StakerNotInClaimPeriod(msg.sender); } uint224 history = staker.history.latest(); uint256 stakerPrincipal = uint256(history >> 112); uint256 stakedAt = uint112(history); // verify that the staker has enough staked LINK amount to unstake if (amount > stakerPrincipal) revert UnstakeExceedsPrincipal(); uint256 updatedPrincipal = stakerPrincipal - amount; // in the case of a partial withdrawal, verify new staked LINK amount is above minimum if (amount < stakerPrincipal && updatedPrincipal < i_minPrincipalPerStaker) { revert UnstakePrincipalBelowMinAmount(); } s_rewardVault.concludeRewardPeriod({ staker: msg.sender, oldPrincipal: stakerPrincipal, unstakedAmount: amount, shouldForfeit: true, stakedAt: stakedAt }); s_pool.state.totalPrincipal -= amount; // Reset the staker's staked at time to 0 to prevent the multiplier // from growing if the staker has unstaked all their staked LINK _updateStakerHistory({ staker: staker, latestPrincipal: updatedPrincipal, latestStakedAtTime: updatedPrincipal == 0 ? 0 : block.timestamp }); // The return value is not checked since the call will revert if any balance, allowance or // receiver conditions fail. i_LINK.transfer(msg.sender, amount); emit Unstaked(msg.sender, amount, updatedPrincipal, s_pool.state.totalPrincipal); } /// @inheritdoc IStakingPool function getTotalPrincipal() external view returns (uint256) { return s_pool.state.totalPrincipal; } /// @inheritdoc IStakingPool function getStakerPrincipal(address staker) external view returns (uint256) { return uint112(s_stakers[staker].history.latest() >> 112); } /// @inheritdoc IStakingPool function getStakerPrincipalAt( address staker, uint256 blockNumber ) external view returns (uint256) { // `Checkpoints` requires to exclude the current block when calling `getAtBlock` return (blockNumber == block.number) ? uint112(s_stakers[staker].history.latest() >> 112) : uint112(s_stakers[staker].history.getAtBlock(blockNumber) >> 112); } /// @inheritdoc IStakingPool function getStakerStakedAtTime(address staker) external view returns (uint256) { return uint112(s_stakers[staker].history.latest()); } /// @inheritdoc IStakingPool function getStakerStakedAtTimeAt( address staker, uint256 blockNumber ) external view returns (uint256) { // `Checkpoints` requires to exclude the current block when calling `getAtBlock` return (blockNumber == block.number) ? uint112(s_stakers[staker].history.latest()) : uint112(s_stakers[staker].history.getAtBlock(blockNumber)); } /// @inheritdoc IStakingPool function getRewardVault() external view returns (IRewardVault) { return s_rewardVault; } /// @inheritdoc IStakingPool function getChainlinkToken() external view returns (address) { return address(i_LINK); } /// @inheritdoc IStakingPool function getMigrationProxy() external view returns (address) { return s_migrationProxy; } /// @inheritdoc IStakingPool function isOpen() external view returns (bool) { return s_isOpen; } /// @inheritdoc IStakingPool function isActive() external view returns (bool) { return _isActive(); } /// @inheritdoc IStakingPool function getStakerLimits() external view returns (uint256, uint256) { return (i_minPrincipalPerStaker, s_pool.configs.maxPrincipalPerStaker); } /// @inheritdoc IStakingPool function getMaxPoolSize() external view returns (uint256) { return s_pool.configs.maxPoolSize; } /// @notice Returns the time a staker's unbonding period ends /// @param staker The address of the staker to query /// @return uint256 The timestamp of when the staker's unbonding period ends. /// This value will be 0 if the unbonding period is not active. function getUnbondingEndsAt(address staker) external view returns (uint256) { return s_stakers[staker].unbondingPeriodEndsAt; } /// @notice Returns the pool's unbonding parameters /// @return uint256 The pool's unbonding period /// @return uint256 The pools's claim period function getUnbondingParams() external view returns (uint256, uint256) { return (s_pool.configs.unbondingPeriod, s_pool.configs.claimPeriod); } /// @notice Returns the time a staker's claim period ends /// @param staker The staker trying to unstake their staked LINK /// @return uint256 The timestamp of when the staker's claim period ends. /// This value will be 0 if the unbonding period has not started. function getClaimPeriodEndsAt(address staker) external view returns (uint256) { return s_stakers[staker].claimPeriodEndsAt; } // =============== // ERC165 // =============== /// @notice This function allows the calling contract to /// check if the contract deployed at this address is a valid /// LINKTokenReceiver. A contract is a valid LINKTokenReceiver /// if it implements the onTokenTransfer function. /// @param interfaceID The ID of the interface to check against /// @return bool True if the contract is a valid LINKTokenReceiver. function supportsInterface(bytes4 interfaceID) public view override returns (bool) { return interfaceID == this.onTokenTransfer.selector || super.supportsInterface(interfaceID); } // ========= // Helpers // ========= /// @notice Resets a staker's unbonding period /// @param stakerState The staker's current state /// @param staker The address of the staker to reset the unbonding period for /// @dev This sets the stakerState's unbondingPeriodEndsAt and /// claimPeriodEndsAt to 0 function _resetUnbondingPeriod(Staker storage stakerState, address staker) internal { if (stakerState.unbondingPeriodEndsAt != 0) { delete stakerState.unbondingPeriodEndsAt; delete stakerState.claimPeriodEndsAt; emit UnbondingPeriodReset(staker); } } /// @inheritdoc Migratable /// @dev precondition The migration target must implement the onTokenTransfer function. /// @dev precondition Cannot be called after the pool is closed. function _validateMigrationTarget(address newMigrationTarget) internal override whenBeforeClosing { Migratable._validateMigrationTarget(newMigrationTarget); if ( !IERC165(newMigrationTarget).supportsInterface( ERC677ReceiverInterface.onTokenTransfer.selector ) ) { revert InvalidMigrationTarget(); } } /// @notice Validate for when LINK is staked or migrated into the pool /// @param sender The address transferring LINK into the pool. Could be the migration proxy /// contract or the staker. /// @param staker The address staking or migrating LINK into the pool /// @param data Arbitrary data passed when staking or migrating function _validateOnTokenTransfer( address sender, address staker, bytes calldata data ) internal view virtual; /// @notice Validates pool state before opening function _validateBeforeOpen() internal view virtual; /// @notice Util function for setting the pool config /// @param maxPoolSize The max amount of staked LINK allowed in the pool /// @param maxPrincipalPerStaker The max amount of LINK a staker can stake /// in the pool. function _setPoolConfig(uint256 maxPoolSize, uint256 maxPrincipalPerStaker) internal { PoolConfigs storage configs = s_pool.configs; // only allow increasing the maxPoolSize if (maxPoolSize == 0 || maxPoolSize < configs.maxPoolSize) { revert InvalidPoolSize(maxPoolSize); } // only allow increasing the maxPrincipalPerStaker if ( maxPrincipalPerStaker == 0 || maxPrincipalPerStaker > maxPoolSize || configs.maxPrincipalPerStaker > maxPrincipalPerStaker ) revert InvalidMaxStakeAmount(maxPrincipalPerStaker); if (configs.maxPoolSize != maxPoolSize) { configs.maxPoolSize = maxPoolSize.toUint96(); emit PoolSizeIncreased(maxPoolSize); } if (configs.maxPrincipalPerStaker != maxPrincipalPerStaker) { configs.maxPrincipalPerStaker = maxPrincipalPerStaker.toUint96(); emit MaxPrincipalAmountIncreased(maxPrincipalPerStaker); } } /// @notice Util function for setting the unbonding period /// @param unbondingPeriod The unbonding period function _setUnbondingPeriod(uint256 unbondingPeriod) internal { if (unbondingPeriod == 0 || unbondingPeriod > i_maxUnbondingPeriod) { revert InvalidUnbondingPeriod(); } if (s_pool.configs.unbondingPeriod == unbondingPeriod) return; uint256 oldUnbondingPeriod = s_pool.configs.unbondingPeriod; s_pool.configs.unbondingPeriod = unbondingPeriod.toUint32(); emit UnbondingPeriodSet(oldUnbondingPeriod, unbondingPeriod); } /// @notice Updates the staking pool state and the staker state /// @param sender The staker address /// @param newPrincipal The staker's staked LINK amount after staking /// @param amount The amount to stake function _increaseStake(address sender, uint256 newPrincipal, uint256 amount) internal { Staker storage staker = s_stakers[sender]; // validate staking limits if (newPrincipal < i_minPrincipalPerStaker) { revert InsufficientStakeAmount(); } if (newPrincipal > s_pool.configs.maxPrincipalPerStaker) { revert ExceedsMaxStakeAmount(); } uint256 newTotalPrincipal = s_pool.state.totalPrincipal + amount; if (newTotalPrincipal > s_pool.configs.maxPoolSize) { revert ExceedsMaxPoolSize(); } // update the pool state s_pool.state.totalPrincipal = newTotalPrincipal; // update the staker state _updateStakerHistory({ staker: staker, latestPrincipal: newPrincipal, latestStakedAtTime: block.timestamp }); emit Staked(sender, amount, newPrincipal, newTotalPrincipal); } /// @notice Gets the staker address from the data passed by the MigrationProxy contract /// @param data The data passed by the MigrationProxy contract /// @return The staker address function _getStakerAddress(bytes calldata data) internal pure returns (address) { if (data.length == 0) revert InvalidData(); // decode the data (address staker) = abi.decode(data, (address)); return staker; } /// @notice Checks to see whether or not a staker is eligible to /// unstake their staked LINK amount (when the pool is closed or, when the pool is open and they /// are in the claim period or, when pool is paused) /// @param staker The staker trying to unstake their staked LINK /// @return bool True if the staker is eligible to unstake function _canUnstake(Staker storage staker) internal view returns (bool) { return s_pool.state.closedAt != 0 || _inClaimPeriod(staker) || paused(); } /// @notice Updates the staker's staked LINK amount history /// @param staker The staker to update /// @param latestPrincipal The staker's latest staked LINK amount /// @param latestStakedAtTime The staker's latest average staked at time function _updateStakerHistory( Staker storage staker, uint256 latestPrincipal, uint256 latestStakedAtTime ) internal { staker.history.push( (uint224(uint112(latestPrincipal)) << 112) | uint224(uint112(latestStakedAtTime)) ); } /// @notice Starts the unbonding period for the staker /// @param staker The staker trying to unbond function _unbond(Staker storage staker) internal { if (staker.unbondingPeriodEndsAt != 0 && block.timestamp <= staker.claimPeriodEndsAt) { revert UnbondingOrClaimPeriodActive(staker.unbondingPeriodEndsAt); } staker.unbondingPeriodEndsAt = (block.timestamp + s_pool.configs.unbondingPeriod).toUint128(); staker.claimPeriodEndsAt = staker.unbondingPeriodEndsAt + s_pool.configs.claimPeriod; emit UnbondingPeriodStarted(msg.sender); } /// @notice Checks to see whether or not a staker is within the claim period /// to unstake their staked LINK /// @param staker The staker trying to unstake their staked LINK /// @return bool True if the staker is inside the claim period function _inClaimPeriod(Staker storage staker) private view returns (bool) { if (staker.unbondingPeriodEndsAt == 0 || block.timestamp < staker.unbondingPeriodEndsAt) { return false; } return block.timestamp <= staker.claimPeriodEndsAt; } /// @notice Util function for setting the claim period /// @param claimPeriod The claim period function _setClaimPeriod(uint256 claimPeriod) private { if (claimPeriod < i_minClaimPeriod || claimPeriod > i_maxClaimPeriod) { revert InvalidClaimPeriod(); } if (s_pool.configs.claimPeriod == claimPeriod) return; uint256 oldClaimPeriod = s_pool.configs.claimPeriod; s_pool.configs.claimPeriod = claimPeriod.toUint32(); emit ClaimPeriodSet(oldClaimPeriod, claimPeriod); } /// @notice Util function to check if the reward vault connected to this pool has rewards added to /// it /// @return bool True if the reward vault has rewards added to it, false otherwise function _hasRewardVaultRewardAdded() internal view virtual returns (bool) { return s_rewardVault.hasRewardAdded(); } /// @notice Util function to check if the pool is active /// @return bool True if the pool is active, false otherwise function _isActive() internal view returns (bool) { return s_isOpen && !s_rewardVault.hasRewardDurationEnded(address(this)); } // ========= // Modifiers // ========= /// @dev Reverts if not sent from the LINK token modifier validateFromLINK() { if (msg.sender != address(i_LINK)) revert SenderNotLinkToken(); _; } /// @dev Reverts if migration proxy is not set modifier validateMigrationProxySet() { if (s_migrationProxy == address(0)) revert MigrationProxyNotSet(); _; } /// @dev Reverts if reward vault is not set modifier validateRewardVaultSet() { if (address(s_rewardVault) == address(0)) revert RewardVaultNotSet(); _; } /// @dev Reverts if pool is after an opening modifier whenBeforeOpening() { if (s_isOpen) revert PoolHasBeenOpened(); if (s_pool.state.closedAt != 0) revert PoolHasBeenClosed(); _; } /// @dev Reverts if the pool is already closed modifier whenBeforeClosing() { if (s_pool.state.closedAt != 0) revert PoolHasBeenClosed(); _; } /// @dev Reverts if pool is not open modifier whenOpen() { if (!s_isOpen) revert PoolNotOpen(); _; } /// @dev Reverts if pool is not active (is open and rewards are available for this pool) modifier whenActive() { if (!_isActive()) revert PoolNotActive(); _; } /// @dev Reverts if pool is not closed modifier whenClosed() { if (s_pool.state.closedAt == 0) revert PoolNotClosed(); _; } /// @dev Reverts if reward vault is not open or is paused modifier whenRewardVaultOpen() { if (!s_rewardVault.isOpen() || s_rewardVault.isPaused()) revert RewardVaultNotActive(); _; } /// @dev Reverts if reward vault has not had rewards added to it modifier whenRewardVaultHasRewards() { if (!_hasRewardVaultRewardAdded()) revert RewardVaultHasNoRewards(); _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControlDefaultAdminRules.sol) pragma solidity ^0.8.0; import "./AccessControl.sol"; import "./IAccessControlDefaultAdminRules.sol"; import "../utils/math/SafeCast.sol"; import "../interfaces/IERC5313.sol"; /** * @dev Extension of {AccessControl} that allows specifying special rules to manage * the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions * over other roles that may potentially have privileged rights in the system. * * If a specific role doesn't have an admin role assigned, the holder of the * `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it. * * This contract implements the following risk mitigations on top of {AccessControl}: * * * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced. * * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account. * * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted. * * The delay can be changed by scheduling, see {changeDefaultAdminDelay}. * * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`. * * Example usage: * * ```solidity * contract MyToken is AccessControlDefaultAdminRules { * constructor() AccessControlDefaultAdminRules( * 3 days, * msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder * ) {} * } * ``` * * _Available since v4.9._ */ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl { // pending admin pair read/written together frequently address private _pendingDefaultAdmin; uint48 private _pendingDefaultAdminSchedule; // 0 == unset uint48 private _currentDelay; address private _currentDefaultAdmin; // pending delay pair read/written together frequently uint48 private _pendingDelay; uint48 private _pendingDelaySchedule; // 0 == unset /** * @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address. */ constructor(uint48 initialDelay, address initialDefaultAdmin) { require(initialDefaultAdmin != address(0), "AccessControl: 0 default admin"); _currentDelay = initialDelay; _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC5313-owner}. */ function owner() public view virtual returns (address) { return defaultAdmin(); } /// /// Override AccessControl role management /// /** * @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`. */ function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly grant default admin role"); super.grantRole(role, account); } /** * @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`. */ function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly revoke default admin role"); super.revokeRole(role, account); } /** * @dev See {AccessControl-renounceRole}. * * For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling * {beginDefaultAdminTransfer} to the `address(0)`, so it's required that the {pendingDefaultAdmin} schedule * has also passed when calling this function. * * After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions. * * NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a {defaultAdmin}, * thereby disabling any functionality that is only available for it, and the possibility of reassigning a * non-administrated role. */ function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin(); require( newDefaultAdmin == address(0) && _isScheduleSet(schedule) && _hasSchedulePassed(schedule), "AccessControl: only can renounce in two delayed steps" ); delete _pendingDefaultAdminSchedule; } super.renounceRole(role, account); } /** * @dev See {AccessControl-_grantRole}. * * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the * role has been previously renounced. * * NOTE: Exposing this function through another mechanism may make the `DEFAULT_ADMIN_ROLE` * assignable again. Make sure to guarantee this is the expected behavior in your implementation. */ function _grantRole(bytes32 role, address account) internal virtual override { if (role == DEFAULT_ADMIN_ROLE) { require(defaultAdmin() == address(0), "AccessControl: default admin already granted"); _currentDefaultAdmin = account; } super._grantRole(role, account); } /** * @dev See {AccessControl-_revokeRole}. */ function _revokeRole(bytes32 role, address account) internal virtual override { if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { delete _currentDefaultAdmin; } super._revokeRole(role, account); } /** * @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override { require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't violate default admin rules"); super._setRoleAdmin(role, adminRole); } /// /// AccessControlDefaultAdminRules accessors /// /** * @inheritdoc IAccessControlDefaultAdminRules */ function defaultAdmin() public view virtual returns (address) { return _currentDefaultAdmin; } /** * @inheritdoc IAccessControlDefaultAdminRules */ function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) { return (_pendingDefaultAdmin, _pendingDefaultAdminSchedule); } /** * @inheritdoc IAccessControlDefaultAdminRules */ function defaultAdminDelay() public view virtual returns (uint48) { uint48 schedule = _pendingDelaySchedule; return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? _pendingDelay : _currentDelay; } /** * @inheritdoc IAccessControlDefaultAdminRules */ function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) { schedule = _pendingDelaySchedule; return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? (_pendingDelay, schedule) : (0, 0); } /** * @inheritdoc IAccessControlDefaultAdminRules */ function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) { return 5 days; } /// /// AccessControlDefaultAdminRules public and internal setters for defaultAdmin/pendingDefaultAdmin /// /** * @inheritdoc IAccessControlDefaultAdminRules */ function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) { _beginDefaultAdminTransfer(newAdmin); } /** * @dev See {beginDefaultAdminTransfer}. * * Internal function without access restriction. */ function _beginDefaultAdminTransfer(address newAdmin) internal virtual { uint48 newSchedule = SafeCast.toUint48(block.timestamp) + defaultAdminDelay(); _setPendingDefaultAdmin(newAdmin, newSchedule); emit DefaultAdminTransferScheduled(newAdmin, newSchedule); } /** * @inheritdoc IAccessControlDefaultAdminRules */ function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) { _cancelDefaultAdminTransfer(); } /** * @dev See {cancelDefaultAdminTransfer}. * * Internal function without access restriction. */ function _cancelDefaultAdminTransfer() internal virtual { _setPendingDefaultAdmin(address(0), 0); } /** * @inheritdoc IAccessControlDefaultAdminRules */ function acceptDefaultAdminTransfer() public virtual { (address newDefaultAdmin, ) = pendingDefaultAdmin(); require(_msgSender() == newDefaultAdmin, "AccessControl: pending admin must accept"); _acceptDefaultAdminTransfer(); } /** * @dev See {acceptDefaultAdminTransfer}. * * Internal function without access restriction. */ function _acceptDefaultAdminTransfer() internal virtual { (address newAdmin, uint48 schedule) = pendingDefaultAdmin(); require(_isScheduleSet(schedule) && _hasSchedulePassed(schedule), "AccessControl: transfer delay not passed"); _revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin()); _grantRole(DEFAULT_ADMIN_ROLE, newAdmin); delete _pendingDefaultAdmin; delete _pendingDefaultAdminSchedule; } /// /// AccessControlDefaultAdminRules public and internal setters for defaultAdminDelay/pendingDefaultAdminDelay /// /** * @inheritdoc IAccessControlDefaultAdminRules */ function changeDefaultAdminDelay(uint48 newDelay) public virtual onlyRole(DEFAULT_ADMIN_ROLE) { _changeDefaultAdminDelay(newDelay); } /** * @dev See {changeDefaultAdminDelay}. * * Internal function without access restriction. */ function _changeDefaultAdminDelay(uint48 newDelay) internal virtual { uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay); _setPendingDelay(newDelay, newSchedule); emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule); } /** * @inheritdoc IAccessControlDefaultAdminRules */ function rollbackDefaultAdminDelay() public virtual onlyRole(DEFAULT_ADMIN_ROLE) { _rollbackDefaultAdminDelay(); } /** * @dev See {rollbackDefaultAdminDelay}. * * Internal function without access restriction. */ function _rollbackDefaultAdminDelay() internal virtual { _setPendingDelay(0, 0); } /** * @dev Returns the amount of seconds to wait after the `newDelay` will * become the new {defaultAdminDelay}. * * The value returned guarantees that if the delay is reduced, it will go into effect * after a wait that honors the previously set delay. * * See {defaultAdminDelayIncreaseWait}. */ function _delayChangeWait(uint48 newDelay) internal view virtual returns (uint48) { uint48 currentDelay = defaultAdminDelay(); // When increasing the delay, we schedule the delay change to occur after a period of "new delay" has passed, up // to a maximum given by defaultAdminDelayIncreaseWait, by default 5 days. For example, if increasing from 1 day // to 3 days, the new delay will come into effect after 3 days. If increasing from 1 day to 10 days, the new // delay will come into effect after 5 days. The 5 day wait period is intended to be able to fix an error like // using milliseconds instead of seconds. // // When decreasing the delay, we wait the difference between "current delay" and "new delay". This guarantees // that an admin transfer cannot be made faster than "current delay" at the time the delay change is scheduled. // For example, if decreasing from 10 days to 3 days, the new delay will come into effect after 7 days. return newDelay > currentDelay ? uint48(Math.min(newDelay, defaultAdminDelayIncreaseWait())) // no need to safecast, both inputs are uint48 : currentDelay - newDelay; } /// /// Private setters /// /** * @dev Setter of the tuple for pending admin and its schedule. * * May emit a DefaultAdminTransferCanceled event. */ function _setPendingDefaultAdmin(address newAdmin, uint48 newSchedule) private { (, uint48 oldSchedule) = pendingDefaultAdmin(); _pendingDefaultAdmin = newAdmin; _pendingDefaultAdminSchedule = newSchedule; // An `oldSchedule` from `pendingDefaultAdmin()` is only set if it hasn't been accepted. if (_isScheduleSet(oldSchedule)) { // Emit for implicit cancellations when another default admin was scheduled. emit DefaultAdminTransferCanceled(); } } /** * @dev Setter of the tuple for pending delay and its schedule. * * May emit a DefaultAdminDelayChangeCanceled event. */ function _setPendingDelay(uint48 newDelay, uint48 newSchedule) private { uint48 oldSchedule = _pendingDelaySchedule; if (_isScheduleSet(oldSchedule)) { if (_hasSchedulePassed(oldSchedule)) { // Materialize a virtual delay _currentDelay = _pendingDelay; } else { // Emit for implicit cancellations when another delay was scheduled. emit DefaultAdminDelayChangeCanceled(); } } _pendingDelay = newDelay; _pendingDelaySchedule = newSchedule; } /// /// Private helpers /// /** * @dev Defines if an `schedule` is considered set. For consistency purposes. */ function _isScheduleSet(uint48 schedule) private pure returns (bool) { return schedule != 0; } /** * @dev Defines if an `schedule` is considered passed. For consistency purposes. */ function _hasSchedulePassed(uint48 schedule) private view returns (bool) { return schedule < block.timestamp; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Checkpoints.sol) // This file was procedurally generated from scripts/generate/templates/Checkpoints.js. pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SafeCast.sol"; /** * @dev This library defines the `History` struct, for checkpointing values as they change at different points in * time, and later looking up past values by block number. See {Votes} as an example. * * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new * checkpoint for the current transaction block using the {push} function. * * _Available since v4.5._ */ library Checkpoints { struct History { Checkpoint[] _checkpoints; } struct Checkpoint { uint32 _blockNumber; uint224 _value; } /** * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one * before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the * block, the requested block number must be in the past, excluding the current block. */ function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) { require(blockNumber < block.number, "Checkpoints: block not yet mined"); uint32 key = SafeCast.toUint32(blockNumber); uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one * before it is returned, or zero otherwise. Similar to {upperLookup} but optimized for the case when the searched * checkpoint is probably "recent", defined as being among the last sqrt(N) checkpoints where N is the number of * checkpoints. */ function getAtProbablyRecentBlock(History storage self, uint256 blockNumber) internal view returns (uint256) { require(blockNumber < block.number, "Checkpoints: block not yet mined"); uint32 key = SafeCast.toUint32(blockNumber); uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._blockNumber) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block. * * Returns previous value and new value. */ function push(History storage self, uint256 value) internal returns (uint256, uint256) { return _insert(self._checkpoints, SafeCast.toUint32(block.number), SafeCast.toUint224(value)); } /** * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will * be set to `op(latest, delta)`. * * Returns previous value and new value. */ function push( History storage self, function(uint256, uint256) view returns (uint256) op, uint256 delta ) internal returns (uint256, uint256) { return push(self, op(latest(self), delta)); } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(History storage self) internal view returns (uint224) { uint256 pos = self._checkpoints.length; return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint( History storage self ) internal view returns (bool exists, uint32 _blockNumber, uint224 _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, 0); } else { Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._blockNumber, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(History storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert(Checkpoint[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { uint256 pos = self.length; if (pos > 0) { // Copying to memory is important here. Checkpoint memory last = _unsafeAccess(self, pos - 1); // Checkpoint keys must be non-decreasing. require(last._blockNumber <= key, "Checkpoint: decreasing keys"); // Update or push new checkpoint if (last._blockNumber == key) { _unsafeAccess(self, pos - 1)._value = value; } else { self.push(Checkpoint({_blockNumber: key, _value: value})); } return (last._value, value); } else { self.push(Checkpoint({_blockNumber: key, _value: value})); return (0, value); } } /** * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( Checkpoint[] storage self, uint32 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._blockNumber > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( Checkpoint[] storage self, uint32 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._blockNumber < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } struct Trace224 { Checkpoint224[] _checkpoints; } struct Checkpoint224 { uint32 _key; uint224 _value; } /** * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint. * * Returns previous value and new value. */ function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) { return _insert(self._checkpoints, key, value); } /** * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if there is none. */ function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { uint256 len = self._checkpoints.length; uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. */ function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). */ function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) { uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._key) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(Trace224 storage self) internal view returns (uint224) { uint256 pos = self._checkpoints.length; return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, 0); } else { Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(Trace224 storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { uint256 pos = self.length; if (pos > 0) { // Copying to memory is important here. Checkpoint224 memory last = _unsafeAccess(self, pos - 1); // Checkpoint keys must be non-decreasing. require(last._key <= key, "Checkpoint: decreasing keys"); // Update or push new checkpoint if (last._key == key) { _unsafeAccess(self, pos - 1)._value = value; } else { self.push(Checkpoint224({_key: key, _value: value})); } return (last._value, value); } else { self.push(Checkpoint224({_key: key, _value: value})); return (0, value); } } /** * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( Checkpoint224[] storage self, uint32 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( Checkpoint224[] storage self, uint32 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess( Checkpoint224[] storage self, uint256 pos ) private pure returns (Checkpoint224 storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } struct Trace160 { Checkpoint160[] _checkpoints; } struct Checkpoint160 { uint96 _key; uint160 _value; } /** * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint. * * Returns previous value and new value. */ function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) { return _insert(self._checkpoints, key, value); } /** * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if there is none. */ function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { uint256 len = self._checkpoints.length; uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. */ function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). */ function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) { uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._key) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(Trace160 storage self) internal view returns (uint160) { uint256 pos = self._checkpoints.length; return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, 0); } else { Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(Trace160 storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) { uint256 pos = self.length; if (pos > 0) { // Copying to memory is important here. Checkpoint160 memory last = _unsafeAccess(self, pos - 1); // Checkpoint keys must be non-decreasing. require(last._key <= key, "Checkpoint: decreasing keys"); // Update or push new checkpoint if (last._key == key) { _unsafeAccess(self, pos - 1)._value = value; } else { self.push(Checkpoint160({_key: key, _value: value})); } return (last._value, value); } else { self.push(Checkpoint160({_key: key, _value: value})); return (0, value); } } /** * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( Checkpoint160[] storage self, uint96 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( Checkpoint160[] storage self, uint96 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess( Checkpoint160[] storage self, uint256 pos ) private pure returns (Checkpoint160 storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; interface ISlashable { /// @notice This error is thrown when the slasher config is invalid error InvalidSlasherConfig(); /// @notice This error is thrown when the contract manager tries to set the slasher role directly /// through /// `grantRole` error InvalidRole(); /// @notice This error is thrown then the contract manager tries to set the slasher config for an /// address /// that doesn't have the slasher role error InvalidSlasher(); /// @notice This struct defines the parameters of the slasher config struct SlasherConfig { /// @notice The pool's refill rate (Juels/sec) uint256 refillRate; /// @notice The refillable slash capacity amount uint256 slashCapacity; } /// @notice This struct defines the parameters of the slasher state struct SlasherState { /// @notice The last slash timestamp, will be 0 if never slashed /// The timestamp will be set to the time the slashing configuration was configured /// instead of 0 if slashing never occurs, refilling slash capacity to full. uint256 lastSlashTimestamp; /// @notice The current amount of remaining slash capacity uint256 remainingSlashCapacityAmount; } /// @notice This struct defines the slasher's state and config struct Slasher { /// @notice The slasher's config SlasherConfig config; /// @notice The slasher's state SlasherState state; } /// @notice Adds a new slasher with the given config /// @param slasher The address of the slasher /// @param config The slasher config function addSlasher(address slasher, SlasherConfig calldata config) external; /// @notice Removes a slasher by revoking the SLASHER_ROLE and resetting the slasher config /// @param slasher The address of the slasher function removeSlasher(address slasher) external; /// @notice Sets the slasher config /// @param slasher The address of the slasher /// @param config The slasher config function setSlasherConfig(address slasher, SlasherConfig calldata config) external; /// @notice Returns the slasher config /// @param slasher The slasher /// @return The slasher config function getSlasherConfig(address slasher) external view returns (SlasherConfig memory); /// @notice Returns the slash capacity for a slasher /// @param slasher The slasher /// @return The slash capacity function getSlashCapacity(address slasher) external view returns (uint256); /// @notice Slashes stakers and rewards the alerter. Moves slashed staker /// funds into the alerter reward funds. The alerter is then /// rewarded by the funds in the alerter reward funds. /// @param stakers The list of stakers to slash /// @param alerter The alerter that successfully raised the alert /// @param principalAmount The amount of the staker's staked LINK amount to slash /// @param alerterRewardAmount The reward amount to be given to the alerter function slashAndReward( address[] calldata stakers, address alerter, uint256 principalAmount, uint256 alerterRewardAmount ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; interface IRewardVault { /// @notice This enum describes the different staker types enum StakerType { NOT_STAKED, COMMUNITY, OPERATOR } /// @notice This struct is used to store the reward information for a staker. struct StakerReward { /// @notice The staker's accrued multiplier-applied reward that's accounted for and stored. /// This is used for storing delegated rewards and preserving the staker's past rewards between /// unstakes or multiplier resets. /// To get the full claimable reward amount, this value is added to the stored reward * /// multiplier. /// @dev This value is reset when a staker calls claimRewards and rewards /// are transferred to the staker. uint112 vestedBaseReward; /// @notice The staker's accrued delegated reward that's accounted for and stored. /// Delegated rewards are not subject to the ramp up multiplier and are immediately finalized. /// @dev This value is reset when a staker calls claimRewards and rewards /// are transferred to the staker. uint112 vestedDelegatedReward; /// @notice The last updated per-token base reward of the staker. This /// value only increases over time uint112 baseRewardPerToken; /// @notice The last updated per-token delegated reward of the operator uint112 operatorDelegatedRewardPerToken; /// @notice The staker type /// @dev This value is set once the first time a staker stakes. This value is used to enforce /// that a community staker is not added as an operator. StakerType stakerType; /// @notice The amount of base rewards that the staker has claimed between /// the last time they staked/unstaked until they stake, unstake again or /// when an operator is removed. /// @dev This is reset to 0 whenever concludeRewardPeriod is called /// @dev This is set to vestedBaseReward whenever claimReward is called /// @dev Invariant: The sum of unvestedBaseReward and claimedBaseRewardsInPeriod /// is the total amount of base rewards a staker has earned since the last time /// they stake/unstake. uint112 claimedBaseRewardsInPeriod; /// @notice The staker's earned but unvested base rewards. The staker's current multiplier is /// applied to get the vested base reward amount. uint112 unvestedBaseReward; } /// @notice Claims reward earned by a staker. /// @return uint256 The amount of rewards claimed in juels function claimReward() external returns (uint256); /// @notice Updates the staking pools' reward per token and staker’s reward state /// in the reward vault. This is called whenever an operator is slashed as we want /// to update the operator's rewards state without resetting their multiplier. /// @param staker The staker's address. If this is set to zero address, /// staker's reward update will be skipped /// @param stakerPrincipal The staker's current staked LINK amount in juels function updateReward(address staker, uint256 stakerPrincipal) external; /// @notice Concludes the staker's current reward period (defined by a multiplier reset). /// This will apply the staker's current ramp up multiplier to their /// earned rewards and store the amount of rewards they have earned before /// their multiplier is reset. /// @dev This is called whenever 1) A staker stakes 2) A staker unstakes /// 3) An operator is removed as we want to update the staker's /// rewards AND reset their multiplier. /// @dev Staker rewards are not forfeited when they stake before they have /// reached their maximum ramp up period multiplier. Instead these /// rewards are stored as already earned rewards and will be subject to the /// multiplier the next time the contract calculates the staker's claimable /// rewards. /// @dev Staker rewards are forfeited when a staker unstakes before they /// have reached their maximum ramp up period multiplier. Additionally an /// operator will also forfeit any unclaimable rewards if they are removed /// before they reach the maximum ramp up period multiplier. The amount of /// rewards forfeited is proportional to the amount unstaked relative to /// the staker's total staked LINK amount when unstaking. A removed operator forfeits /// 100% of their unclaimable rewards. /// @param staker The staker addres /// @param oldPrincipal The staker's staked LINK amount before finalizing /// @param stakedAt The last time the staker staked at /// @param unstakedAmount The amount that the staker has unstaked in juels /// @param shouldForfeit True if rewards should be forfeited function concludeRewardPeriod( address staker, uint256 oldPrincipal, uint256 stakedAt, uint256 unstakedAmount, bool shouldForfeit ) external; /// @notice Closes the reward vault, disabling adding rewards and staking function close() external; /// @notice Returns a boolean that is true if the reward vault is open /// @return True if open, false otherwise function isOpen() external view returns (bool); /// @notice Returns the rewards that the staker would get if they withdraw now /// Rewards calculation is based on the staker's multiplier /// @param staker The staker's address /// @return The reward amount function getReward(address staker) external view returns (uint256); /// @notice Returns the stored reward info of the staker /// @param staker The staker address /// @return The staker's stored reward info function getStoredReward(address staker) external view returns (StakerReward memory); /// @notice Returns whether or not the vault is paused /// @return bool True if the vault is paused function isPaused() external view returns (bool); /// @notice Returns whether or not the reward duration for the pool has ended /// @param stakingPool The address of the staking pool rewards are being shared to /// @return bool True if the reward duration has ended function hasRewardDurationEnded(address stakingPool) external view returns (bool); /// @notice Returns whether or not the reward vault has had rewards added to it /// @return bool True if the reward vault has had rewards added to it function hasRewardAdded() external view returns (bool); /// @notice Returns the staking pools that are earning rewards from /// the reward vault /// @return address[] The staking pools that are earning rewards from the /// reward vault function getStakingPools() external view returns (address[] memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; interface ERC677ReceiverInterface { function onTokenTransfer( address sender, uint256 amount, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface LinkTokenInterface { function allowance(address owner, address spender) external view returns (uint256 remaining); function approve(address spender, uint256 value) external returns (bool success); function balanceOf(address owner) external view returns (uint256 balance); function decimals() external view returns (uint8 decimalPlaces); function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); function increaseApproval(address spender, uint256 subtractedValue) external; function name() external view returns (string memory tokenName); function symbol() external view returns (string memory tokenSymbol); function totalSupply() external view returns (uint256 totalTokensIssued); function transfer(address to, uint256 value) external returns (bool success); function transferAndCall( address to, uint256 value, bytes calldata data ) external returns (bool success); function transferFrom( address from, address to, uint256 value ) external returns (bool success); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; interface IMigratable { /// @notice This error is thrown when the owner tries to set the migration target to the /// zero address or an invalid address as well as when the migration target is not set and owner /// tries to migrate the contract. error InvalidMigrationTarget(); /// @notice This event is emitted when the migration target is set /// @param oldMigrationTarget The previous migration target /// @param newMigrationTarget The updated migration target event MigrationTargetSet(address indexed oldMigrationTarget, address indexed newMigrationTarget); /// @notice Sets the address this contract will be upgraded to /// @param newMigrationTarget The address of the migration target function setMigrationTarget(address newMigrationTarget) external; /// @notice Returns the current migration target of the contract /// @return address The current migration target function getMigrationTarget() external view returns (address); /// @notice Migrates the contract /// @param data Optional calldata to call on new contract function migrate(bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; interface IStakingOwner { /// @notice This event is emitted when the staking pool is opened for staking event PoolOpened(); /// @notice This event is emitted when the staking pool is closed event PoolClosed(); /// @notice This error is thrown when an invalid min operator stake amount is /// supplied error InvalidMinStakeAmount(); /// @notice This error is raised when attempting to decrease maximum pool size /// @param maxPoolSize the proposed maximum pool size error InvalidPoolSize(uint256 maxPoolSize); /// @notice This error is raised when attempting to decrease maximum stake amount /// for the pool members /// @param maxStakeAmount the proposed maximum stake amount error InvalidMaxStakeAmount(uint256 maxStakeAmount); /// @notice This error is thrown when the staking pool is closed. error PoolNotOpen(); /// @notice This error is thrown when the staking pool is open. error PoolNotClosed(); /// @notice This error is thrown when the staking pool has been opened and contract manager tries /// to re-open. error PoolHasBeenOpened(); /// @notice This error is thrown when the pool has been closed and contract manager tries to /// re-open error PoolHasBeenClosed(); /// @notice Set the pool config /// @param maxPoolSize The max amount of staked LINK allowed in the pool /// @param maxPrincipalPerStaker The max amount of LINK a staker can stake /// in the pool. function setPoolConfig(uint256 maxPoolSize, uint256 maxPrincipalPerStaker) external; /// @notice Opens the pool for staking function open() external; /// @notice Closes the pool function close() external; /// @notice Sets the migration proxy contract address /// @param migrationProxy The migration proxy contract address function setMigrationProxy(address migrationProxy) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {IRewardVault} from "./IRewardVault.sol"; import {Checkpoints} from "@openzeppelin/contracts/utils/Checkpoints.sol"; interface IStakingPool { /// @notice This error is thrown when a caller tries to execute a transaction /// that they do not have permissions for error AccessForbidden(); /// @notice This event is emitted when the migration proxy address has been set /// @param oldMigrationProxy The old migration proxy contract address /// @param newMigrationProxy The new migration proxy contract address event MigrationProxySet(address indexed oldMigrationProxy, address indexed newMigrationProxy); /// @notice This event is emitted when the staking pool's maximum size is /// increased /// @param maxPoolSize the new maximum pool size event PoolSizeIncreased(uint256 maxPoolSize); /// @notice This event is emitted when the maximum stake amount // for the stakers in the pool is increased /// @param maxPrincipalPerStaker the new maximum stake amount event MaxPrincipalAmountIncreased(uint256 maxPrincipalPerStaker); /// @notice This event is emitted when a staker adds stake to the pool. /// @param staker Staker address /// @param amount Amount of stake added /// @param newStake New LINK amount staked /// @param newTotalPrincipal Total amount of juels staked in the pool event Staked(address indexed staker, uint256 amount, uint256 newStake, uint256 newTotalPrincipal); /// @notice This event is emitted when a staker removes stake from the pool. /// @param staker Staker address /// @param amount Amount of stake removed /// @param newStake New LINK amount staked /// @param newTotalPrincipal Total amount of staked juels remaining in the pool event Unstaked( address indexed staker, uint256 amount, uint256 newStake, uint256 newTotalPrincipal ); /// @notice This error is thrown whenever a zero-address is supplied when /// a non-zero address is required error InvalidZeroAddress(); /// @notice This error is thrown whenever the sender is not the LINK token error SenderNotLinkToken(); /// @notice This error is thrown whenever the migration proxy address has not been set error MigrationProxyNotSet(); /// @notice This error is thrown whenever the reward vault address has not been set error RewardVaultNotSet(); /// @notice This error is thrown when invalid data is passed to the onTokenTransfer function error InvalidData(); /// @notice This error is thrown when the staker tries to stake less than the min amount error InsufficientStakeAmount(); /// @notice This error is thrown when the staker tries to stake more than the max amount error ExceedsMaxStakeAmount(); /// @notice This error is thrown when the staker tries to stake more than the max pool size error ExceedsMaxPoolSize(); /// @notice This error is raised when stakers attempt to exit the pool /// @param staker address of the staker error StakeNotFound(address staker); /// @notice This error is thrown when the staker tries to unstake a zero amount error UnstakeZeroAmount(); /// @notice This error is thrown when the staker tries to unstake more than the /// staked LINK amount error UnstakeExceedsPrincipal(); /// @notice This error is thrown when the staker tries to unstake an amount that leaves their /// staked LINK amount below the minimum amount error UnstakePrincipalBelowMinAmount(); /// @notice This struct defines the state of a staker struct Staker { /// @notice The combined staked LINK amount and staked at time history /// @dev Both the staker staked LINK amount and staked at timestamp are stored in uint112 to /// save space /// @dev The max value of uint112 is greater than the total supply of LINK /// @dev The max value of uint112 can represent a timestamp in the year 3615, long after the /// staking program has ended /// @dev The combination is performed as such: /// uint224 history = (uint224(uint112(principal)) << 112) | /// uint224(uint112(stakedAtTime)) Checkpoints.History history; /// @notice The staker's unbonding period end time uint128 unbondingPeriodEndsAt; /// @notice The staker's claim period end time uint128 claimPeriodEndsAt; } /// @notice Unstakes amount LINK tokens from the staker’s staked LINK amount /// @param amount The amount of LINK tokens to unstake function unstake(uint256 amount) external; /// @notice Returns the total amount staked in the pool /// @return The total amount staked in pool function getTotalPrincipal() external view returns (uint256); /// @notice Returns the staker's staked LINK amount /// @param staker The address of the staker to query for /// @return uint256 The staker's staked LINK amount function getStakerPrincipal(address staker) external view returns (uint256); /// @notice Returns the staker's staked LINK amount /// @param staker The address of the staker to query for /// @param blockNumber The block number to fetch the staker's balance for. Pass 0 /// to return the staker's latest staked LINK amount /// @return uint256 The staker's staked LINK amount function getStakerPrincipalAt( address staker, uint256 blockNumber ) external view returns (uint256); /// @notice Returns the staker's average staked at time /// @param staker The address of the staker to query for /// @return uint256 The staker's average staked at time function getStakerStakedAtTime(address staker) external view returns (uint256); /// @notice Returns the staker's last staked at time for a block number ID /// @param staker The address of the staker to query for /// @param blockNumber The block number to query for /// @return uint256 The staker's staked at time for the block number ID function getStakerStakedAtTimeAt( address staker, uint256 blockNumber ) external view returns (uint256); /// @notice Returns the current reward vault address /// @return The reward vault function getRewardVault() external view returns (IRewardVault); /// @notice Returns the address of the LINK token contract /// @return The LINK token contract's address that is used by the pool function getChainlinkToken() external view returns (address); /// @notice Returns the migration proxy contract address /// @return The migration proxy contract address function getMigrationProxy() external view returns (address); /// @notice Returns a boolean that is true if the pool is open /// @return True if the pool is open, false otherwise function isOpen() external view returns (bool); /// @notice Returns a boolean that is true if the pool is active, /// i.e. is open and there are remaining rewards to vest in the pool. /// @return True if the pool is active, false otherwise function isActive() external view returns (bool); /// @notice Returns the minimum and maximum amounts a staker can stake in the /// pool /// @return uint256 minimum amount that can be staked by a staker /// @return uint256 maximum amount that can be staked by a staker function getStakerLimits() external view returns (uint256, uint256); /// @notice uint256 Returns the maximum amount that can be staked in the pool /// @return uint256 current maximum staking pool size function getMaxPoolSize() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {AccessControlDefaultAdminRules} from "@openzeppelin/contracts/access/AccessControlDefaultAdminRules.sol"; import {IMigratable} from "./interfaces/IMigratable.sol"; /// @notice Base contract that adds migration functionality. abstract contract Migratable is IMigratable, AccessControlDefaultAdminRules { /// @notice The address of the new contract that this contract will be upgraded to. address internal s_migrationTarget; function setMigrationTarget(address newMigrationTarget) external override onlyRole(DEFAULT_ADMIN_ROLE) { _validateMigrationTarget(newMigrationTarget); address oldMigrationTarget = s_migrationTarget; s_migrationTarget = newMigrationTarget; emit MigrationTargetSet(oldMigrationTarget, newMigrationTarget); } /// @inheritdoc IMigratable function getMigrationTarget() external view returns (address) { return s_migrationTarget; } /// @notice Helper function for validating the migration target /// @param newMigrationTarget The address of the new migration target function _validateMigrationTarget(address newMigrationTarget) internal virtual { if ( newMigrationTarget == address(0) || newMigrationTarget == address(this) || newMigrationTarget == s_migrationTarget || newMigrationTarget.code.length == 0 ) { revert InvalidMigrationTarget(); } } /// @dev Reverts if the migration target is not set modifier validateMigrationTargetSet() { if (s_migrationTarget == address(0)) { revert InvalidMigrationTarget(); } _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {AccessControlDefaultAdminRules} from "@openzeppelin/contracts/access/AccessControlDefaultAdminRules.sol"; import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; import {IPausable} from "./interfaces/IPausable.sol"; /// @notice Base contract that adds pausing and access control functionality. abstract contract PausableWithAccessControl is IPausable, Pausable, AccessControlDefaultAdminRules { /// @notice This is the ID for the pauser role, which is given to the addresses that can pause and /// unpause the contract. /// @dev Hash: 65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); constructor( uint48 adminRoleTransferDelay, address defaultAdmin ) AccessControlDefaultAdminRules(adminRoleTransferDelay, defaultAdmin) {} /// @inheritdoc IPausable function emergencyPause() external onlyRole(PAUSER_ROLE) { _pause(); } /// @inheritdoc IPausable function emergencyUnpause() external onlyRole(PAUSER_ROLE) { _unpause(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/IAccessControlDefaultAdminRules.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; /** * @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection. * * _Available since v4.9._ */ interface IAccessControlDefaultAdminRules is IAccessControl { /** * @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next * address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule` * passes. */ event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule); /** * @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule. */ event DefaultAdminTransferCanceled(); /** * @dev Emitted when a {defaultAdminDelay} change is started, setting `newDelay` as the next * delay to be applied between default admin transfer after `effectSchedule` has passed. */ event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule); /** * @dev Emitted when a {pendingDefaultAdminDelay} is reset if its schedule didn't pass. */ event DefaultAdminDelayChangeCanceled(); /** * @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder. */ function defaultAdmin() external view returns (address); /** * @dev Returns a tuple of a `newAdmin` and an accept schedule. * * After the `schedule` passes, the `newAdmin` will be able to accept the {defaultAdmin} role * by calling {acceptDefaultAdminTransfer}, completing the role transfer. * * A zero value only in `acceptSchedule` indicates no pending admin transfer. * * NOTE: A zero address `newAdmin` means that {defaultAdmin} is being renounced. */ function pendingDefaultAdmin() external view returns (address newAdmin, uint48 acceptSchedule); /** * @dev Returns the delay required to schedule the acceptance of a {defaultAdmin} transfer started. * * This delay will be added to the current timestamp when calling {beginDefaultAdminTransfer} to set * the acceptance schedule. * * NOTE: If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this * function returns the new delay. See {changeDefaultAdminDelay}. */ function defaultAdminDelay() external view returns (uint48); /** * @dev Returns a tuple of `newDelay` and an effect schedule. * * After the `schedule` passes, the `newDelay` will get into effect immediately for every * new {defaultAdmin} transfer started with {beginDefaultAdminTransfer}. * * A zero value only in `effectSchedule` indicates no pending delay change. * * NOTE: A zero value only for `newDelay` means that the next {defaultAdminDelay} * will be zero after the effect schedule. */ function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 effectSchedule); /** * @dev Starts a {defaultAdmin} transfer by setting a {pendingDefaultAdmin} scheduled for acceptance * after the current timestamp plus a {defaultAdminDelay}. * * Requirements: * * - Only can be called by the current {defaultAdmin}. * * Emits a DefaultAdminRoleChangeStarted event. */ function beginDefaultAdminTransfer(address newAdmin) external; /** * @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}. * * A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function. * * Requirements: * * - Only can be called by the current {defaultAdmin}. * * May emit a DefaultAdminTransferCanceled event. */ function cancelDefaultAdminTransfer() external; /** * @dev Completes a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}. * * After calling the function: * * - `DEFAULT_ADMIN_ROLE` should be granted to the caller. * - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder. * - {pendingDefaultAdmin} should be reset to zero values. * * Requirements: * * - Only can be called by the {pendingDefaultAdmin}'s `newAdmin`. * - The {pendingDefaultAdmin}'s `acceptSchedule` should've passed. */ function acceptDefaultAdminTransfer() external; /** * @dev Initiates a {defaultAdminDelay} update by setting a {pendingDefaultAdminDelay} scheduled for getting * into effect after the current timestamp plus a {defaultAdminDelay}. * * This function guarantees that any call to {beginDefaultAdminTransfer} done between the timestamp this * method is called and the {pendingDefaultAdminDelay} effect schedule will use the current {defaultAdminDelay} * set before calling. * * The {pendingDefaultAdminDelay}'s effect schedule is defined in a way that waiting until the schedule and then * calling {beginDefaultAdminTransfer} with the new delay will take at least the same as another {defaultAdmin} * complete transfer (including acceptance). * * The schedule is designed for two scenarios: * * - When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by * {defaultAdminDelayIncreaseWait}. * - When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`. * * A {pendingDefaultAdminDelay} that never got into effect will be canceled in favor of a new scheduled change. * * Requirements: * * - Only can be called by the current {defaultAdmin}. * * Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event. */ function changeDefaultAdminDelay(uint48 newDelay) external; /** * @dev Cancels a scheduled {defaultAdminDelay} change. * * Requirements: * * - Only can be called by the current {defaultAdmin}. * * May emit a DefaultAdminDelayChangeCanceled event. */ function rollbackDefaultAdminDelay() external; /** * @dev Maximum time in seconds for an increase to {defaultAdminDelay} (that is scheduled using {changeDefaultAdminDelay}) * to take effect. Default to 5 days. * * When the {defaultAdminDelay} is scheduled to be increased, it goes into effect after the new delay has passed with * the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds) * that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can * be overrode for a custom {defaultAdminDelay} increase scheduling. * * IMPORTANT: Make sure to add a reasonable amount of time while overriding this value, otherwise, * there's a risk of setting a high new delay that goes into effect almost immediately without the * possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds). */ function defaultAdminDelayIncreaseWait() external view returns (uint48); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5313.sol) pragma solidity ^0.8.0; /** * @dev Interface for the Light Contract Ownership Standard. * * A standardized minimal interface required to identify an account that controls a contract * * _Available since v4.9._ */ interface IERC5313 { /** * @dev Gets the address of the owner. */ function owner() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; interface IPausable { /// @notice This function pauses the contract /// @dev Sets the pause flag to true function emergencyPause() external; /// @notice This function unpauses the contract /// @dev Sets the pause flag to false function emergencyUnpause() external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
{ "remappings": [ "@chainlink/=lib/chainlink/", "@openzeppelin/=lib/openzeppelin-contracts/", "@solmate/=lib/solmate/src/", "chainlink/=lib/chainlink/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solmate/=lib/solmate/src/", "lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/", "lib/openzeppelin-contracts:ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/", "lib/openzeppelin-contracts:erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "lib/openzeppelin-contracts:forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/", "lib/openzeppelin-contracts:openzeppelin/=lib/openzeppelin-contracts/contracts/", "lib/solmate:ds-test/=lib/solmate/lib/ds-test/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"components":[{"components":[{"internalType":"contract LinkTokenInterface","name":"LINKAddress","type":"address"},{"internalType":"uint96","name":"initialMaxPoolSize","type":"uint96"},{"internalType":"uint96","name":"initialMaxPrincipalPerStaker","type":"uint96"},{"internalType":"uint96","name":"minPrincipalPerStaker","type":"uint96"},{"internalType":"uint32","name":"initialUnbondingPeriod","type":"uint32"},{"internalType":"uint32","name":"maxUnbondingPeriod","type":"uint32"},{"internalType":"uint32","name":"initialClaimPeriod","type":"uint32"},{"internalType":"uint32","name":"minClaimPeriod","type":"uint32"},{"internalType":"uint32","name":"maxClaimPeriod","type":"uint32"},{"internalType":"uint48","name":"adminRoleTransferDelay","type":"uint48"}],"internalType":"struct StakingPoolBase.ConstructorParamsBase","name":"baseParams","type":"tuple"},{"internalType":"contract OperatorStakingPool","name":"operatorStakingPool","type":"address"}],"internalType":"struct CommunityStakingPool.ConstructorParams","name":"params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessForbidden","type":"error"},{"inputs":[],"name":"ExceedsMaxPoolSize","type":"error"},{"inputs":[],"name":"ExceedsMaxStakeAmount","type":"error"},{"inputs":[],"name":"InsufficientStakeAmount","type":"error"},{"inputs":[],"name":"InvalidClaimPeriod","type":"error"},{"inputs":[{"internalType":"uint256","name":"minClaimPeriod","type":"uint256"},{"internalType":"uint256","name":"maxClaimPeriod","type":"uint256"}],"name":"InvalidClaimPeriodRange","type":"error"},{"inputs":[],"name":"InvalidData","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxStakeAmount","type":"uint256"}],"name":"InvalidMaxStakeAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxUnbondingPeriod","type":"uint256"}],"name":"InvalidMaxUnbondingPeriod","type":"error"},{"inputs":[],"name":"InvalidMigrationTarget","type":"error"},{"inputs":[],"name":"InvalidMinStakeAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxPoolSize","type":"uint256"}],"name":"InvalidPoolSize","type":"error"},{"inputs":[],"name":"InvalidUnbondingPeriod","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[],"name":"MerkleRootNotSet","type":"error"},{"inputs":[],"name":"MigrationProxyNotSet","type":"error"},{"inputs":[],"name":"PoolHasBeenClosed","type":"error"},{"inputs":[],"name":"PoolHasBeenOpened","type":"error"},{"inputs":[],"name":"PoolNotActive","type":"error"},{"inputs":[],"name":"PoolNotClosed","type":"error"},{"inputs":[],"name":"PoolNotOpen","type":"error"},{"inputs":[],"name":"RewardVaultHasNoRewards","type":"error"},{"inputs":[],"name":"RewardVaultNotActive","type":"error"},{"inputs":[],"name":"RewardVaultNotClosed","type":"error"},{"inputs":[],"name":"RewardVaultNotSet","type":"error"},{"inputs":[],"name":"SenderNotLinkToken","type":"error"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"StakeNotFound","type":"error"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"StakerNotInClaimPeriod","type":"error"},{"inputs":[{"internalType":"uint256","name":"unbondingPeriodEndsAt","type":"uint256"}],"name":"UnbondingOrClaimPeriodActive","type":"error"},{"inputs":[],"name":"UnstakeExceedsPrincipal","type":"error"},{"inputs":[],"name":"UnstakePrincipalBelowMinAmount","type":"error"},{"inputs":[],"name":"UnstakeZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldClaimPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newClaimPeriod","type":"uint256"}],"name":"ClaimPeriodSet","type":"event"},{"anonymous":false,"inputs":[],"name":"DefaultAdminDelayChangeCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint48","name":"newDelay","type":"uint48"},{"indexed":false,"internalType":"uint48","name":"effectSchedule","type":"uint48"}],"name":"DefaultAdminDelayChangeScheduled","type":"event"},{"anonymous":false,"inputs":[],"name":"DefaultAdminTransferCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"},{"indexed":false,"internalType":"uint48","name":"acceptSchedule","type":"uint48"}],"name":"DefaultAdminTransferScheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPrincipalPerStaker","type":"uint256"}],"name":"MaxPrincipalAmountIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"oldMerkleRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newMerkleRoot","type":"bytes32"}],"name":"MerkleRootChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldMigrationProxy","type":"address"},{"indexed":true,"internalType":"address","name":"newMigrationProxy","type":"address"}],"name":"MigrationProxySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldMigrationTarget","type":"address"},{"indexed":true,"internalType":"address","name":"newMigrationTarget","type":"address"}],"name":"MigrationTargetSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOperatorStakingPool","type":"address"},{"indexed":true,"internalType":"address","name":"newOperatorStakingPool","type":"address"}],"name":"OperatorStakingPoolChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[],"name":"PoolClosed","type":"event"},{"anonymous":false,"inputs":[],"name":"PoolOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPoolSize","type":"uint256"}],"name":"PoolSizeIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRewardVault","type":"address"},{"indexed":true,"internalType":"address","name":"newRewardVault","type":"address"}],"name":"RewardVaultSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStake","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalPrincipal","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"migrationTarget","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"migrationData","type":"bytes"}],"name":"StakerMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"}],"name":"UnbondingPeriodReset","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldUnbondingPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUnbondingPeriod","type":"uint256"}],"name":"UnbondingPeriodSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"}],"name":"UnbondingPeriodStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStake","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalPrincipal","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptDefaultAdminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"beginDefaultAdminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelDefaultAdminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"newDelay","type":"uint48"}],"name":"changeDefaultAdminDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"close","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultAdminDelay","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultAdminDelayIncreaseWait","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyUnpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getChainlinkToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getClaimPeriodEndsAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClaimPeriodLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxPoolSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxUnbondingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMigrationProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMigrationTarget","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardVault","outputs":[{"internalType":"contract IRewardVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakerLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getStakerPrincipal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getStakerPrincipalAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getStakerStakedAtTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getStakerStakedAtTimeAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalPrincipal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getUnbondingEndsAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnbondingParams","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"hasAccess","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"open","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingDefaultAdmin","outputs":[{"internalType":"address","name":"newAdmin","type":"address"},{"internalType":"uint48","name":"schedule","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingDefaultAdminDelay","outputs":[{"internalType":"uint48","name":"newDelay","type":"uint48"},{"internalType":"uint48","name":"schedule","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollbackDefaultAdminDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"claimPeriod","type":"uint256"}],"name":"setClaimPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newMerkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migrationProxy","type":"address"}],"name":"setMigrationProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMigrationTarget","type":"address"}],"name":"setMigrationTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract OperatorStakingPool","name":"newOperatorStakingPool","type":"address"}],"name":"setOperatorStakingPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxPoolSize","type":"uint256"},{"internalType":"uint256","name":"maxPrincipalPerStaker","type":"uint256"}],"name":"setPoolConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRewardVault","name":"newRewardVault","type":"address"}],"name":"setRewardVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newUnbondingPeriod","type":"uint256"}],"name":"setUnbondingPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"unbond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061038e5760003560e01c8063649a5ec7116101de578063ace192f51161010f578063d2c04f43116100ad578063e0d307e01161007c578063e0d307e01461086e578063e63ab1e914610881578063ec1fbf21146108a8578063fcfff16f146108f857600080fd5b8063d2c04f431461080b578063d547741f1461081e578063d602b9fd14610831578063dfa4c2611461083957600080fd5b8063cc8463c8116100e9578063cc8463c8146107ae578063cd0ef498146107b6578063cefc1429146107d5578063cf6eefb7146107dd57600080fd5b8063ace192f51461073b578063c231bace1461074e578063c4ef722a1461076157600080fd5b80638da5cb5b1161017c5780639d0a3864116101565780639d0a3864146106e6578063a1eda53c146106f9578063a217fddf14610720578063a4c0ed361461072857600080fd5b80638da5cb5b146106b857806391d14854146106c057806396cd37fe146106d357600080fd5b80638125dd10116101b85780638125dd101461067957806384ef8ffc1461068c578063885491af1461069d5780638932a90d146106a557600080fd5b8063649a5ec7146106425780636d5f3c73146106555780637cb647591461066657600080fd5b80632f2ff15d116102c35780634af9a030116102615780635c975abb116102305780635c975abb1461060b5780635df6a6bc146106165780635f0f4c831461061e578063634e93da1461062f57600080fd5b80634af9a030146105ca5780634c5b725f146105dd57806351858e27146105f057806358939184146105f857600080fd5b806347535d7b1161029d57806347535d7b1461059557806349590657146105a75780634a4e3bd5146105af5780634aba2ca9146105b757600080fd5b80632f2ff15d1461056757806336568abe1461057a57806343d726d61461058d57600080fd5b80631990e97911610330578063232390231161030a57806323239023146104c8578063248a9ca3146105045780632b2f6b5e146105285780632e17de781461055457600080fd5b80631990e979146104885780631ddb5552146104af57806322f3e2d4146104c057600080fd5b80630fbc8f5b1161036c5780630fbc8f5b146103e1578063114eaf55146103fc578063165d35e11461040f578063181f5a771461044957600080fd5b806301ffc9a714610393578063022d63fb146103bb5780630aa6220b146103d7575b600080fd5b6103a66103a13660046139d1565b610900565b60405190151581526020015b60405180910390f35b620697805b60405165ffffffffffff90911681526020016103b2565b6103df61092b565b005b6005546001600160601b03165b6040519081526020016103b2565b6103df61040a3660046139fb565b610941565b7f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca5b6040516001600160a01b0390911681526020016103b2565b604080518082018252601a81527f436f6d6d756e6974795374616b696e67506f6f6c20312e302e30000000000000602082015290516103b29190613a64565b6103ee7f6b8b15f1c11543d8280deaa7c24d12fffba6a357e4428e8c43e4234790186bff81565b6004546001600160a01b0316610431565b6103a661097a565b6103ee6104d6366004613a8c565b6001600160a01b0316600090815260086020526040902060010154600160801b90046001600160801b031690565b6103ee6105123660046139fb565b6000908152600160208190526040909120015490565b7f00000000000000000000000000000000000000000000000000000000004f1a0063ffffffff166103ee565b6103df6105623660046139fb565b610989565b6103df610575366004613aa9565b610c19565b6103df610588366004613aa9565b610c8f565b6103df610d79565b600a54600160a01b900460ff166103a6565b600c546103ee565b6103df610deb565b6103df6105c5366004613ad9565b610e1d565b6103df6105d8366004613a8c565b610e61565b6103ee6105eb366004613afb565b610f1c565b6103df610f91565b6103ee610606366004613a8c565b610fc3565b60005460ff166103a6565b6103df610ff3565b600a546001600160a01b0316610431565b6103df61063d366004613a8c565b611049565b6103df610650366004613b27565b61105d565b6009546001600160a01b0316610431565b6103df6106743660046139fb565b611071565b6103df610687366004613a8c565b61110f565b6003546001600160a01b0316610431565b6006546103ee565b6103df6106b3366004613b91565b61140f565b61043161167a565b6103a66106ce366004613aa9565b61168e565b6103ee6106e1366004613afb565b6116b9565b6103a66106f4366004613bd3565b61170a565b610701611751565b6040805165ffffffffffff9384168152929091166020830152016103b2565b6103ee600081565b6103df610736366004613c5b565b6117a5565b6103df610749366004613a8c565b611a9c565b6103df61075c366004613a8c565b611b3c565b6005546001600160601b037f0000000000000000000000000000000000000000000000000de0b6b3a7640000811691600160601b9004165b604080519283526020830191909152016103b2565b6103c0611ba3565b60055463ffffffff600160c01b8204811691600160e01b900416610799565b6103df611c02565b6107e5611c80565b604080516001600160a01b03909316835265ffffffffffff9091166020830152016103b2565b6103df6108193660046139fb565b611ca1565b6103df61082c366004613aa9565b611cd6565b6103df611d53565b6103ee610847366004613a8c565b6001600160a01b03166000908152600860205260409020600101546001600160801b031690565b6103ee61087c366004613a8c565b611d66565b6103ee7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000151808116907f0000000000000000000000000000000000000000000000000000000000278d0016610799565b6103df611da5565b60006001600160e01b03198216635260769b60e11b1480610925575061092582611fc3565b92915050565b600061093681611fe8565b61093e611ff2565b50565b600061094c81611fe8565b6007541561096d57604051637c773fd960e01b815260040160405180910390fd5b61097682611fff565b5050565b60006109846120e5565b905090565b806000036109aa5760405163fa840c8f60e01b815260040160405180910390fd5b3360009081526008602052604090206109c28161216e565b6109e657604051635626ffb560e01b81523360048201526024015b60405180910390fd5b60006109f182612196565b90506001600160701b03607082901c811690821681851115610a2657604051634d1a7f2b60e01b815260040160405180910390fd5b6000610a328684613ccd565b90508286108015610a6b57507f0000000000000000000000000000000000000000000000000de0b6b3a76400006001600160601b031681105b15610a895760405163e0f5d02f60e01b815260040160405180910390fd5b600a5460405163cf3bf2eb60e01b8152336004820152602481018590526044810184905260648101889052600160848201526001600160a01b039091169063cf3bf2eb9060a401600060405180830381600087803b158015610aea57600080fd5b505af1158015610afe573d6000803e3d6000fd5b505050508560056001016000016000828254610b1a9190613ccd565b90915550610b38905085828015610b3157426121df565b60006121df565b60405163a9059cbb60e01b8152336004820152602481018790527f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca6001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610ba5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc99190613ce0565b5060065460408051888152602081018490529081019190915233907f204fccf0d92ed8d48f204adb39b2e81e92bad0dedb93f5716ca9478cfb57de009060600160405180910390a2505050505050565b81610c855760405162461bcd60e51b815260206004820152603660248201527f416363657373436f6e74726f6c3a2063616e2774206469726563746c79206772604482015275616e742064656661756c742061646d696e20726f6c6560501b60648201526084016109dd565b6109768282612212565b81158015610caa57506003546001600160a01b038281169116145b15610d6f57600080610cba611c80565b90925090506001600160a01b038216158015610cdd575065ffffffffffff811615155b8015610cf057504265ffffffffffff8216105b610d5a5760405162461bcd60e51b815260206004820152603560248201527f416363657373436f6e74726f6c3a206f6e6c792063616e2072656e6f756e636560448201527420696e2074776f2064656c6179656420737465707360581b60648201526084016109dd565b50506002805465ffffffffffff60a01b191690555b6109768282612238565b6000610d8481611fe8565b600a54600160a01b900460ff16610dae5760405163050d584d60e21b815260040160405180910390fd5b600a805460ff60a01b19169055426007556040517fd9fd1a29efbd67e74bbcd110e7344e0a2fbc8efd8334b946c1b805670d8d08ea90600090a150565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610e1581611fe8565b61093e6122b2565b6000610e2881611fe8565b600a54600160a01b900460ff16610e525760405163050d584d60e21b815260040160405180910390fd5b610e5c8383612304565b505050565b6000610e6c81611fe8565b60075415610e8d57604051637c773fd960e01b815260040160405180910390fd5b6001600160a01b038216610eb45760405163f6b2911f60e01b815260040160405180910390fd5b6009546001600160a01b0383811691161461097657600980546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f05c7298d5a1cfa304dcb2b5dca121c2dcbcba489d28eff0474f99491dab8e95c90600090a3505050565b6000438214610f51576001600160a01b0383166000908152600860205260409020607090610f4a908461246f565b901c610f81565b6001600160a01b0383166000908152600860205260409020607090610f7590612196565b6001600160e01b0316901c5b6001600160701b03169392505050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610fbb81611fe8565b61093e612522565b6001600160a01b0381166000908152600860205260408120610fe490612196565b6001600160701b031692915050565b3360009081526008602052604081209061100c82612196565b90506001600160701b03607082901c16600081900361104057604051637256ef3960e11b81523360048201526024016109dd565b610e5c8361255f565b600061105481611fe8565b61097682612673565b600061106881611fe8565b610976826126e6565b7f6b8b15f1c11543d8280deaa7c24d12fffba6a357e4428e8c43e4234790186bff61109b81611fe8565b600754156110bc57604051637c773fd960e01b815260040160405180910390fd5b600c548281036110cb57505050565b600c83905560408051828152602081018590527f123d88ba82600dfc3f219f8885c691b0ff020caa535666874b3f5174973757fe91015b60405180910390a1505050565b600061111a81611fe8565b6007541561113b57604051637c773fd960e01b815260040160405180910390fd5b6001600160a01b0382166111625760405163f6b2911f60e01b815260040160405180910390fd5b600a546001600160a01b03908116908316810361117e57505050565b600a546001600160a01b03161580159061120a5750600a60009054906101000a90046001600160a01b03166001600160a01b03166347535d7b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120a9190613ce0565b1561122857604051630839ee2b60e01b815260040160405180910390fd5b600a546001600160a01b0316158015906113085750826001600160a01b03166347535d7b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561127b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129f9190613ce0565b15806113085750826001600160a01b031663b187bd266040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113089190613ce0565b1561132657604051633363bbbd60e21b815260040160405180910390fd5b600a546001600160a01b03161580159061139f5750826001600160a01b031663fcb6813e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611379573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139d9190613ce0565b155b156113bd576040516339936dcd60e11b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0385811691821790925560405190918316907f5da547b9d16fdf24d2effc5aab5525df02b543c8f72b9dec3867cc81aba3598290600090a3505050565b6007546000036114325760405163f78030f560e01b815260040160405180910390fd5b6004546001600160a01b031661145b576040516306cf420760e31b815260040160405180910390fd5b3360009081526008602052604081209061147482612196565b90506001600160701b03607082901c168160008290036114a957604051637256ef3960e11b81523360048201526024016109dd565b6000338288886040516020016114c29493929190613d02565b60408051808303601f1901815290829052600a5463cf3bf2eb60e01b83523360048401526001600160701b038087166024850181905290861660448501526064840152600060848401529092506001600160a01b03169063cf3bf2eb9060a401600060405180830381600087803b15801561153c57600080fd5b505af1158015611550573d6000803e3d6000fd5b50505050826001600160701b0316600560010160000160008282546115759190613ccd565b9091555061159090508560006001600160701b0385166121df565b60048054604051630200057560e51b81526001600160a01b037f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca811693634000aea0936115e4939216918891879101613d52565b6020604051808303816000875af1158015611603573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116279190613ce0565b506004546040516001600160a01b03909116907fd66969e43355e162ea901ee1cf101884497194ad4eea7cf7f32922cb33f5801d906116699086908590613d8e565b60405180910390a250505050505050565b60006109846003546001600160a01b031690565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60004382146116e9576001600160a01b03831660009081526008602052604090206116e4908361246f565b610f81565b6001600160a01b0383166000908152600860205260409020610f8190612196565b60006117498484848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061274f92505050565b949350505050565b600354600090600160d01b900465ffffffffffff16801515801561177d57504265ffffffffffff821610155b6117895760008061179d565b600354600160a01b900465ffffffffffff16815b915091509091565b336001600160a01b037f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca16146117ee576040516309ad2a8760e31b815260040160405180910390fd5b6009546001600160a01b031661181757604051631595876b60e01b815260040160405180910390fd5b600a54600160a01b900460ff166118415760405163050d584d60e21b815260040160405180910390fd5b600a60009054906101000a90046001600160a01b03166001600160a01b03166347535d7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b89190613ce0565b15806119365750600a60009054906101000a90046001600160a01b03166001600160a01b031663b187bd266040518163ffffffff1660e01b8152600401602060405180830381865afa158015611912573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119369190613ce0565b1561195457604051633363bbbd60e21b815260040160405180910390fd5b61195c6127b8565b8215611a96576009546000906001600160a01b03868116911614611980578461198a565b61198a83836127fe565b90506001600160a01b0381166119b35760405163f6b2911f60e01b815260040160405180910390fd5b6119bf8582858561282e565b6001600160a01b0381166000908152600860205260408120906119e182612196565b90506001600160701b03607082901c81169082166119ff8486612989565b600a5460405163cf3bf2eb60e01b81526001600160a01b038781166004830152602482018590526044820184905260006064830181905260848301529091169063cf3bf2eb9060a401600060405180830381600087803b158015611a6257600080fd5b505af1158015611a76573d6000803e3d6000fd5b50505050611a90858984611a8a9190613db0565b8a6129da565b50505050505b50505050565b6000611aa781611fe8565b6001600160a01b038216611ace5760405163f6b2911f60e01b815260040160405180910390fd5b600b546001600160a01b039081169083168103611aea57505050565b600b80546001600160a01b0319166001600160a01b0385811691821790925560405190918316907ffa5d2783351524c3e15773cb2a3f90d4cdf8cac06964200fd7d35e935a1e60cd90600090a3505050565b6000611b4781611fe8565b611b5082612b12565b600480546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f17ea51c1e1f33dc6d52b4d266abbfcc3324be3374a3756d110ef8226e0234d7e90600090a3505050565b600354600090600160d01b900465ffffffffffff168015158015611bce57504265ffffffffffff8216105b611be957600254600160d01b900465ffffffffffff16611bfc565b600354600160a01b900465ffffffffffff165b91505090565b6000611c0c611c80565b509050336001600160a01b03821614611c785760405162461bcd60e51b815260206004820152602860248201527f416363657373436f6e74726f6c3a2070656e64696e672061646d696e206d75736044820152671d081858d8d95c1d60c21b60648201526084016109dd565b61093e612bc8565b6002546001600160a01b03811691600160a01b90910465ffffffffffff1690565b6000611cac81611fe8565b60075415611ccd57604051637c773fd960e01b815260040160405180910390fd5b61097682612c93565b81611d495760405162461bcd60e51b815260206004820152603760248201527f416363657373436f6e74726f6c3a2063616e2774206469726563746c7920726560448201527f766f6b652064656661756c742061646d696e20726f6c6500000000000000000060648201526084016109dd565b6109768282612d97565b6000611d5e81611fe8565b61093e612dbd565b6001600160a01b0381166000908152600860205260408120607090611d8a90612196565b6001600160e01b0316901c6001600160701b03169050919050565b7f6b8b15f1c11543d8280deaa7c24d12fffba6a357e4428e8c43e4234790186bff611dcf81611fe8565b600a54600160a01b900460ff1615611dfa576040516303097b4b60e51b815260040160405180910390fd5b60075415611e1b57604051637c773fd960e01b815260040160405180910390fd5b600a546001600160a01b0316611e445760405163fcb260f760e01b815260040160405180910390fd5b600a60009054906101000a90046001600160a01b03166001600160a01b03166347535d7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebb9190613ce0565b1580611f395750600a60009054906101000a90046001600160a01b03166001600160a01b031663b187bd266040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f399190613ce0565b15611f5757604051633363bbbd60e21b815260040160405180910390fd5b611f5f612dc8565b611f7c576040516339936dcd60e11b815260040160405180910390fd5b611f84612e36565b600a805460ff60a01b1916600160a01b1790556040517fded6ebf04e261e1eb2f3e3b268a2e6aee5b478c15b341eba5cf18b9bc80c2e6390600090a150565b60006001600160e01b031982166318a4c3c360e11b1480610925575061092582612e56565b61093e8133612e8b565b611ffd600080612ee4565b565b80158061203157507f00000000000000000000000000000000000000000000000000000000004f1a0063ffffffff1681115b1561204f5760405163027a6b4360e61b815260040160405180910390fd5b600554600160c01b900463ffffffff168190036120695750565b600554600160c01b900463ffffffff1661208282612fa4565b6005805463ffffffff92909216600160c01b0263ffffffff60c01b1990921691909117905560408051828152602081018490527f8a64345dc20861a6d144acccb8559538642cccafb7485ad5f14b8c4739ba107b91015b60405180910390a15050565b600a54600090600160a01b900460ff1680156109845750600a54604051635350e73160e01b81523060048201526001600160a01b0390911690635350e73190602401602060405180830381865afa158015612144573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121689190613ce0565b15905090565b60075460009015158061218557506121858261300d565b80610925575060005460ff16610925565b805460009080156121d5576121be836121b0600184613ccd565b600091825260209091200190565b5464010000000090046001600160e01b03166121d8565b60005b9392505050565b61220b836dffffffffffffffffffffffffffff60701b607085901b166001600160701b0384161761305e565b5050505050565b6000828152600160208190526040909120015461222e81611fe8565b610e5c8383613094565b6001600160a01b03811633146122a85760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016109dd565b610976828261313e565b6122ba613179565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600582158061231c575080546001600160601b031683105b1561233d57604051630f9e1c3b60e11b8152600481018490526024016109dd565b81158061234957508282115b8061236457508054600160601b90046001600160601b031682105b156123855760405163bc91aa3360e01b8152600481018390526024016109dd565b80546001600160601b031683146123f35761239f836131c2565b81546bffffffffffffffffffffffff19166001600160601b03919091161781556040518381527f7f4f497e086b2eb55f8a9885ba00d33399bbe0ebcb92ea092834386435a1b9c09060200160405180910390a15b8054600160601b90046001600160601b03168214610e5c57612414826131c2565b81546001600160601b0391909116600160601b026bffffffffffffffffffffffff60601b199091161781556040518281527f25a396cea9ba6982315a3d3e139ba96cd1c22cbd4d13b3a34474be6a78d79cf490602001611102565b60004382106124c05760405162461bcd60e51b815260206004820181905260248201527f436865636b706f696e74733a20626c6f636b206e6f7420796574206d696e656460448201526064016109dd565b60006124cb83612fa4565b845490915060006124de8684838561322a565b9050801561250c576124f5866121b0600184613ccd565b5464010000000090046001600160e01b031661250f565b60005b6001600160e01b03169695505050505050565b61252a6127b8565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586122e73390565b60018101546001600160801b03161580159061258f57506001810154600160801b90046001600160801b03164211155b156125be57600181015460405163ede02c8360e01b81526001600160801b0390911660048201526024016109dd565b6005546125e1906125dc90600160c01b900463ffffffff1642613db0565b613288565b6001820180546fffffffffffffffffffffffffffffffff19166001600160801b0392909216918217905560055461262691600160e01b90910463ffffffff1690613dc3565b6001820180546001600160801b03928316600160801b02921691909117905560405133907f5b9cd1c6f24b416d2354b7b7ad07d92bc1c662a403180e84fac2782414a5f4ed90600090a250565b600061267d611ba3565b612686426132f1565b6126909190613dea565b905061269c8282613358565b60405165ffffffffffff821681526001600160a01b038316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed69060200160405180910390a25050565b60006126f1826133d7565b6126fa426132f1565b6127049190613dea565b90506127108282612ee4565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b91016120d9565b600c5460009061276157506001610925565b600c54604080516001600160a01b03861660208201526121d892859290910160408051601f19818403018152828252805160209182012090830152016040516020818303038152906040528051906020012061341f565b60005460ff1615611ffd5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109dd565b600081810361282057604051635cb045db60e01b815260040160405180910390fd5b600061174983850185613a8c565b6009546001600160a01b0385811691161480159061284d5750600c5415155b801561286b57506128698361286483850185613e1f565b61274f565b155b1561288957604051631decfebb60e31b815260040160405180910390fd5b600b546040516336b87bd760e11b81526001600160a01b03858116600483015290911690636d70f7ae90602401602060405180830381865afa1580156128d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f79190613ce0565b8061296b5750600b54604051637d3374e560e01b81526001600160a01b03858116600483015290911690637d3374e590602401602060405180830381865afa158015612947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296b9190613ce0565b15611a9657604051631decfebb60e31b815260040160405180910390fd5b60018201546001600160801b031615610976576000600183018190556040516001600160a01b038316917f2139bcf9aedec1324f4900a905dca2fa45768477dcef823731813cfb36d86fb891a25050565b6001600160a01b03831660009081526008602052604090206001600160601b037f0000000000000000000000000000000000000000000000000de0b6b3a764000016831015612a3c5760405163a8ded35f60e01b815260040160405180910390fd5b600554600160601b90046001600160601b0316831115612a6f5760405163ba1e17c160e01b815260040160405180910390fd5b600654600090612a80908490613db0565b6005549091506001600160601b0316811115612aaf5760405163d279763560e01b815260040160405180910390fd5b6006819055612abf8285426121df565b60408051848152602081018690529081018290526001600160a01b038616907fb4caaf29adda3eefee3ad552a8e85058589bf834c7466cae4ee58787f70589ed9060600160405180910390a25050505050565b60075415612b3357604051637c773fd960e01b815260040160405180910390fd5b612b3c81613435565b6040516301ffc9a760e01b8152635260769b60e11b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015612b87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bab9190613ce0565b61093e576040516306cf420760e31b815260040160405180910390fd5b600080612bd3611c80565b91509150612be88165ffffffffffff16151590565b8015612bfb57504265ffffffffffff8216105b612c585760405162461bcd60e51b815260206004820152602860248201527f416363657373436f6e74726f6c3a207472616e736665722064656c6179206e6f6044820152671d081c185cdcd95960c21b60648201526084016109dd565b612c746000612c6f6003546001600160a01b031690565b61313e565b612c7f600083613094565b5050600280546001600160d01b0319169055565b7f000000000000000000000000000000000000000000000000000000000001518063ffffffff16811080612cec57507f0000000000000000000000000000000000000000000000000000000000278d0063ffffffff1681115b15612d0a57604051636385801560e11b815260040160405180910390fd5b600554600160e01b900463ffffffff16819003612d245750565b600554600160e01b900463ffffffff16612d3d82612fa4565b6005805463ffffffff92909216600160e01b026001600160e01b0390921691909117905560408051828152602081018490527f9450c62cdfe8d5a3d6d6ef2b42b61c81ce45b294d6a56f3a8dbe883c64831eac91016120d9565b60008281526001602081905260409091200154612db381611fe8565b610e5c838361313e565b611ffd600080613358565b600a5460408051637e5b409f60e11b815290516000926001600160a01b03169163fcb6813e9160048083019260209291908290030181865afa158015612e12573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109849190613ce0565b600c54611ffd57604051634fc5147960e11b815260040160405180910390fd5b60006001600160e01b03198216637965db0b60e01b148061092557506301ffc9a760e01b6001600160e01b0319831614610925565b612e95828261168e565b61097657612ea28161349c565b612ead8360206134ae565b604051602001612ebe929190613edd565b60408051601f198184030181529082905262461bcd60e51b82526109dd91600401613a64565b600354600160d01b900465ffffffffffff168015612f67574265ffffffffffff82161015612f3d57600354600280546001600160d01b0316600160a01b90920465ffffffffffff16600160d01b02919091179055612f67565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec590600090a15b50600380546001600160a01b0316600160a01b65ffffffffffff948516026001600160d01b031617600160d01b9290931691909102919091179055565b600063ffffffff8211156130095760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b60648201526084016109dd565b5090565b60018101546000906001600160801b03161580613036575060018201546001600160801b031642105b1561304357506000919050565b5060010154600160801b90046001600160801b031642111590565b60008061307c8461306e43612fa4565b6130778661364a565b6136b3565b6001600160e01b0391821693501690505b9250929050565b816131345760006130ad6003546001600160a01b031690565b6001600160a01b0316146131185760405162461bcd60e51b815260206004820152602c60248201527f416363657373436f6e74726f6c3a2064656661756c742061646d696e20616c7260448201526b1958591e4819dc985b9d195960a21b60648201526084016109dd565b600380546001600160a01b0319166001600160a01b0383161790555b610976828261385a565b8115801561315957506003546001600160a01b038281169116145b1561316f57600380546001600160a01b03191690555b61097682826138c5565b60005460ff16611ffd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109dd565b60006001600160601b038211156130095760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b60648201526084016109dd565b60005b81831015613280576000613241848461392c565b60008781526020902090915063ffffffff86169082015463ffffffff16111561326c5780925061327a565b613277816001613db0565b93505b5061322d565b509392505050565b60006001600160801b038211156130095760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016109dd565b600065ffffffffffff8211156130095760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b60648201526084016109dd565b6000613362611c80565b6002805465ffffffffffff8616600160a01b026001600160d01b03199091166001600160a01b0388161717905591506133a490508165ffffffffffff16151590565b15610e5c576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a960510990600090a1505050565b6000806133e2611ba3565b90508065ffffffffffff168365ffffffffffff161161340a576134058382613f52565b6121d8565b6121d865ffffffffffff841662069780613947565b60008261342c858461395d565b14949350505050565b6001600160a01b038116158061345357506001600160a01b03811630145b8061346b57506004546001600160a01b038281169116145b8061347e57506001600160a01b0381163b155b1561093e576040516306cf420760e31b815260040160405180910390fd5b60606109256001600160a01b03831660145b606060006134bd836002613f71565b6134c8906002613db0565b67ffffffffffffffff8111156134e0576134e0613e09565b6040519080825280601f01601f19166020018201604052801561350a576020820181803683370190505b509050600360fc1b8160008151811061352557613525613f88565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061355457613554613f88565b60200101906001600160f81b031916908160001a9053506000613578846002613f71565b613583906001613db0565b90505b60018111156135fb576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106135b7576135b7613f88565b1a60f81b8282815181106135cd576135cd613f88565b60200101906001600160f81b031916908160001a90535060049490941c936135f481613f9e565b9050613586565b5083156121d85760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109dd565b60006001600160e01b038211156130095760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b60648201526084016109dd565b8254600090819080156137fc5760006136d1876121b0600185613ccd565b60408051808201909152905463ffffffff8082168084526401000000009092046001600160e01b0316602084015291925090871610156137535760405162461bcd60e51b815260206004820152601b60248201527f436865636b706f696e743a2064656372656173696e67206b657973000000000060448201526064016109dd565b805163ffffffff80881691160361379c5784613774886121b0600186613ccd565b80546001600160e01b03929092166401000000000263ffffffff9092169190911790556137ec565b6040805180820190915263ffffffff80881682526001600160e01b0380881660208085019182528b54600181018d5560008d81529190912094519151909216640100000000029216919091179101555b6020015192508391506138529050565b50506040805180820190915263ffffffff80851682526001600160e01b0380851660208085019182528854600181018a5560008a8152918220955192519093166401000000000291909316179201919091559050815b935093915050565b613864828261168e565b6109765760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6138cf828261168e565b156109765760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600061393b6002848418613fb5565b6121d890848416613db0565b600081831061395657816121d8565b5090919050565b600081815b84518110156132805761398e8286838151811061398157613981613f88565b60200260200101516139a2565b91508061399a81613fd7565b915050613962565b60008183106139be5760008281526020849052604090206121d8565b60008381526020839052604090206121d8565b6000602082840312156139e357600080fd5b81356001600160e01b0319811681146121d857600080fd5b600060208284031215613a0d57600080fd5b5035919050565b60005b83811015613a2f578181015183820152602001613a17565b50506000910152565b60008151808452613a50816020860160208601613a14565b601f01601f19169290920160200192915050565b6020815260006121d86020830184613a38565b6001600160a01b038116811461093e57600080fd5b600060208284031215613a9e57600080fd5b81356121d881613a77565b60008060408385031215613abc57600080fd5b823591506020830135613ace81613a77565b809150509250929050565b60008060408385031215613aec57600080fd5b50508035926020909101359150565b60008060408385031215613b0e57600080fd5b8235613b1981613a77565b946020939093013593505050565b600060208284031215613b3957600080fd5b813565ffffffffffff811681146121d857600080fd5b60008083601f840112613b6157600080fd5b50813567ffffffffffffffff811115613b7957600080fd5b60208301915083602082850101111561308d57600080fd5b60008060208385031215613ba457600080fd5b823567ffffffffffffffff811115613bbb57600080fd5b613bc785828601613b4f565b90969095509350505050565b600080600060408486031215613be857600080fd5b8335613bf381613a77565b9250602084013567ffffffffffffffff80821115613c1057600080fd5b818601915086601f830112613c2457600080fd5b813581811115613c3357600080fd5b8760208260051b8501011115613c4857600080fd5b6020830194508093505050509250925092565b60008060008060608587031215613c7157600080fd5b8435613c7c81613a77565b935060208501359250604085013567ffffffffffffffff811115613c9f57600080fd5b613cab87828801613b4f565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561092557610925613cb7565b600060208284031215613cf257600080fd5b815180151581146121d857600080fd5b6001600160a01b03851681526001600160701b03841660208201526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b6001600160a01b03841681526001600160701b0383166020820152606060408201819052600090613d8590830184613a38565b95945050505050565b6001600160701b03831681526040602082015260006117496040830184613a38565b8082018082111561092557610925613cb7565b6001600160801b03818116838216019080821115613de357613de3613cb7565b5092915050565b65ffffffffffff818116838216019080821115613de357613de3613cb7565b634e487b7160e01b600052604160045260246000fd5b60006020808385031215613e3257600080fd5b823567ffffffffffffffff80821115613e4a57600080fd5b818501915085601f830112613e5e57600080fd5b813581811115613e7057613e70613e09565b8060051b604051601f19603f83011681018181108582111715613e9557613e95613e09565b604052918252848201925083810185019188831115613eb357600080fd5b938501935b82851015613ed157843584529385019392850192613eb8565b98975050505050505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613f15816017850160208801613a14565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351613f46816028840160208801613a14565b01602801949350505050565b65ffffffffffff828116828216039080821115613de357613de3613cb7565b808202811582820484141761092557610925613cb7565b634e487b7160e01b600052603260045260246000fd5b600081613fad57613fad613cb7565b506000190190565b600082613fd257634e487b7160e01b600052601260045260246000fd5b500490565b600060018201613fe957613fe9613cb7565b506001019056fea2646970667358221220db267b767f6a035b0d60c92d01283a3f2e6cf4cb4bdf65cd73c7ff48245c3e0c64736f6c63430008130033
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.