-
Notifications
You must be signed in to change notification settings - Fork 7
Upgradeable staker (DO NOT MERGE) #154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
alexkeating
wants to merge
19
commits into
main
Choose a base branch
from
upgradeable-staker
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
6ec6f67
Initial upgradeable
alexkeating 327efc8
Changes
alexkeating f172dee
Fix compilation
alexkeating 20cf975
Fix tuple destructuring issues
alexkeating 579d557
Test gas
alexkeating 259848a
Constructors removed tests failing
alexkeating c5787f6
Passing tests except for bytecode comparison
alexkeating e940b6a
Proxy changes
alexkeating e7488ac
Proxy changes
alexkeating 0ee5b71
Final proxy changes
alexkeating a462379
Add Upgradeable suffix
alexkeating 366e7f3
Do not build harnesses
alexkeating dd11571
Cleanup
alexkeating 2932a1b
Remove comments
alexkeating 2fe8124
Some cleanup
alexkeating 97687dc
More cleanup
alexkeating 1596bcc
More cleanup
alexkeating 126860b
Lower coverage
alexkeating 768dc70
Update reward duration
alexkeating File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| { | ||
| "lib/forge-std": { | ||
| "rev": "1714bee72e286e73f76e320d110e0eaf5c4e649d" | ||
| }, | ||
| "lib/openzeppelin-contracts": { | ||
| "rev": "dbb6104ce834628e473d2173bbc9d47f81a9eec3" | ||
| }, | ||
| "lib/openzeppelin-contracts-upgradeable": { | ||
| "tag": { | ||
| "name": "v5.4.0", | ||
| "rev": "e725abddf1e01cf05ace496e950fc8e243cc7cab" | ||
| } | ||
| } | ||
| } |
Submodule openzeppelin-contracts-upgradeable
added at
e725ab
Large diffs are not rendered by default.
Oops, something went wrong.
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| pragma solidity ^0.8.23; | ||
|
|
||
| import {Staker} from "../Staker.sol"; | ||
| import {StakerUpgradeable} from "../StakerUpgradeable.sol"; | ||
|
|
||
| /// @title StakerCapDeposits | ||
| /// @author [ScopeLift](https://scopelift.co) | ||
|
|
@@ -11,24 +11,56 @@ import {Staker} from "../Staker.sol"; | |
| /// The contract allows the admin to configure a total stake cap that applies across all deposits. | ||
| /// Any attempt to stake tokens that would cause the total staked amount to exceed this cap will | ||
| /// revert. | ||
| abstract contract StakerCapDeposits is Staker { | ||
| abstract contract StakerCapDepositsUpgradeable is StakerUpgradeable { | ||
| /// @notice Emitted when the total stake cap is changed. | ||
| /// @param oldTotalStakeCap The previous maximum total stake allowed. | ||
| /// @param newTotalStakeCap The new maximum total stake allowed. | ||
| event TotalStakeCapSet(uint256 oldTotalStakeCap, uint256 newTotalStakeCap); | ||
|
|
||
| /// @notice Thrown when a staking operation would cause the total staked amount to exceed the | ||
| /// cap. | ||
| error StakerCapDeposits__CapExceeded(); | ||
| error StakerCapDepositsUpgradeable__CapExceeded(); | ||
|
|
||
| /// @notice The maximum total amount of tokens that can be staked across all deposits. | ||
| uint256 public totalStakeCap; | ||
| struct StakerCapDepositsStorage { | ||
| /// @notice The maximum total amount of tokens that can be staked across all deposits. | ||
| uint256 _totalStakeCap; | ||
| } | ||
|
|
||
| // keccak256(abi.encode(uint256(keccak256("storage.scopelift.StakerCapDeposits")) - 1)) | ||
| // &~bytes32(uint256(0xff)) | ||
| bytes32 private constant STAKER_CAP_DEPOSITS_STORAGE_LOCATION = | ||
| 0x965a89691c17af92914eadf0e487b628b4de164741f52e43f2d8c224cfe56100; | ||
|
|
||
| function _getStakerCapDepositsStorage() private pure returns (StakerCapDepositsStorage storage $) { | ||
| assembly { | ||
| $.slot := STAKER_CAP_DEPOSITS_STORAGE_LOCATION | ||
| } | ||
| } | ||
|
|
||
| /// @notice Initializes the `StakerCapDepositsUpgradeable` contract. | ||
| /// @param _initialTotalStakeCap The initial maximum total stake allowed. | ||
| constructor(uint256 _initialTotalStakeCap) { | ||
| function __StakerCapDepositsUpgradeable_init(uint256 _initialTotalStakeCap) | ||
| internal | ||
| onlyInitializing | ||
| { | ||
| __StakerCapDepositsUpgradeable_init_unchained(_initialTotalStakeCap); | ||
| } | ||
|
|
||
| /// @notice Initializes the `StakerCapDepositsUpgradeable` contract. | ||
| /// @param _initialTotalStakeCap The initial maximum total stake allowed. | ||
| function __StakerCapDepositsUpgradeable_init_unchained(uint256 _initialTotalStakeCap) | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kept these to match convention, but they seem to only be used as a passthrough |
||
| internal | ||
| onlyInitializing | ||
| { | ||
| _setTotalStakeCap(_initialTotalStakeCap); | ||
| } | ||
|
|
||
| /// @notice The maximum total amount of tokens that can be staked across all deposits. | ||
| function totalStakeCap() public view returns (uint256) { | ||
| StakerCapDepositsStorage storage $ = _getStakerCapDepositsStorage(); | ||
| return $._totalStakeCap; | ||
| } | ||
|
|
||
| /// @notice Sets a new maximum total stake cap. | ||
| /// @param _newTotalStakeCap The new maximum total stake allowed. | ||
| /// @dev Caller must be the current admin. | ||
|
|
@@ -40,31 +72,32 @@ abstract contract StakerCapDeposits is Staker { | |
| /// @notice Internal helper method which sets a new total stake cap. | ||
| /// @param _newTotalStakeCap The new maximum total stake allowed. | ||
| function _setTotalStakeCap(uint256 _newTotalStakeCap) internal { | ||
| emit TotalStakeCapSet(totalStakeCap, _newTotalStakeCap); | ||
| totalStakeCap = _newTotalStakeCap; | ||
| StakerCapDepositsStorage storage $ = _getStakerCapDepositsStorage(); | ||
| emit TotalStakeCapSet($._totalStakeCap, _newTotalStakeCap); | ||
| $._totalStakeCap = _newTotalStakeCap; | ||
| } | ||
|
|
||
| /// @inheritdoc Staker | ||
| /// @inheritdoc StakerUpgradeable | ||
| /// @dev Checks if the stake would exceed the total stake cap before proceeding. | ||
| function _stake(address _depositor, uint256 _amount, address _delegatee, address _claimer) | ||
| internal | ||
| virtual | ||
| override(Staker) | ||
| override(StakerUpgradeable) | ||
| returns (DepositIdentifier _depositId) | ||
| { | ||
| _revertIfCapExceeded(_amount); | ||
| return Staker._stake(_depositor, _amount, _delegatee, _claimer); | ||
| return StakerUpgradeable._stake(_depositor, _amount, _delegatee, _claimer); | ||
| } | ||
|
|
||
| /// @inheritdoc Staker | ||
| /// @inheritdoc StakerUpgradeable | ||
| /// @dev Checks if the additional stake would exceed the total stake cap before proceeding. | ||
| function _stakeMore(Deposit storage deposit, DepositIdentifier _depositId, uint256 _amount) | ||
| internal | ||
| virtual | ||
| override(Staker) | ||
| override(StakerUpgradeable) | ||
| { | ||
| _revertIfCapExceeded(_amount); | ||
| Staker._stakeMore(deposit, _depositId, _amount); | ||
| StakerUpgradeable._stakeMore(deposit, _depositId, _amount); | ||
| } | ||
|
|
||
| /// @notice Internal helper method which reverts if adding a given stake amount would exceed the | ||
|
|
@@ -73,6 +106,9 @@ abstract contract StakerCapDeposits is Staker { | |
| /// @dev Reverts with StakerCapDeposits__CapExceeded if the amount would cause total stake to | ||
| /// exceed the cap. | ||
| function _revertIfCapExceeded(uint256 _amount) internal view virtual { | ||
| if ((totalStaked + _amount) > totalStakeCap) revert StakerCapDeposits__CapExceeded(); | ||
| StakerCapDepositsStorage storage $ = _getStakerCapDepositsStorage(); | ||
| if ((totalStaked() + _amount) > $._totalStakeCap) { | ||
| revert StakerCapDepositsUpgradeable__CapExceeded(); | ||
| } | ||
| } | ||
| } | ||
This file was deleted.
Oops, something went wrong.
93 changes: 93 additions & 0 deletions
93
src/extensions/StakerDelegateSurrogateVotesUpgradeable.sol
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| pragma solidity ^0.8.23; | ||
|
|
||
| import {DelegationSurrogate} from "../DelegationSurrogate.sol"; | ||
| import {DelegationSurrogateVotes} from "../DelegationSurrogateVotes.sol"; | ||
| import {StakerUpgradeable} from "../StakerUpgradeable.sol"; | ||
| import {IERC20Delegates} from "../interfaces/IERC20Delegates.sol"; | ||
|
|
||
| /// @title StakerDelegateSurrogateVotes | ||
| /// @author [ScopeLift](https://scopelift.co) | ||
| /// @notice This contract extension adds delegation surrogates to the Staker base | ||
| /// contract, allowing staked tokens to be delegated to a specific delegate. | ||
| abstract contract StakerDelegateSurrogateVotesUpgradeable is StakerUpgradeable { | ||
| /// @notice Emitted when a surrogate contract is deployed. | ||
| event SurrogateDeployed(address indexed delegatee, address indexed surrogate); | ||
|
|
||
| /// @notice Thrown if an inheritor misconfigures the staking token on deployment. | ||
| error StakerDelegateSurrogateVotesUpgradeable__UnauthorizedToken(); | ||
|
|
||
| struct StakerDelegateSurrogateVotesStorage { | ||
| /// @notice Maps the account of each governance delegate with the surrogate contract which holds | ||
| /// the staked tokens from deposits which assign voting weight to said delegate. | ||
| mapping(address delegatee => DelegationSurrogate surrogate) _storedSurrogates; | ||
| } | ||
|
|
||
| // keccak256(abi.encode(uint256(keccak256("storage.scopelift.StakerDelegateSurrogateVotes")) - 1)) | ||
| // &~bytes32(uint256(0xff)) | ||
| bytes32 private constant STAKER_DELEGATE_SURROGATE_STORAGE_LOCATION = | ||
| 0x010103b2a019a28f51fa63a98fe162dac866120b721518e29f318125463ff100; | ||
|
|
||
| function _getStakerDelegateSurrogateStorage() | ||
| private | ||
| pure | ||
| returns (StakerDelegateSurrogateVotesStorage storage $) | ||
| { | ||
| assembly { | ||
| $.slot := STAKER_DELEGATE_SURROGATE_STORAGE_LOCATION | ||
| } | ||
| } | ||
|
|
||
| /// @notice Initializes the `StakerDelegateSurrogateVotesUpgradeable` contract. | ||
| /// @param _votingToken The token that is used for voting, which must be the same as the parent | ||
| /// Staker's STAKE_TOKEN. | ||
| function __StakerDelegateSurrogateVotesUpgradeable_init(IERC20Delegates _votingToken) | ||
| internal | ||
| onlyInitializing | ||
| { | ||
| __StakerDelegateSurrogateVotesUpgradeable_init_unchained(_votingToken); | ||
| } | ||
|
|
||
| /// @notice Initializes the `StakerDelegateSurrogateVotesUpgradeable` contract. | ||
| /// @param _votingToken The token that is used for voting, which must be the same as the parent | ||
| /// Staker's STAKE_TOKEN. | ||
| function __StakerDelegateSurrogateVotesUpgradeable_init_unchained(IERC20Delegates _votingToken) | ||
| internal | ||
| onlyInitializing | ||
| { | ||
| if (address(STAKE_TOKEN()) != address(_votingToken)) { | ||
| revert StakerDelegateSurrogateVotesUpgradeable__UnauthorizedToken(); | ||
| } | ||
| } | ||
|
|
||
| /// @inheritdoc StakerUpgradeable | ||
| function surrogates(address _delegatee) public view override returns (DelegationSurrogate) { | ||
| StakerDelegateSurrogateVotesStorage storage $ = _getStakerDelegateSurrogateStorage(); | ||
| return $._storedSurrogates[_delegatee]; | ||
| } | ||
|
|
||
| /// @notice Maps the account of each governance delegate with the surrogate contract. | ||
| /// @param _delegatee The address of the delegatee. | ||
| /// @return The surrogate contract address for the given delegatee. | ||
| function storedSurrogates(address _delegatee) public view returns (DelegationSurrogate) { | ||
| StakerDelegateSurrogateVotesStorage storage $ = _getStakerDelegateSurrogateStorage(); | ||
| return $._storedSurrogates[_delegatee]; | ||
| } | ||
|
|
||
| /// @inheritdoc StakerUpgradeable | ||
| function _fetchOrDeploySurrogate(address _delegatee) | ||
| internal | ||
| virtual | ||
| override | ||
| returns (DelegationSurrogate _surrogate) | ||
| { | ||
| StakerDelegateSurrogateVotesStorage storage $ = _getStakerDelegateSurrogateStorage(); | ||
| _surrogate = $._storedSurrogates[_delegatee]; | ||
|
|
||
| if (address(_surrogate) == address(0)) { | ||
| _surrogate = new DelegationSurrogateVotes(IERC20Delegates(address(STAKE_TOKEN())), _delegatee); | ||
| $._storedSurrogates[_delegatee] = _surrogate; | ||
| emit SurrogateDeployed(_delegatee, address(_surrogate)); | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.