Stakinator Overview
This document provides a comprehensive guide to the Stakinator facet in the Diamond Vaultinator framework.
Table of Contents
Introduction
Features
Architecture
Usage
Staking Pools
Reward Calculation
Security Considerations
Best Practices
Integration Examples
Introduction
The Stakinator facet extends the Diamond Vaultinator with comprehensive staking functionality, allowing vault owners to stake tokens, earn rewards, and participate in various staking strategies. It provides a flexible system for creating and managing staking pools with customizable parameters.
Features
Multiple Staking Pools: Support for multiple token staking pools with different reward rates and lock periods
Flexible Locking: Customizable lock periods for staked tokens
Reward Distribution: Automated reward calculation and distribution
Emergency Withdrawals: Safety mechanism for emergency situations
Role-Based Access Control: Secure management of staking pools and parameters
Vault Integration: Seamless integration with the Diamond Vaultinator vault system
Architecture
The Stakinator facet follows the Diamond pattern and consists of:
IStakinatorFacet: Interface defining all functions and events
StakinatorFacet: Implementation of the interface
StakinatorStorage: Dedicated storage structure for staking data
Storage Structure
struct StakinatorStorage {
address rewardToken;
EnumerableSet.AddressSet activePoolTokens;
mapping(address => StakingPool) stakingPools;
bool initialized;
}
struct StakingPool {
bool active;
address token;
uint256 rewardRate; // Basis points per year (e.g., 500 = 5%)
uint256 totalStaked;
uint256 lockPeriod; // Lock period in seconds
uint256 lastUpdateTime;
mapping(uint256 => UserStake) stakes; // vaultId => UserStake
}
struct UserStake {
uint256 amount;
uint256 stakedAt;
uint256 lockUntil;
uint256 lastClaimTime;
uint256 rewardDebt;
}Access Control
The Stakinator facet uses the following role:
STAKING_MANAGER_ROLE: Required for creating and updating staking pools and managing system parameters
Usage
Initialization
Before using the Stakinator facet, it must be initialized:
function initializeStakinatorStorage(address _admin, address _rewardToken) external;This function:
Sets the reward token address
Grants the
STAKING_MANAGER_ROLEto the adminMarks the storage as initialized
Creating Staking Pools
Staking pools can be created by accounts with the STAKING_MANAGER_ROLE:
function createStakingPool(
address _token,
uint256 _rewardRate,
uint256 _lockPeriod
) external;Parameters:
_token: Address of the token to be staked_rewardRate: Annual reward rate in basis points (e.g., 500 = 5%)_lockPeriod: Duration in seconds that tokens must remain staked
Staking Tokens
Vault owners or approved operators can stake tokens:
function stake(
uint256 _vaultId,
address _token,
uint256 _amount,
uint256 _lockPeriod
) external;Parameters:
_vaultId: ID of the vault_token: Address of the token to stake_amount: Amount to stake_lockPeriod: Optional custom lock period (0 for default pool period)
Managing Stakes
Users can increase their stakes, withdraw after the lock period, or claim rewards:
// Increase existing stake
function increaseStake(uint256 _vaultId, address _token, uint256 _amount) external;
// Withdraw after lock period
function withdraw(uint256 _vaultId, address _token, uint256 _amount) external;
// Claim rewards without withdrawing
function claimRewards(uint256 _vaultId, address _token) external returns (uint256);
// Emergency withdrawal (may forfeit rewards)
function emergencyWithdraw(uint256 _vaultId, address _token) external;Viewing Information
The facet provides several view functions to check staking information:
// Check pending rewards
function pendingRewards(uint256 _vaultId, address _token) external view returns (uint256);
// Get staking pool information
function getStakingPoolInfo(address _token) external view returns (...);
// Get user stake information
function getUserStakeInfo(uint256 _vaultId, address _token) external view returns (...);
// Get all active staking pools
function getActiveStakingPools() external view returns (address[] memory);Staking Pools
Pool Parameters
Each staking pool has the following parameters:
Token: The ERC20 token that can be staked
Reward Rate: Annual percentage yield in basis points
Lock Period: Minimum duration tokens must remain staked
Total Staked: Total amount of tokens staked in the pool
Updating Pools
Pool parameters can be updated by accounts with the STAKING_MANAGER_ROLE:
function updateStakingPool(
address _token,
uint256 _rewardRate,
uint256 _lockPeriod
) external;When updating a pool, all pending rewards are calculated and stored before applying the new parameters.
Reward Calculation
Rewards are calculated based on:
Staked Amount: The amount of tokens staked
Reward Rate: Annual percentage yield in basis points
Time Elapsed: Duration since the last reward calculation
The formula used is:
rewardPerSecond = (rewardRate * stakedAmount) / (10000 * 31536000)
reward = rewardPerSecond * timeElapsedWhere:
10000is the basis points denominator (100%)31536000is the number of seconds in a year (365 days)
Security Considerations
Lock Period Enforcement
The lock period is strictly enforced. Users cannot withdraw staked tokens before the lock period expires unless they use the emergency withdrawal function, which may forfeit rewards.
Emergency Withdrawals
The emergency withdrawal function provides a safety mechanism for users to withdraw their staked tokens in case of emergencies, even if the lock period has not expired. However, this may result in forfeiting accumulated rewards.
Access Control
All administrative functions are protected by role-based access control. Only accounts with the appropriate roles can create or update staking pools or change system parameters.
Best Practices
Setting Appropriate Reward Rates
When setting reward rates, consider:
The value of the staked token
The value of the reward token
Market conditions and competitive rates
Sustainability of the reward system
Lock Periods
Choose lock periods that balance:
User flexibility
Protocol stability
Reward economics
Common lock periods range from 7 days to 365 days.
Reward Token Management
Ensure that:
The reward token contract is secure and well-audited
Sufficient reward tokens are available for distribution
The reward distribution is sustainable over time
Integration Examples
Basic Staking Example
// Initialize the Stakinator
stakinatorFacet.initializeStakinatorStorage(admin, rewardTokenAddress);
// Create a staking pool for DAI with 5% APY and 30-day lock
stakinatorFacet.createStakingPool(daiAddress, 500, 30 days);
// Stake 1000 DAI from vault #123
dai.approve(diamondAddress, 1000e18);
stakinatorFacet.stake(123, daiAddress, 1000e18, 0);
// After 30 days, claim rewards
uint256 rewards = stakinatorFacet.claimRewards(123, daiAddress);
// Withdraw staked tokens
stakinatorFacet.withdraw(123, daiAddress, 1000e18);Staking with Custom Lock Period
// Stake with a custom 60-day lock period
dai.approve(diamondAddress, 1000e18);
stakinatorFacet.stake(123, daiAddress, 1000e18, 60 days);Emergency Withdrawal
// In case of emergency, withdraw without waiting for lock period
stakinatorFacet.emergencyWithdraw(123, daiAddress);