Staking
Technical documentation for StakeChain — the Zentachain staking smart contract system.
Verified Contracts
All contracts are deployed on Ethereum mainnet and verified on Etherscan.
Overview
StakeChain is the staking smart contract that allows CHAIN token holders to stake their tokens in configurable pools and earn rewards. Rewards are minted directly to stakers — there is no pre-funded reward pool.
The contract is built on Solidity ^0.8.28 with OpenZeppelin v5.2.0 libraries and includes reentrancy protection, timestamp manipulation safeguards, and owner-controlled administration.
Live Staking Pools
Three staking pools are currently active on mainnet:
0
12%
1,000 CHAIN
10,000 CHAIN
100,000 CHAIN
1 day
7 days
1
16%
2,000 CHAIN
20,000 CHAIN
200,000 CHAIN
1 day
14 days
2
20%
5,000 CHAIN
50,000 CHAIN
500,000 CHAIN
1 day
28 days
Higher APR pools require larger minimum stakes and longer lock-up periods.
Pool System
Each staking pool is an independent configuration with its own parameters:
APR
Annual Percentage Rate in basis points (1600 = 16%)
Minimum Stake Amount
Lowest amount a user can stake
Maximum Stake Per User
Cap on individual stakes
Pool Size Limit
Maximum total tokens in the pool
Claim Time Lock
Minimum time between reward claims (1 day)
Unstake Time Lock
Minimum time before withdrawal allowed
Staking
Standard Staking
Two-transaction process:
Approve — User approves the StakeChain contract to spend their CHAIN tokens
Stake — Call
stake(poolId, amount)to deposit tokens into a pool
Permit-Based Staking
Single-transaction process using ERC-2612 permit signatures:
Call
stakeWithPermit(poolId, amount, deadline, v, r, s)Combines approval and staking in one transaction
Saves gas and improves UX
Compound Staking
Users can add more tokens to an existing stake at any time:
Previous rewards are preserved and continue accruing
The unstake timer resets for the entire staked amount
New rewards begin accruing on the combined amount
Rewards
Calculation
Rewards are calculated based on time elapsed and the pool's APR:
Key details:
APR is stored in basis points (1200 = 12%, 1600 = 16%, 2000 = 20%)
A 15-minute timestamp buffer is applied to prevent manipulation
Rewards are minted to the user (inflationary), not drawn from a pool
Claiming
User calls
claimRewards(poolId)Claim time lock (1 day) must have elapsed since last claim
Pool must not be paused
Rewards are minted directly to the user's wallet
Unstaking
Standard Unstake
Unstake time lock must have elapsed since staking (7/14/28 days depending on pool)
Returns full staked amount plus any unclaimed rewards
Removes user from the pool
Emergency Unstake
Only available when emergency mode is enabled for the pool
Bypasses time lock restrictions
Returns staked amount plus accumulated rewards
Emergency mode has a 24-hour toggle cooldown to prevent abuse
Security
Reentrancy Protection
nonReentrant modifier on all external calls
No Contract Interaction
noContracts modifier blocks smart contract callers
APR Change Delay
48-hour delay prevents front-running
Timestamp Buffer
15-minute buffer reduces manipulation window
Emergency Cooldown
24-hour cooldown on emergency toggle
Pause Mechanism
Pools can be paused individually
Max Stake Limits
Per-user cap enforcement per pool
Testing & Audit
Test Cases
152 passing (100% coverage)
Test Files
18 dedicated test files
Security Rating
9.2 / 10
Code Quality
9.0 / 10
Gas Efficiency
8.5 / 10
Solidity Version
^0.8.28
OpenZeppelin Version
5.2.0
Framework
Hardhat + Chai
Security Tests Include
Access control enforcement
Staking limits and pool size enforcement
Timelock mechanism validation
Emergency function testing
Reward calculation precision and edge cases
APR change protection (48-hour delay, front-running prevention)
Timestamp manipulation protection
Pool deletion safety (only when empty)
Emergency toggle rate limiting
Permit-based staking validation
Deployment integrity verification
Security Verification Matrix
Reentrancy Protection
Passed
Passed
Passed
Access Control
Passed
Passed
Passed
Input Validation
Passed
Passed
Passed
Integer Overflow
Passed
Passed
Passed
Emergency Pause
Passed
Passed
Passed
Time Manipulation
Passed
Passed
Passed
Front-running Protection
Passed
Passed
Passed
Rate Limiting
Passed
Passed
Passed
APR Changes
To prevent front-running:
Owner schedules an APR change via
scheduleAPRChange(poolId, newAPR)A 48-hour delay period begins
After the delay, anyone can call
applyPendingAPRChange(poolId)to activate itAll changes are publicly visible on-chain
View Functions
getPoolInfo(id)
Complete pool configuration
getUserStakeInfo(address, id)
User's staked amount, rewards, timestamps
getUserRewards(address, poolId)
Accumulated unclaimed rewards
getUnstakeUnlockTimestamp(address, poolId)
When unstake becomes available
getClaimUnlockTimestamp(address, poolId)
When next claim is available
getPoolStatus(poolId)
Whether pool is paused
getPoolEmergencyStatus(poolId)
Whether emergency mode is active
getMaximumStakeStatus(poolId)
Whether max stake is enforced
getPendingAPRChange(poolId)
Scheduled APR change details
Token Contract
Name
Zentachain
Symbol
CHAIN
Standard
ERC-20
Decimals
12
Total Supply
5,000,000
Features
Burnable, Pausable, Permit (EIP-2612)
Address
0x6B58cfBEdCfe7C59d456c864c92257910A61D8FC
StakeChain and Zentanode are both whitelisted as minters on the CHAIN token contract, allowing them to mint reward tokens directly.
Zentanode Rewards Contract
A separate contract (Zentanode.sol) handles node operator rewards independently from StakeChain:
Address
0x5a427e6aA609509C6EE089502a048f17B4895a9b
Rewards Per Claim
25 CHAIN (configurable, max 1,000)
Claim Duration
31 days
Slash Duration
15 days
Daily Mint Limit
100,000 CHAIN
Access
Allowlist-based
Node operators are added to the allowlist and can claim rewards at regular intervals. The contract includes a slashing mechanism for misbehaving nodes and pro-rated partial rewards for operator removal.
Last updated
Was this helpful?