Created
March 21, 2021 12:20
-
-
Save amirhabibzadeh/52c73b2b091fd5fc7893a10458baeb03 to your computer and use it in GitHub Desktop.
StakeManager Flatten version by truffle-flattener
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // File: @openzeppelin/contracts/math/SafeMath.sol | |
| // SPDX-License-Identifier: MIT | |
| pragma solidity ^0.6.0; | |
| /** | |
| * @dev Wrappers over Solidity's arithmetic operations with added overflow | |
| * checks. | |
| * | |
| * Arithmetic operations in Solidity wrap on overflow. This can easily result | |
| * in bugs, because programmers usually assume that an overflow raises an | |
| * error, which is the standard behavior in high level programming languages. | |
| * `SafeMath` restores this intuition by reverting the transaction when 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. | |
| */ | |
| library SafeMath { | |
| /** | |
| * @dev Returns the addition of two unsigned integers, reverting on | |
| * overflow. | |
| * | |
| * Counterpart to Solidity's `+` operator. | |
| * | |
| * Requirements: | |
| * | |
| * - Addition cannot overflow. | |
| */ | |
| function add(uint256 a, uint256 b) internal pure returns (uint256) { | |
| uint256 c = a + b; | |
| require(c >= a, "SafeMath: addition overflow"); | |
| return c; | |
| } | |
| /** | |
| * @dev Returns the subtraction of two unsigned integers, reverting on | |
| * overflow (when the result is negative). | |
| * | |
| * Counterpart to Solidity's `-` operator. | |
| * | |
| * Requirements: | |
| * | |
| * - Subtraction cannot overflow. | |
| */ | |
| function sub(uint256 a, uint256 b) internal pure returns (uint256) { | |
| return sub(a, b, "SafeMath: subtraction overflow"); | |
| } | |
| /** | |
| * @dev Returns the subtraction of two unsigned integers, reverting with custom message on | |
| * overflow (when the result is negative). | |
| * | |
| * Counterpart to Solidity's `-` operator. | |
| * | |
| * Requirements: | |
| * | |
| * - Subtraction cannot overflow. | |
| */ | |
| function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { | |
| require(b <= a, errorMessage); | |
| uint256 c = a - b; | |
| return c; | |
| } | |
| /** | |
| * @dev Returns the multiplication of two unsigned integers, reverting on | |
| * overflow. | |
| * | |
| * Counterpart to Solidity's `*` operator. | |
| * | |
| * Requirements: | |
| * | |
| * - Multiplication cannot overflow. | |
| */ | |
| function mul(uint256 a, uint256 b) internal pure returns (uint256) { | |
| // Gas optimization: this is cheaper than requiring 'a' not being zero, but the | |
| // benefit is lost if 'b' is also tested. | |
| // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 | |
| if (a == 0) { | |
| return 0; | |
| } | |
| uint256 c = a * b; | |
| require(c / a == b, "SafeMath: multiplication overflow"); | |
| return c; | |
| } | |
| /** | |
| * @dev Returns the integer division of two unsigned integers. Reverts on | |
| * division by zero. The result is rounded towards zero. | |
| * | |
| * Counterpart to Solidity's `/` operator. Note: this function uses a | |
| * `revert` opcode (which leaves remaining gas untouched) while Solidity | |
| * uses an invalid opcode to revert (consuming all remaining gas). | |
| * | |
| * Requirements: | |
| * | |
| * - The divisor cannot be zero. | |
| */ | |
| function div(uint256 a, uint256 b) internal pure returns (uint256) { | |
| return div(a, b, "SafeMath: division by zero"); | |
| } | |
| /** | |
| * @dev Returns the integer division of two unsigned integers. Reverts with custom message on | |
| * division by zero. The result is rounded towards zero. | |
| * | |
| * Counterpart to Solidity's `/` operator. Note: this function uses a | |
| * `revert` opcode (which leaves remaining gas untouched) while Solidity | |
| * uses an invalid opcode to revert (consuming all remaining gas). | |
| * | |
| * Requirements: | |
| * | |
| * - The divisor cannot be zero. | |
| */ | |
| function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { | |
| require(b > 0, errorMessage); | |
| uint256 c = a / b; | |
| // assert(a == b * c + a % b); // There is no case in which this doesn't hold | |
| return c; | |
| } | |
| /** | |
| * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), | |
| * Reverts when dividing by zero. | |
| * | |
| * Counterpart to Solidity's `%` operator. This function uses a `revert` | |
| * opcode (which leaves remaining gas untouched) while Solidity uses an | |
| * invalid opcode to revert (consuming all remaining gas). | |
| * | |
| * Requirements: | |
| * | |
| * - The divisor cannot be zero. | |
| */ | |
| function mod(uint256 a, uint256 b) internal pure returns (uint256) { | |
| return mod(a, b, "SafeMath: modulo by zero"); | |
| } | |
| /** | |
| * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), | |
| * Reverts with custom message when dividing by zero. | |
| * | |
| * Counterpart to Solidity's `%` operator. This function uses a `revert` | |
| * opcode (which leaves remaining gas untouched) while Solidity uses an | |
| * invalid opcode to revert (consuming all remaining gas). | |
| * | |
| * Requirements: | |
| * | |
| * - The divisor cannot be zero. | |
| */ | |
| function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { | |
| require(b != 0, errorMessage); | |
| return a % b; | |
| } | |
| } | |
| // File: contracts/interfaces/IStakeManager.sol | |
| pragma solidity ^0.6.2; | |
| pragma experimental ABIEncoderV2; | |
| interface IStakeManager { | |
| /// Emitted when a stake or unstakeDelay are initialized or increased | |
| event StakeAdded( | |
| address indexed relayManager, | |
| address indexed owner, | |
| uint256 stake, | |
| uint256 unstakeDelay | |
| ); | |
| /// Emitted once a stake is scheduled for withdrawal | |
| event StakeUnlocked( | |
| address indexed relayManager, | |
| address indexed owner, | |
| uint256 withdrawBlock | |
| ); | |
| /// Emitted when owner withdraws relayManager funds | |
| event StakeWithdrawn( | |
| address indexed relayManager, | |
| address indexed owner, | |
| uint256 amount | |
| ); | |
| /// Emitted when an authorized Relay Hub penalizes a relayManager | |
| event StakePenalized( | |
| address indexed relayManager, | |
| address indexed beneficiary, | |
| uint256 reward | |
| ); | |
| event HubAuthorized( | |
| address indexed relayManager, | |
| address indexed relayHub | |
| ); | |
| event HubUnauthorized( | |
| address indexed relayManager, | |
| address indexed relayHub, | |
| uint256 removalBlock | |
| ); | |
| /// @param stake - amount of ether staked for this relay | |
| /// @param unstakeDelay - number of blocks to elapse before the owner can retrieve the stake after calling 'unlock' | |
| /// @param withdrawBlock - first block number 'withdraw' will be callable, or zero if the unlock has not been called | |
| /// @param owner - address that receives revenue and manages relayManager's stake | |
| struct StakeInfo { | |
| uint256 stake; | |
| uint256 unstakeDelay; | |
| uint256 withdrawBlock; | |
| address payable owner; | |
| } | |
| struct RelayHubInfo { | |
| uint256 removalBlock; | |
| } | |
| /// Put a stake for a relayManager and set its unstake delay. | |
| /// If the entry does not exist, it is created, and the caller of this function becomes its owner. | |
| /// If the entry already exists, only the owner can call this function. | |
| /// @param relayManager - address that represents a stake entry and controls relay registrations on relay hubs | |
| /// @param unstakeDelay - number of blocks to elapse before the owner can retrieve the stake after calling 'unlock' | |
| function stakeForAddress(address relayManager, uint256 unstakeDelay) external payable; | |
| function unlockStake(address relayManager) external; | |
| function withdrawStake(address relayManager) external; | |
| function authorizeHubByOwner(address relayManager, address relayHub) external; | |
| function authorizeHubByManager(address relayHub) external; | |
| function unauthorizeHubByOwner(address relayManager, address relayHub) external; | |
| function unauthorizeHubByManager(address relayHub) external; | |
| function isRelayManagerStaked(address relayManager, address relayHub, uint256 minAmount, uint256 minUnstakeDelay) | |
| external | |
| view | |
| returns (bool); | |
| /// Slash the stake of the relay relayManager. In order to prevent stake kidnapping, burns half of stake on the way. | |
| /// @param relayManager - entry to penalize | |
| /// @param beneficiary - address that receives half of the penalty amount | |
| /// @param amount - amount to withdraw from stake | |
| function penalizeRelayManager(address relayManager, address payable beneficiary, uint256 amount) external; | |
| function getStakeInfo(address relayManager) external view returns (StakeInfo memory stakeInfo); | |
| function versionSM() external view returns (string memory); | |
| } | |
| // File: contracts/StakeManager.sol | |
| pragma solidity ^0.6.2; | |
| pragma experimental ABIEncoderV2; | |
| contract StakeManager is IStakeManager { | |
| using SafeMath for uint256; | |
| string public override versionSM = "2.0.0+opengsn.stakemanager.istakemanager"; | |
| /// maps relay managers to their stakes | |
| mapping(address => StakeInfo) public stakes; | |
| function getStakeInfo(address relayManager) external override view returns (StakeInfo memory stakeInfo) { | |
| return stakes[relayManager]; | |
| } | |
| /// maps relay managers to a map of addressed of their authorized hubs to the information on that hub | |
| mapping(address => mapping(address => RelayHubInfo)) public authorizedHubs; | |
| /// Put a stake for a relayManager and set its unstake delay. | |
| /// If the entry does not exist, it is created, and the caller of this function becomes its owner. | |
| /// If the entry already exists, only the owner can call this function. | |
| /// @param relayManager - address that represents a stake entry and controls relay registrations on relay hubs | |
| /// @param unstakeDelay - number of blocks to elapse before the owner can retrieve the stake after calling 'unlock' | |
| function stakeForAddress(address relayManager, uint256 unstakeDelay) external override payable { | |
| require(stakes[relayManager].owner == address(0) || stakes[relayManager].owner == msg.sender, "not owner"); | |
| require(unstakeDelay >= stakes[relayManager].unstakeDelay, "unstakeDelay cannot be decreased"); | |
| require(msg.sender != relayManager, "relayManager cannot stake for itself"); | |
| require(stakes[msg.sender].owner == address(0), "sender is a relayManager itself"); | |
| stakes[relayManager].owner = msg.sender; | |
| stakes[relayManager].stake += msg.value; | |
| stakes[relayManager].unstakeDelay = unstakeDelay; | |
| emit StakeAdded(relayManager, stakes[relayManager].owner, stakes[relayManager].stake, stakes[relayManager].unstakeDelay); | |
| } | |
| function unlockStake(address relayManager) external override { | |
| StakeInfo storage info = stakes[relayManager]; | |
| require(info.owner == msg.sender, "not owner"); | |
| require(info.withdrawBlock == 0, "already pending"); | |
| info.withdrawBlock = block.number.add(info.unstakeDelay); | |
| emit StakeUnlocked(relayManager, msg.sender, info.withdrawBlock); | |
| } | |
| function withdrawStake(address relayManager) external override { | |
| StakeInfo storage info = stakes[relayManager]; | |
| require(info.owner == msg.sender, "not owner"); | |
| require(info.withdrawBlock > 0, "Withdrawal is not scheduled"); | |
| require(info.withdrawBlock <= block.number, "Withdrawal is not due"); | |
| uint256 amount = info.stake; | |
| delete stakes[relayManager]; | |
| msg.sender.transfer(amount); | |
| emit StakeWithdrawn(relayManager, msg.sender, amount); | |
| } | |
| modifier ownerOnly (address relayManager) { | |
| StakeInfo storage info = stakes[relayManager]; | |
| require(info.owner == msg.sender, "not owner"); | |
| _; | |
| } | |
| modifier managerOnly () { | |
| StakeInfo storage info = stakes[msg.sender]; | |
| require(info.owner != address(0), "not manager"); | |
| _; | |
| } | |
| function authorizeHubByOwner(address relayManager, address relayHub) external ownerOnly(relayManager) override { | |
| _authorizeHub(relayManager, relayHub); | |
| } | |
| function authorizeHubByManager(address relayHub) external managerOnly override { | |
| _authorizeHub(msg.sender, relayHub); | |
| } | |
| function _authorizeHub(address relayManager, address relayHub) internal { | |
| authorizedHubs[relayManager][relayHub].removalBlock = uint(-1); | |
| emit HubAuthorized(relayManager, relayHub); | |
| } | |
| function unauthorizeHubByOwner(address relayManager, address relayHub) external override ownerOnly(relayManager) { | |
| _unauthorizeHub(relayManager, relayHub); | |
| } | |
| function unauthorizeHubByManager(address relayHub) external override managerOnly { | |
| _unauthorizeHub(msg.sender, relayHub); | |
| } | |
| function _unauthorizeHub(address relayManager, address relayHub) internal { | |
| RelayHubInfo storage hubInfo = authorizedHubs[relayManager][relayHub]; | |
| require(hubInfo.removalBlock == uint(-1), "hub not authorized"); | |
| uint256 removalBlock = block.number.add(stakes[relayManager].unstakeDelay); | |
| hubInfo.removalBlock = removalBlock; | |
| emit HubUnauthorized(relayManager, relayHub, removalBlock); | |
| } | |
| function isRelayManagerStaked(address relayManager, address relayHub, uint256 minAmount, uint256 minUnstakeDelay) | |
| external | |
| override | |
| view | |
| returns (bool) { | |
| StakeInfo storage info = stakes[relayManager]; | |
| bool isAmountSufficient = info.stake >= minAmount; | |
| bool isDelaySufficient = info.unstakeDelay >= minUnstakeDelay; | |
| bool isStakeLocked = info.withdrawBlock == 0; | |
| bool isHubAuthorized = authorizedHubs[relayManager][relayHub].removalBlock == uint(-1); | |
| return | |
| isAmountSufficient && | |
| isDelaySufficient && | |
| isStakeLocked && | |
| isHubAuthorized; | |
| } | |
| /// Slash the stake of the relay relayManager. In order to prevent stake kidnapping, burns half of stake on the way. | |
| /// @param relayManager - entry to penalize | |
| /// @param beneficiary - address that receives half of the penalty amount | |
| /// @param amount - amount to withdraw from stake | |
| function penalizeRelayManager(address relayManager, address payable beneficiary, uint256 amount) external override { | |
| uint256 removalBlock = authorizedHubs[relayManager][msg.sender].removalBlock; | |
| require(removalBlock != 0, "hub not authorized"); | |
| require(removalBlock > block.number, "hub authorization expired"); | |
| // Half of the stake will be burned (sent to address 0) | |
| require(stakes[relayManager].stake >= amount, "penalty exceeds stake"); | |
| stakes[relayManager].stake = SafeMath.sub(stakes[relayManager].stake, amount); | |
| uint256 toBurn = SafeMath.div(amount, 2); | |
| uint256 reward = SafeMath.sub(amount, toBurn); | |
| // Ether is burned and transferred | |
| address(0).transfer(toBurn); | |
| beneficiary.transfer(reward); | |
| emit StakePenalized(relayManager, beneficiary, reward); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment