// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; /** * @title SOMA Staking Contract. * @author SOMA.finance. * @notice A staking contract that supports multiple reward tokens and strategies. */ interface ISomaStaking { /** * Events *********************************** */ /** * @notice Emitted when a user Stakes. * @param amount The amount staked, denominated in the staking token. * @param sender The address of the message sender. */ event Staked(uint256 amount, address indexed sender); /** * @notice Emitted when a user Unstakes. * @param amount The amount unstaked, denominated in the staking token. * @param sender The address of the message sender. */ event Unstaked(uint256 amount, address indexed sender); /** * @notice Emitted when a user Unstakes immediately. * @param amount The amount of the staking token unstaked. * @param fee The early unstake fee charged. * @param sender The address of the message sender. */ event UnstakedImmediate(uint256 amount, uint256 fee, address indexed sender); /** * @notice Emitted when a user Claims. * @param asset The address of the reward token claimed. * @param amount The amount of the reward token claimed. * @param sender The address of the message sender. */ event Claimed(address indexed asset, uint256 amount, address indexed sender); /** * @notice Emitted when a user Claims immediately. * @param asset The address of the reward token claimed. * @param amount The amount of the reward token claimed. * @param fee The early claim fee. * @param sender The address of the message sender. */ event ClaimedImmediate(address indexed asset, uint256 amount, uint256 fee, address indexed sender); /** * @notice Emitted when a Strategy is created. * @param rewardToken The address of the reward token. * @param amount The amount of the reward tokens. * @param startDate The timestamp marking the start of the strategy. * @param endDate The timestamp marking the end of the strategy. * @param sender The address of the message sender. */ event StrategyCreated( address indexed rewardToken, uint256 amount, uint256 startDate, uint256 endDate, address indexed sender ); /** * @notice Emitted when a Admin claims. * @param asset The address of the asset claimed. * @param amount The amount of the asset claimed. * @param to The address that the claimed tokens is sent to. * @param sender The address of the message sender. */ event AdminClaimed(address indexed asset, uint256 amount, address indexed to, address indexed sender); /** * @notice Emitted when the Staking Config is updated. * @param prevConfig The previous staking configuration. * @param newConfig The new staking configuration. * @param sender The address of the message sender. */ event StakingConfigUpdated(StakingConfig prevConfig, StakingConfig newConfig, address indexed sender); /** * @notice Emitted when an Unstake or Claim Request is created. * @param id The ID of the request. * @param asset The asset of the request. * @param amount The amount of the requested asset. * @param sender The address of the message sender. * @param requestType The type of request. */ event RequestCreated( uint256 indexed id, address indexed asset, uint256 amount, address indexed sender, RequestType requestType ); /** * @notice Emitted when an Unstake or Claim Request is cancelled. * @param id The ID of the request. */ event RequestCancelled(uint256 indexed id); /** * @notice Emitted when an Unstake or Claim Request is fulfilled. * @param id The ID of the request. */ event RequestFulfilled(uint256 indexed id); /** * @notice Emitted when a Reward Token is added. * @param token The address of the reward token. * @param sender The address of the message sender. */ event RewardTokenAdded(address indexed token, address indexed sender); /** * @notice Emitted when a Staking Token is seized. * @param from The address that is having their tokens seized. * @param to The address to receive the seized tokens. * @param amount The amount of tokens seized. * @param seizedRewards The array of seized reward token amounts. * @param sender The address of the message sender. */ event Seized( address indexed from, address indexed to, uint256 amount, uint256[] seizedRewards, address indexed sender ); /** * Enum *********************************** */ /** * @notice Request type. */ enum RequestType { UNSTAKE, CLAIM } /** * Structs *********************************** */ /** * @notice Staking Configuration structure. Defines the fees and unstake duration. * @param unstakeDuration The amount of seconds that must pass before an unstake request is fulfilled. * @param claimDuration The amount of seconds that must pass before a claim request is fulfilled. * @param earlyUnstakeFee The fee charged for early unstakes. * @param earlyClaimFee The fee charged for early claims. */ struct StakingConfig { uint64 unstakeDuration; uint64 claimDuration; uint16 earlyUnstakeFee; uint16 earlyClaimFee; } /** * @notice Request Configuration structure. * @param hash The ID of the request. * @param timestamp The timestamp that the request was created at. * @param amount The amount of the reward token requested. */ struct Request { bytes8 hash; uint64 timestamp; uint128 amount; } /** * @notice User Information structure. * @param stake The amount of tokens the user has staked. * @param claimable The mapping of reward token to the claimable rewards amount for the user. * @param debt The mapping of reward token to rewards amount for the user. */ struct UserInfo { uint256 stake; // How many tokens the user has staked mapping(address => uint256) claimable; mapping(address => uint256) debt; } /** * @notice Strategy structure. Defines the rewards that are released over a particular amount of time for * an asset. * @param startDate The timestamp marking the start of the strategy. * @param endDate The timestamp marking the end of the strategy. * @param rewardToken The address of the reward token. * @param rewardsLocked The amount of locked reward tokens. * @param rewardsUnlocked The amount of unlocked reward tokens. */ struct Strategy { uint48 startDate; uint48 endDate; address rewardToken; uint128 rewardsLocked; uint128 rewardsUnlocked; } /** * @notice Returns the Staking Global Admin Role. * @dev Equivalent to keccak256('Staking.GLOBAL_ADMIN_ROLE'). */ function GLOBAL_ADMIN_ROLE() external pure returns (bytes32); /** * @notice Returns the Staking Local Admin Role. */ function LOCAL_ADMIN_ROLE() external view returns (bytes32); /** * @notice Returns the Staking Global Seize Role. * @dev Equivalent to keccak256('Staking.GLOBAL_SEIZE_ROLE'). */ function GLOBAL_SEIZE_ROLE() external pure returns (bytes32); /** * @notice Returns the Staking Local Seize Role. */ function LOCAL_SEIZE_ROLE() external view returns (bytes32); /** * @notice Returns the Staking Configuration. */ function config() external view returns (StakingConfig memory); /** * @notice Returns the strategy, given a strategy ID. * @param id The ID of the strategy. * @return The strategy with the matching ID. */ function strategy(uint256 id) external view returns (Strategy memory); /** * @notice Returns the pending strategy, given a strategy ID. * @param index The ID of the pending strategy. * @return The pending strategy with the matching ID. */ function pendingStrategy(uint256 index) external view returns (Strategy memory); /** * @notice Returns the total number of strategies created. */ function totalStrategies() external view returns (uint256); /** * @notice Returns the total number of pending strategies. */ function totalPendingStrategies() external view returns (uint256); /** * @notice Returns the total number of staked tokens. */ function totalStaked() external view returns (uint256); /** * @notice Returns the total number of staking tokens pending unstake. */ function totalPendingUnstake() external view returns (uint256); /** * @notice Returns the last recorded tokens per share, given a token. * @param _asset The token to return the tokens per share of. * @return The tokens per share of `_asset`. */ function tps(address _asset) external view returns (uint256); /** * @notice Returns the current tokens per share, given a token. * @param token The token to return the current tokens per share of. * @param tps_ The current tokens per share of `token`. */ function currentTPS(address token) external view returns (uint256 tps_); /** * @notice Returns the number of reward tokens. */ function totalRewardTokens() external view returns (uint256); /** * @notice Returns the address of a reward token, given an index. * @param index The index of the reward token. */ function rewardToken(uint256 index) external view returns (address); /** * @notice Returns the address of the staking token. */ function stakingToken() external view returns (address); /** * @notice Returns the staked balance of an account. * @param _account The account to return the staked balance of. * @return The staked balance of the account, denominated in the staking token. */ function stakeOf(address _account) external view returns (uint256); /** * @notice Returns an Unstake Request, given an account and Request ID. * @param _account The account to return the Request of. * @param _id The ID of the request. * @return The Request with the matching ID. */ function unstakeRequest(address _account, uint256 _id) external view returns (Request memory); /** * @notice Returns the debt of an account, given an asset. * @param _account The account to return the debt of. * @param _asset The asset to return the account's debt of. * @return The debt of the account, denominated in the asset. */ function debt(address _account, address _asset) external view returns (uint256); /** * @notice Returns the amount of claimable tokens of an account, given an asset. * @param _account The account to return the claimable tokens of. * @param _asset The asset to return the claimable amount of. * @return The number of claimable tokens. */ function claimable(address _account, address _asset) external view returns (uint256); /** * @notice Returns the Claim Request of an account, given an asset and Request ID. * @param _account The account to return the Claim Request of. * @param _asset The asset to return the Claim Request of. * @param _id The ID of the Claim Request. * @return The Claim Request. */ function claimRequest(address _account, address _asset, uint256 _id) external view returns (Request memory); /** * @notice Initializer for the Staking Contract. * @param stakingToken_ The address of the staking token. * @param rewardTokens_ An array of addresses of the reward tokens. * @custom:emits Initialized * @custom:requirement `stakingToken_` must be a contract. * @custom:requirement Each token in `rewardTokens_` must be a contract. */ function initialize(address stakingToken_, address[] memory rewardTokens_) external; /** * @notice Stakes an amount of staking tokens. * @param _amount The amount of tokens to stake. * @custom:emits Staked * @custom:requirement `_amount` must be greater than zero. */ function stake(uint256 _amount) external; /** * @notice Creates an Unstake Request. This is required before performing an unstake. Creating an * unstake request will stop users from earning rewards on the amount that they are unstaking for. * @param _amount The amount of tokens requested to unstake. * @custom:emits RequestCreated * @custom:requirement The stake of the message sender must be greater than or equal to `_amount`. * @custom:requirement `_amount` must be greater than zero. * @return _id The ID of the created Unstake Request. */ function createUnstakeRequest(uint256 _amount) external returns (uint256 _id); /** * @notice Cancels multiple Unstake Requests. Cancelling an unstake will return the staking tokens to * the contract allowing the user to earn rewards on these tokens again. * @param _ids An array of Request IDs to cancel the unstake requests for. * @custom:emits RequestCancelled * @custom:requirement The length of `_ids` must be greater than zero. */ function cancelUnstakeRequests(uint256[] calldata _ids) external; /** * @notice Unstakes the input requests, given that the required unstake duration has passed. This unstake has no fees * associated with the transaction. * @param _ids An array of Request IDs. * @custom:emits Unstaked * @custom:emits RequestFulfilled * @custom:requirement The difference between the timestamp of the function call and the timestamp of the request creation * must be greater than or equal to the Unstake required duration. */ function unstake(uint256[] calldata _ids) external; /** * @notice Unstakes tokens immediately. This incurs a fee to bypass the unstake duration required to unstake. * @param _amount The number of staking tokens to unstake immediately. * @custom:emits UnstakedImmediate * @custom:requirement The staked balance of the message caller must be greater than or equal to `_amount`. * @custom:requirement `_amount` must be greater than or equal to zero. */ function unstakeImmediate(uint256 _amount) external; /** * @notice Creates Claim Requests for multiple rewards tokens. This is required before performing a claim. * @param _assets The array of rewards tokens to create Claim Requests for. * @custom:emits RequestCreated * @custom:requirement Each asset in `_assets` must be a valid reward token. * @custom:requirement The claimable amount for the message sender, for each asset in `_assets` must be greater than zero. * @return _ids The array of created Claim Requests IDs. */ function createClaimRequests(address[] calldata _assets) external returns (uint256[] memory _ids); /** * @notice Cancels multiple Claim Requests. * @param _assets The array of rewards tokens to cancel Claim Requests for. * @param _ids The 2D array of Request IDs to cancel requests of. * @custom:emits RequestCancelled * @custom:requirement The length of `_assets` must be greater than zero. * @custom:requirement The length of `_ids` must be equal to the length of `_assets`. */ function cancelClaimRequests(address[] calldata _assets, uint256[][] calldata _ids) external; /** * @notice Claims an amount of reward tokens, provided that each request is ready to be claimed. * @param _assets The array of rewards tokens to fulfill Claim Requests for. * @param _ids The 2D array of Request IDs to fulfill requests of. * @custom:emits Claimed * @custom:emits RequestFulfilled * @custom:requirement The length of `_ids` must be equal to the length of `_asset`. */ function claim(address[] calldata _assets, uint256[][] calldata _ids) external; /** * @notice Claims an amount of reward tokens immediately, bypassing the claim duration in exchange for a fee. * @param _assets The array of rewards tokens to claim immediately. * @param _amounts The array of amounts for each reward token to claim immediately. * @custom:emits ClaimedImmediate * @custom:requirement The length of `_assets` must be equal to the length of `_amounts`. * @custom:requirement Each asset in `_assets` must be a valid reward token. */ function claimImmediate(address[] calldata _assets, uint256[] calldata _amounts) external; // ********************************** ADMIN ********************************** /** * @notice Returns the amount of admin claimable tokens originating from fees. * @param _asset The asset to return the admin claimable balance of. * @custom:requirement `_asset` must be a valid reward token. * @return The amount of admin claimable tokens, denominated in `_asset`. */ function adminClaimable(address _asset) external view returns (uint256); /** * @notice Adds a reward token to contract. Once a reward token has been added, it cannot be removed. * @param _asset The asset to add as a reward token. * @custom:emits RewardTokenAdded * @custom:requirement `_asset` must not be an existing reward token. * @custom:requirement The message sender must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE. */ function addRewardToken(address _asset) external; /** * @notice Claims the admin claimable amount for a reward token. * @param _asset The reward token to claim as an admin. * @param _to The address to send the claimed tokens to. * @custom:emits AdminClaimed * @custom:requirement `_asset` must not be an existing reward token. * @custom:requirement The claimable amount of `_asset` must be greater than zero. * @custom:requirement The message sender must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE. */ function adminClaim(address _asset, address _to) external; /** * @notice Creates a Strategy. * @param _startDate The timestamp marking the start of the strategy. * @param _endDate The timestamp marking the end of the strategy. * @param _rewardToken The address of the reward token. * @param _rewardAmount The amount of the reward token. * @custom:emits StrategyCreated * @custom:requirement `_startDate` must be greater than the timestamp of the function call. * @custom:requirement `_startDate` must be less than `_endDate`. * @custom:requirement `_rewardToken` must be a valid existing reward token. * @custom:requirement `_endDate` must be a valid uint48. * @custom:requirement The message sender must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE. */ function createStrategy(uint256 _startDate, uint256 _endDate, address _rewardToken, uint256 _rewardAmount) external; /** * @notice Updates the Staking Configuration. * @param _unstakeDuration The new unstake duration. * @param _claimDuration The new claim duration. * @param _earlyUnstakeFee The new early unstake fee. * @param _earlyClaimFee The new early claim fee. * @custom:emits StakingConfigUpdated * @custom:requirement The message sender must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE. */ function updateConfig( uint64 _unstakeDuration, uint64 _claimDuration, uint16 _earlyUnstakeFee, uint16 _earlyClaimFee ) external; /** * @notice Seizes staking tokens from `from`. * @param from The address to have their tokens seized. * @custom:emits Seized * @custom:requirement The user's staked balance must be greater than zero. */ function seize(address from) external; }