🥩Staking
Learn about the 2.0 version of Staking CHAIN token currency instructions.
StakeChain Staking Documentation
Overview
StakeChain is a comprehensive staking platform that allows users to earn rewards by staking CHAIN tokens in multiple pools. Each pool has its own unique parameters including APR (Annual Percentage Rate), minimum and maximum stake amounts, and time locks for unstaking and claiming rewards. The system provides flexible staking options with robust security measures to protect user funds.
Pool System
The StakeChain contract manages multiple independent pools through the PoolInfo structure. Each pool operates with distinct parameters that determine how users can interact with it:
struct PoolInfo {
bool created;
uint256 APR;
uint256 maximumStakedByUser;
uint256 minimumStakeAmount;
uint256 lastClaimedRewards;
uint256 maxSize;
uint256 unstakeTimeLock;
uint256 claimTimeLock;
uint256 totalStakers;
uint256 totalStakedAmount;
uint256 totalRewardsEarned;
}
Pool Parameters
APR (Annual Percentage Rate): Determines the yearly reward rate for staked tokens. For example, a 16% APR means users earn 16% of their staked amount annually
Minimum Stake Amount: The lowest amount of CHAIN tokens required to participate in a pool, ensuring meaningful participation and preventing spam transactions
Maximum Stake Per User: Optional limit on how much a single user can stake in a pool, promoting fair distribution of staking opportunities
Pool Size Limit: Maximum total tokens that can be staked across all users in a pool, preventing unlimited growth
Claim Time Lock: Minimum waiting period between reward claims, preventing frequent micro-transactions
Unstake Time Lock: Required waiting period after staking before tokens can be withdrawn, ensuring pool stability
User Staking Process
Standard Staking
Users can stake CHAIN tokens in any active pool using the standard staking function:
function stake(uint256 poolId, uint256 amount) external nonReentrant noContracts whenNotPaused(poolId)
Security Checks:
Pool must exist and be active
Amount must meet minimum stake requirement
Pool size limit cannot be exceeded
User must have sufficient token balance
Maximum stake per user limit enforced (if enabled)
Only externally owned accounts can stake (no contracts)
Pool must not be paused
Permit-Based Staking
For enhanced user experience, users can stake without separate approval transactions:
function stakeWithPermit(
uint256 poolId,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external nonReentrant whenNotPaused(poolId) noContracts returns (bool)
This function uses ERC20Permit to combine token approval and staking in a single transaction, reducing gas costs and improving user experience.
Reward System
Reward Calculation
Rewards are calculated using precise mathematics with timestamp buffering to prevent manipulation:
function calculateRewards(
uint256 APR,
uint256 amount,
uint256 lastStakeOrClaimTimestamp
) private view returns (uint256) {
uint256 rewardsEarnedRange = block.timestamp - lastStakeOrClaimTimestamp;
if (rewardsEarnedRange > TIMESTAMP_BUFFER) {
rewardsEarnedRange -= TIMESTAMP_BUFFER;
}
uint256 annualRewards = (amount * APR) / 10000;
uint256 rewardsPerSecond = annualRewards / ONE_YEAR;
return rewardsPerSecond * rewardsEarnedRange;
}
Security Features:
15-minute timestamp buffer prevents manipulation
High precision calculations prevent rounding errors
APR stored in basis points (1600 = 16.00%)
Claiming Rewards
Users can claim accumulated rewards while keeping their tokens staked:
function claimRewards(uint256 poolId) external nonReentrant noContracts whenNotPaused(poolId)
Requirements:
Pool must exist and be active
User must have staked tokens
Claim time lock must have passed
Pool must not be paused
Unstaking Process
Standard Unstaking
Users can withdraw their staked tokens along with accumulated rewards:
function unstake(uint256 poolId) external nonReentrant noContracts whenNotPaused(poolId)
Security Checks:
Pool must exist
User must have staked tokens
Unstake time lock must have passed
Pool must not be paused
Emergency Unstaking
During emergency situations, users can immediately withdraw their funds:
function emergencyUnstake(uint256 poolId) external nonReentrant noContracts onEmergency(poolId)
Emergency unstaking bypasses normal time locks but requires the pool to be in emergency mode, which can only be activated by the contract owner.
Compound Staking
Users can add more tokens to their existing stake at any time. When additional tokens are staked:
The unstake timer resets for the entire staked amount
Previously earned rewards are preserved and continue accruing
New stake amount is added to the existing balance
Reward calculations continue based on the new total
This compound staking mechanism allows users to grow their stake while maintaining their reward history.
Security Measures
Access Control
No Contract Interaction: The noContracts
modifier prevents smart contracts from interacting with staking functions, reducing attack vectors
Reentrancy Protection: All state-changing functions use nonReentrant
modifier to prevent reentrancy attacks
Owner-Only Functions: Critical administrative functions are restricted to the contract owner
Time-Based Security
APR Change Delays: Changes to APR rates require a 48-hour delay to prevent front-running attacks
Emergency Toggle Cooldown: Emergency status can only be toggled once per day to prevent abuse
Timestamp Buffering: Reward calculations include a 15-minute buffer to prevent timestamp manipulation
Pool Security
Pause Mechanism: Pools can be paused to prevent new interactions during maintenance or emergencies
Maximum Stake Limits: Optional per-user and total pool limits prevent concentration of stakes
Pool Deletion: Empty pools can be deleted to clean up the contract state
View Functions for Users
Pool Information
function getPoolInfo(uint256 id) public view returns (PoolInfo memory)
Returns complete pool information including APR, limits, and current statistics.
User Stake Information
function getUserStakeInfo(address user, uint256 id) public view returns (StakeInfo memory)
Returns user's staking details including staked amount, rewards, and timestamps.
Reward Calculations
function getUserRewards(address user, uint256 poolId) public view returns (uint256)
Calculates total rewards available for claiming including both stored rewards and newly earned rewards.
Time Lock Information
function getUnstakeUnlockTimestamp(address user, uint256 poolId) public view returns (uint256)
function getClaimUnlockTimestamp(address user, uint256 poolId) public view returns (uint256)
Returns remaining time before users can unstake or claim rewards.
Pool Status Monitoring
Status Checks
function getPoolStatus(uint256 poolId) public view returns (bool)
function getPoolEmergencyStatus(uint256 poolId) public view returns (bool)
function getMaximumStakeStatus(uint256 poolId) public view returns (bool)
These functions allow users to check if pools are paused, in emergency mode, or have maximum stake limits enabled.
Best Practices for Users
Check Pool Status: Always verify pool status before attempting transactions
Monitor Time Locks: Track remaining time before unstaking or claiming becomes available
Understand APR Changes: Be aware that APR changes have a 48-hour delay for security
Emergency Procedures: Familiarize yourself with emergency unstaking procedures
Gas Optimization: Use permit-based staking to reduce transaction costs
Reward Timing: Plan reward claims considering time locks and gas costs
Error Handling
The contract provides clear error messages for common issues:
"Pool has not been created yet" - Invalid pool ID
"The staked amount is lower than the minimum stake amount required" - Insufficient stake
"The minimum lockup period has not passed" - Time lock not expired
"Pool operations are currently paused" - Pool is paused
"Not in Emergency" - Emergency function called on non-emergency pool
This comprehensive staking system provides users with flexible options for earning rewards while maintaining strong security measures to protect their investments.
Last updated
Was this helpful?