-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add `SnapshotStakingPool` add `SignedSnapshotStakingPool` --------- Co-authored-by: christn <[email protected]>
- Loading branch information
Showing
10 changed files
with
1,330 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,7 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.10; | ||
|
||
interface IBaseManagerV2 { | ||
function addExtension(address _newExtension) external; | ||
function isExtension(address _extension) external view returns (bool); | ||
} |
This file contains 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,11 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.10; | ||
|
||
interface IPrtFeeSplitExtension { | ||
function accrueFeesAndDistribute() external; | ||
function isAnyoneAllowedToAccrue() external view returns (bool); | ||
function prtStakingPool() external view returns (address); | ||
function updateAnyoneAccrue(bool _anyoneAccrue) external; | ||
function updateFeeRecipient(address _feeRecipient) external; | ||
function updatePrtStakingPool(address _prtStakingPool) external; | ||
} |
This file contains 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 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.10; | ||
|
||
interface IStreamingFeeModule { | ||
struct FeeState { | ||
address feeRecipient; | ||
uint256 maxStreamingFeePercentage; | ||
uint256 streamingFeePercentage; | ||
uint256 lastStreamingFeeTimestamp; | ||
} | ||
|
||
function feeStates(address _setToken) external view returns (FeeState memory); | ||
function getFee(address _setToken) external view returns (uint256); | ||
} |
This file contains 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,32 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import {ISnapshotStakingPool} from "./ISnapshotStakingPool.sol"; | ||
|
||
interface ISignedSnapshotStakingPool is ISnapshotStakingPool { | ||
|
||
/// @notice Message to sign when staking | ||
function message() external view returns (string memory); | ||
|
||
/// @notice Mapping of approved stakers | ||
function isApprovedStaker(address) external view returns (bool); | ||
|
||
/// @notice Stake `amount` of stakeToken from `msg.sender` and mint staked tokens. | ||
/// @param amount The amount of stakeToken to stake | ||
/// @dev Must be an approved staker | ||
function stake(uint256 amount) external; | ||
|
||
/// @notice Stake `amount` of stakeToken from `msg.sender` and mint staked tokens. | ||
/// @param amount The amount of stakeToken to stake | ||
/// @param signature The signature of the message | ||
/// @dev Approves the staker if not already approved | ||
function stake(uint256 amount, bytes calldata signature) external; | ||
|
||
/// @notice Approve the signer of the message as an approved staker | ||
/// @param signature The signature of the message | ||
function approveStaker(bytes calldata signature) external; | ||
|
||
/// @notice Get the hashed digest of the message to be signed for staking | ||
/// @return The hashed bytes to be signed | ||
function getStakeSignatureDigest() external view returns (bytes32); | ||
} |
This file contains 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,103 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
|
||
interface ISnapshotStakingPool is IERC20 { | ||
|
||
/// @notice Token to be distributed as rewards | ||
function rewardToken() external view returns (IERC20); | ||
|
||
/// @notice Token to be staked | ||
function stakeToken() external view returns (IERC20); | ||
|
||
/// @notice Distributor of rewards | ||
function distributor() external view returns (address); | ||
|
||
/// @notice Snapshot delay | ||
function snapshotDelay() external view returns (uint256); | ||
|
||
/// @notice Last snapshot time | ||
function lastSnapshotTime() external view returns (uint256); | ||
|
||
/// @notice Next snapshot id for `account` to claim | ||
function nextClaimId(address account) external view returns (uint256); | ||
|
||
/// @notice Reward snapshot at `snapshotId` | ||
function rewardSnapshots(uint256) external view returns (uint256); | ||
|
||
/// @notice Get the reward snapshots | ||
function getRewardSnapshots() external view returns (uint256[] memory); | ||
|
||
/// @notice Stake `amount` of stakeToken from `msg.sender` and mint staked tokens. | ||
/// @param amount The amount of stakeToken to stake | ||
function stake(uint256 amount) external; | ||
|
||
/// @notice Unstake `amount` of stakeToken by `msg.sender`. | ||
/// @param amount The amount of stakeToken to unstake | ||
function unstake(uint256 amount) external; | ||
|
||
/// @notice ONLY DISTRIBUTOR: Accrue rewardToken and update snapshot. | ||
/// @param amount The amount of rewardToken to accrue | ||
function accrue(uint256 amount) external; | ||
|
||
/// @notice Claim the staking rewards from pending snapshots for `msg.sender`. | ||
function claim() external; | ||
|
||
/// @notice Claim partial staking rewards from pending snapshots for `msg.sender` from `_startClaimId` to `_endClaimId`. | ||
/// @param startSnapshotId The snapshot id to start the partial claim | ||
/// @param endSnapshotId The snapshot id to end the partial claim | ||
function claimPartial(uint256 startSnapshotId, uint256 endSnapshotId) external; | ||
|
||
/* ========== Admin Functions ========== */ | ||
|
||
/// @notice ONLY OWNER: Update the distributor address. | ||
/// @param newDistributor The new distributor address | ||
function setDistributor(address newDistributor) external; | ||
|
||
/// @notice ONLY OWNER: Update the snapshot delay. Can set to 0 to disable snapshot delay. | ||
/// @param newSnapshotDelay The new snapshot delay | ||
function setSnapshotDelay(uint256 newSnapshotDelay) external; | ||
|
||
/* ========== View Functions ========== */ | ||
|
||
/// @notice Get the current snapshot id. | ||
/// @return The current snapshot id | ||
function getCurrentSnapshotId() external view returns (uint256); | ||
|
||
/// @notice Retrieves the rewards pending to be claimed by `account`. | ||
/// @param account The account to retrieve pending rewards for | ||
/// @return The rewards pending to be claimed by `account` | ||
function getPendingRewards(address account) external view returns (uint256); | ||
|
||
/// @notice Retrives the rewards of `account` in the range of `startSnapshotId` to `endSnapshotId`. | ||
/// @param account The account to retrieve rewards for | ||
/// @param startSnapshotId The start snapshot id | ||
/// @param endSnapshotId The end snapshot id | ||
/// @return The rewards of `account` in the range of `startSnapshotId` to `endSnapshotId` | ||
function rewardOfInRange(address account, uint256 startSnapshotId, uint256 endSnapshotId) external view returns (uint256); | ||
|
||
/// @notice Retrieves the rewards of `account` at the `snapshotId`. | ||
/// @param account The account to retrieve rewards for | ||
/// @param snapshotId The snapshot id | ||
/// @return The rewards of `account` at the `snapshotId` | ||
function rewardOfAt(address account, uint256 snapshotId) external view returns (uint256); | ||
|
||
/// @notice Retrieves the total pool reward at the time `snapshotId`. | ||
/// @param snapshotId The snapshot id | ||
/// @return The total pool reward at the time `snapshotId` | ||
function rewardAt(uint256 snapshotId) external view returns (uint256); | ||
|
||
/// @notice Retrieves the rewards across all snapshots for `account`. | ||
/// @param account The account to retrieve rewards for | ||
/// @return The rewards across all snapshots for `account` | ||
function getLifetimeRewards(address account) external view returns (uint256); | ||
|
||
/// @notice Check if rewards can be accrued. | ||
/// @return Boolean indicating if rewards can be accrued | ||
function canAccrue() external view returns (bool); | ||
|
||
/// @notice Get the time until the next snapshot. | ||
/// @return The time until the next snapshot | ||
function getTimeUntilNextSnapshot() external view returns (uint256); | ||
} |
This file contains 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,108 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import {ISignedSnapshotStakingPool} from "../interfaces/staking/ISignedSnapshotStakingPool.sol"; | ||
|
||
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; | ||
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; | ||
import {SnapshotStakingPool} from "./SnapshotStakingPool.sol"; | ||
|
||
/// @title SignedSnapshotStakingPool | ||
/// @author Index Cooperative | ||
/// @notice A contract for staking `stakeToken` and receiving `rewardToken` based | ||
/// on snapshots taken when rewards are accrued. | ||
contract SignedSnapshotStakingPool is ISignedSnapshotStakingPool, SnapshotStakingPool, EIP712 { | ||
string private constant MESSAGE_TYPE = "StakeMessage(string message)"; | ||
|
||
/* ERRORS */ | ||
|
||
/// @notice Error when staker is not approved | ||
error NotApprovedStaker(); | ||
/// @notice Error when signature is invalid | ||
error InvalidSignature(); | ||
|
||
/* EVENTS */ | ||
|
||
/// @notice Emitted when a staker has message signature approved | ||
event StakerApproved(address indexed staker); | ||
|
||
/* STORAGE */ | ||
|
||
/// @inheritdoc ISignedSnapshotStakingPool | ||
string public message; | ||
/// @inheritdoc ISignedSnapshotStakingPool | ||
mapping(address => bool) public isApprovedStaker; | ||
|
||
/* CONSTRUCTOR */ | ||
|
||
/// @param eip712Name Name of the EIP712 signing domain | ||
/// @param eip712Version Current major version of the EIP712 signing domain | ||
/// @param stakeMessage The message to sign when staking | ||
/// @param name Name of the staked token | ||
/// @param symbol Symbol of the staked token | ||
/// @param rewardToken Instance of the reward token | ||
/// @param stakeToken Instance of the stake token | ||
/// @param distributor Address of the distributor | ||
/// @param snapshotDelay The minimum amount of time between snapshots | ||
constructor( | ||
string memory eip712Name, | ||
string memory eip712Version, | ||
string memory stakeMessage, | ||
string memory name, | ||
string memory symbol, | ||
IERC20 rewardToken, | ||
IERC20 stakeToken, | ||
address distributor, | ||
uint256 snapshotDelay | ||
) | ||
EIP712(eip712Name, eip712Version) | ||
SnapshotStakingPool(name, symbol, rewardToken, stakeToken, distributor, snapshotDelay) | ||
{ | ||
message = stakeMessage; | ||
} | ||
|
||
/* STAKER FUNCTIONS */ | ||
|
||
/// @inheritdoc ISignedSnapshotStakingPool | ||
function stake(uint256 _amount) external override(SnapshotStakingPool, ISignedSnapshotStakingPool) nonReentrant { | ||
if (!isApprovedStaker[msg.sender]) revert NotApprovedStaker(); | ||
_stake(msg.sender, _amount); | ||
} | ||
|
||
/// @inheritdoc ISignedSnapshotStakingPool | ||
function stake(uint256 _amount, bytes calldata _signature) external nonReentrant { | ||
_approveStaker(msg.sender, _signature); | ||
_stake(msg.sender, _amount); | ||
} | ||
|
||
/// @inheritdoc ISignedSnapshotStakingPool | ||
function approveStaker(bytes calldata _signature) external { | ||
_approveStaker(msg.sender, _signature); | ||
} | ||
|
||
/* VIEW FUNCTIONS */ | ||
|
||
/// @inheritdoc ISignedSnapshotStakingPool | ||
function getStakeSignatureDigest() public view returns (bytes32) { | ||
return _hashTypedDataV4( | ||
keccak256( | ||
abi.encode( | ||
keccak256(abi.encodePacked(MESSAGE_TYPE)), | ||
keccak256(bytes(message)) | ||
) | ||
) | ||
); | ||
} | ||
|
||
/* INTERNAL FUNCTIONS */ | ||
|
||
/// @dev Approve the `staker` if the `signature` is valid | ||
/// @param staker The staker to approve | ||
/// @param signature The signature to verify | ||
function _approveStaker(address staker, bytes calldata signature) internal { | ||
if (!SignatureChecker.isValidSignatureNow(staker, getStakeSignatureDigest(), signature)) revert InvalidSignature(); | ||
isApprovedStaker[staker] = true; | ||
emit StakerApproved(staker); | ||
} | ||
} |
Oops, something went wrong.