Token Proof of Stake System
The token proof of stake system is a mechanism for stake allocation and validation based on token holdings, used to implement decentralized consensus and governance. This tutorial will explain how to implement a secure and reliable proof of stake system.
Features
- Staking Mechanism
- Validator Management
- Reward Distribution
- Slashing Mechanism
- Delegation Mechanism
Contract Implementation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
/**
* @title ProofOfStake
* @dev Proof of stake contract implementation
*/
contract ProofOfStake is Ownable, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for IERC20;
// Validator information
struct Validator {
uint256 stake; // Staked amount
uint256 rewards; // Accumulated rewards
uint256 lastRewardBlock; // Last reward block
uint256 delegatedStake; // Total delegated stake
bool isActive; // Whether active
bool isJailed; // Whether jailed
}
// Delegation information
struct Delegation {
uint256 stake; // Delegated amount
uint256 rewards; // Accumulated rewards
uint256 lastRewardBlock; // Last reward block
}
// Staking configuration
struct StakingConfig {
uint256 minValidatorStake; // Minimum validator stake
uint256 minDelegationStake; // Minimum delegation stake
uint256 maxValidators; // Maximum validator count
uint256 validatorCommission; // Validator commission rate
uint256 unbondingTime; // Unbonding time
uint256 slashingRate; // Slashing rate
}
// State variables
IERC20 public stakingToken; // Staking token
mapping(address => Validator) public validators; // Validator mapping
mapping(address => mapping(address => Delegation)) public delegations; // Delegation mapping
address[] public validatorSet; // Validator set
StakingConfig public config; // Staking configuration
uint256 public totalStaked; // Total staked amount
uint256 public epochNumber; // Current epoch
uint256 public epochBlocks; // Blocks per epoch
uint256 public rewardPerBlock; // Reward per block
// Unbonding request
struct UnbondingRequest {
uint256 amount; // Unbonding amount
uint256 completionTime; // Completion time
}
mapping(address => UnbondingRequest[]) public unbondingRequests;
// Events
event ValidatorRegistered(address indexed validator, uint256 stake);
event ValidatorUpdated(address indexed validator, uint256 stake);
event ValidatorRemoved(address indexed validator);
event Delegated(address indexed delegator, address indexed validator, uint256 amount);
event Undelegated(address indexed delegator, address indexed validator, uint256 amount);
event RewardsClaimed(address indexed account, uint256 amount);
event ValidatorSlashed(address indexed validator, uint256 amount);
event EpochCompleted(uint256 indexed epochNumber);
/**
* @dev Constructor
*/
constructor(
address _stakingToken,
uint256 _epochBlocks,
uint256 _rewardPerBlock,
uint256 _minValidatorStake,
uint256 _minDelegationStake,
uint256 _maxValidators,
uint256 _validatorCommission,
uint256 _unbondingTime,
uint256 _slashingRate
) {
stakingToken = IERC20(_stakingToken);
epochBlocks = _epochBlocks;
rewardPerBlock = _rewardPerBlock;
config = StakingConfig({
minValidatorStake: _minValidatorStake,
minDelegationStake: _minDelegationStake,
maxValidators: _maxValidators,
validatorCommission: _validatorCommission,
unbondingTime: _unbondingTime,
slashingRate: _slashingRate
});
}
/**
* @dev Register as validator
*/
function registerValidator(uint256 _stake) external nonReentrant {
require(_stake >= config.minValidatorStake, "Stake too low");
require(!validators[msg.sender].isActive, "Already registered");
require(validatorSet.length < config.maxValidators, "Max validators reached");
stakingToken.safeTransferFrom(msg.sender, address(this), _stake);
validators[msg.sender] = Validator({
stake: _stake,
rewards: 0,
lastRewardBlock: block.number,
delegatedStake: 0,
isActive: true,
isJailed: false
});
validatorSet.push(msg.sender);
totalStaked = totalStaked.add(_stake);
emit ValidatorRegistered(msg.sender, _stake);
}
/**
* @dev Add validator stake
*/
function addValidatorStake(uint256 _amount) external nonReentrant {
require(validators[msg.sender].isActive, "Not a validator");
require(!validators[msg.sender].isJailed, "Validator jailed");
stakingToken.safeTransferFrom(msg.sender, address(this), _amount);
validators[msg.sender].stake = validators[msg.sender].stake.add(_amount);
totalStaked = totalStaked.add(_amount);
emit ValidatorUpdated(msg.sender, validators[msg.sender].stake);
}
/**
* @dev Delegate stake
*/
function delegate(address _validator, uint256 _amount) external nonReentrant {
require(validators[_validator].isActive, "Validator not active");
require(!validators[_validator].isJailed, "Validator jailed");
require(_amount >= config.minDelegationStake, "Stake too low");
stakingToken.safeTransferFrom(msg.sender, address(this), _amount);
Delegation storage delegation = delegations[msg.sender][_validator];
if (delegation.stake == 0) {
delegation.lastRewardBlock = block.number;
}
delegation.stake = delegation.stake.add(_amount);
validators[_validator].delegatedStake = validators[_validator].delegatedStake.add(_amount);
totalStaked = totalStaked.add(_amount);
emit Delegated(msg.sender, _validator, _amount);
}
/**
* @dev Request undelegation
*/
function undelegate(address _validator, uint256 _amount) external nonReentrant {
Delegation storage delegation = delegations[msg.sender][_validator];
require(delegation.stake >= _amount, "Insufficient stake");
// Update delegation information
delegation.stake = delegation.stake.sub(_amount);
validators[_validator].delegatedStake = validators[_validator].delegatedStake.sub(_amount);
totalStaked = totalStaked.sub(_amount);
// Create unbonding request
unbondingRequests[msg.sender].push(UnbondingRequest({
amount: _amount,
completionTime: block.timestamp.add(config.unbondingTime)
}));
emit Undelegated(msg.sender, _validator, _amount);
}
/**
* @dev Complete unbonding
*/
function completeUnbonding() external nonReentrant {
UnbondingRequest[] storage requests = unbondingRequests[msg.sender];
uint256 totalAmount = 0;
uint256 completedCount = 0;
for (uint256 i = 0; i < requests.length; i++) {
if (requests[i].completionTime <= block.timestamp) {
totalAmount = totalAmount.add(requests[i].amount);
completedCount++;
} else {
break;
}
}
require(totalAmount > 0, "No completed unbonding");
// Remove completed requests
if (completedCount > 0) {
for (uint256 i = completedCount; i < requests.length; i++) {
requests[i - completedCount] = requests[i];
}
for (uint256 i = 0; i < completedCount; i++) {
requests.pop();
}
}
// Transfer unbonded tokens
stakingToken.safeTransfer(msg.sender, totalAmount);
}
/**
* @dev Calculate pending rewards
*/
function calculateRewards(address _account, address _validator) public view returns (uint256) {
Validator storage validator = validators[_validator];
Delegation storage delegation = delegations[_account][_validator];
if (delegation.stake == 0) {
return 0;
}
uint256 blocksSinceLastReward = block.number.sub(delegation.lastRewardBlock);
uint256 totalRewards = blocksSinceLastReward.mul(rewardPerBlock);
uint256 validatorShare = totalRewards.mul(config.validatorCommission).div(100);
uint256 delegatorShare = totalRewards.sub(validatorShare);
return delegatorShare.mul(delegation.stake).div(validator.delegatedStake);
}
/**
* @dev Claim rewards
*/
function claimRewards(address _validator) external nonReentrant {
require(validators[_validator].isActive, "Validator not active");
uint256 rewards = calculateRewards(msg.sender, _validator);
require(rewards > 0, "No rewards to claim");
delegations[msg.sender][_validator].lastRewardBlock = block.number;
delegations[msg.sender][_validator].rewards = delegations[msg.sender][_validator].rewards.add(rewards);
stakingToken.safeTransfer(msg.sender, rewards);
emit RewardsClaimed(msg.sender, rewards);
}
/**
* @dev Batch claim rewards
*/
function batchClaimRewards(address[] calldata _validators) external nonReentrant {
uint256 totalRewards = 0;
for (uint256 i = 0; i < _validators.length; i++) {
address validator = _validators[i];
if (validators[validator].isActive) {
uint256 rewards = calculateRewards(msg.sender, validator);
if (rewards > 0) {
delegations[msg.sender][validator].lastRewardBlock = block.number;
delegations[msg.sender][validator].rewards = delegations[msg.sender][validator].rewards.add(rewards);
totalRewards = totalRewards.add(rewards);
}
}
}
require(totalRewards > 0, "No rewards to claim");
stakingToken.safeTransfer(msg.sender, totalRewards);
emit RewardsClaimed(msg.sender, totalRewards);
}
/**
* @dev Slash validator
*/
function slashValidator(address _validator) external onlyOwner {
require(validators[_validator].isActive, "Validator not active");
require(!validators[_validator].isJailed, "Already jailed");
uint256 slashAmount = validators[_validator].stake.mul(config.slashingRate).div(100);
validators[_validator].stake = validators[_validator].stake.sub(slashAmount);
validators[_validator].isJailed = true;
totalStaked = totalStaked.sub(slashAmount);
emit ValidatorSlashed(_validator, slashAmount);
}
/**
* @dev Unjail validator
*/
function unjailValidator(address _validator) external onlyOwner {
require(validators[_validator].isActive, "Validator not active");
require(validators[_validator].isJailed, "Not jailed");
validators[_validator].isJailed = false;
}
/**
* @dev Remove validator
*/
function removeValidator(address _validator) external onlyOwner {
require(validators[_validator].isActive, "Validator not active");
uint256 totalAmount = validators[_validator].stake.add(validators[_validator].delegatedStake);
validators[_validator].isActive = false;
totalStaked = totalStaked.sub(totalAmount);
// Remove validator from validator set
for (uint256 i = 0; i < validatorSet.length; i++) {
if (validatorSet[i] == _validator) {
validatorSet[i] = validatorSet[validatorSet.length - 1];
validatorSet.pop();
break;
}
}
emit ValidatorRemoved(_validator);
}
/**
* @dev Update staking configuration
*/
function updateConfig(
uint256 _minValidatorStake,
uint256 _minDelegationStake,
uint256 _maxValidators,
uint256 _validatorCommission,
uint256 _unbondingTime,
uint256 _slashingRate
) external onlyOwner {
require(_validatorCommission <= 100, "Invalid commission");
require(_slashingRate <= 100, "Invalid slashing rate");
config.minValidatorStake = _minValidatorStake;
config.minDelegationStake = _minDelegationStake;
config.maxValidators = _maxValidators;
config.validatorCommission = _validatorCommission;
config.unbondingTime = _unbondingTime;
config.slashingRate = _slashingRate;
}
/**
* @dev Update reward per block
*/
function updateRewardPerBlock(uint256 _rewardPerBlock) external onlyOwner {
rewardPerBlock = _rewardPerBlock;
}
/**
* @dev Update epoch blocks
*/
function updateEpochBlocks(uint256 _epochBlocks) external onlyOwner {
epochBlocks = _epochBlocks;
}
/**
* @dev Complete epoch
*/
function completeEpoch() external onlyOwner {
epochNumber = epochNumber.add(1);
emit EpochCompleted(epochNumber);
}
/**
* @dev Get validator information
*/
function getValidatorInfo(address _validator) external view returns (
uint256 stake,
uint256 rewards,
uint256 lastRewardBlock,
uint256 delegatedStake,
bool isActive,
bool isJailed
) {
Validator storage validator = validators[_validator];
return (
validator.stake,
validator.rewards,
validator.lastRewardBlock,
validator.delegatedStake,
validator.isActive,
validator.isJailed
);
}
/**
* @dev Get delegation information
*/
function getDelegationInfo(address _delegator, address _validator) external view returns (
uint256 stake,
uint256 rewards,
uint256 lastRewardBlock
) {
Delegation storage delegation = delegations[_delegator][_validator];
return (
delegation.stake,
delegation.rewards,
delegation.lastRewardBlock
);
}
/**
* @dev Get unbonding requests
*/
function getUnbondingRequests(address _account) external view returns (
uint256[] memory amounts,
uint256[] memory completionTimes
) {
UnbondingRequest[] storage requests = unbondingRequests[_account];
amounts = new uint256[](requests.length);
completionTimes = new uint256[](requests.length);
for (uint256 i = 0; i < requests.length; i++) {
amounts[i] = requests[i].amount;
completionTimes[i] = requests[i].completionTime;
}
return (amounts, completionTimes);
}
/**
* @dev Emergency withdraw
*/
function emergencyWithdraw(
address _token,
address _to,
uint256 _amount
) external onlyOwner {
require(_token != address(stakingToken), "Cannot withdraw staking token");
require(_to != address(0), "Invalid recipient");
IERC20(_token).safeTransfer(_to, _amount);
}
}
Key Concepts
Staking Mechanism
The staking system supports:
- Validator staking
- Delegation staking
- Unbonding mechanism
- Reward distribution
Validator Management
Management functions include:
- Registering validators
- Updating stake
- Slashing mechanism
- Unjailing
Delegation Mechanism
Delegation functions include:
- Delegating stake
- Undelegating
- Reward calculation
- Reward claiming
Security Considerations
Staking Security
- Minimum stake limit
- Unbonding delay
- Slashing mechanism
- Permission verification
Reward Security
- Reward calculation
- Distribution rules
- Reward claiming limits
- Inflation control
System Security
- Reentrancy protection
- Permission management
- State checking
- Emergency control
Data Security
- State synchronization
- Data verification
- Error handling
- Event logging
Best Practices
Staking Management
- Reasonable minimum stake
- Appropriate unbonding period
- Fair distribution mechanism
- Effective slashing mechanism
Validator Management
- Strict准入条件
- Thorough monitoring
- Timely punishment measures
- Reasonable exit mechanism
Delegation Management
- Flexible delegation mechanism
- Transparent reward calculation
- Convenient operation process
- Complete information display
System Maintenance
- Regular checks
- Parameter optimization
- Security audits
- Upgrade plans
Extended Features
- Dynamic validator set
- Multi-layer delegation mechanism
- Governance voting weight
- Automatic reinvestment mechanism
- Cross-chain staking
Application Scenarios
Network consensus
- Block validation
- Transaction confirmation
- Network security
- Consensus formation
Governance participation
- Proposal voting
- Parameter adjustment
- Protocol upgrade
- Community decision
Economic incentives
- Staking income
- Inflation distribution
- Ecological construction
- Long-term development
Summary
The proof of stake system is an important component of blockchain networks. Through this tutorial, you can:
- Implement a complete staking mechanism
- Ensure system security
- Optimize user experience
- Promote network development
Frequently Asked Questions (FAQ)
Basic Concepts
Q: What is proof of stake (PoS)?
A: Proof of stake is a consensus mechanism, characterized by:
- Token staking
- Validator election
- Reward distribution
- Slashing mechanism
- Delegation mechanism
Q: What is the difference between a validator and a delegate?
A: The main differences include:
- Validators run nodes, while delegates only need to stake
- Validators need to meet the minimum stake requirements
- Validators bear more responsibility and risks
- Validators can earn commission income
- Delegates have lower thresholds
Operational Related
Q: How to become a validator?
A: The steps to become a validator include:
- Prepare enough staking tokens
- Deploy validator nodes
- Register validator identity
- Wait for activation confirmation
- Start validating work
Q: How to delegate stake?
A: The steps to delegate stake include:
- Select a reliable validator
- Prepare staking tokens
- Authorize contract use
- Execute delegation operation
- Wait for confirmation to take effect
Security Related
Q: What are the risks of PoS systems?
A: The main risks include:
- Validator malicious behavior
- Network attacks
- Token price volatility
- Staking token lock-up
- Slashing losses
Q: How to ensure system security?
A: Security measures include:
- Multi-factor verification
- Slashing mechanism
- Lock period setting
- Equity distribution
- Monitoring and warning
Performance Related
Q: How to optimize system performance?
A: Optimization methods include:
- Batch processing
- State caching
- Gas optimization
- Event optimization
- Load balancing
Q: How to improve user experience?
A: Improvement measures include:
- Clear interface
- Real-time updates
- Error handling
- Status feedback
- Operation guidance
Maintenance Related
Q: How to maintain the system?
A: Maintenance includes:
- Regular monitoring
- Parameter adjustment
- Security audits
- Version upgrades
- Emergency response
Q: How to handle system upgrades?
A: Upgrade strategies include:
- Compatibility testing
- Gradual rollout
- Data migration
- Version control
- Rollback plan
Integration Related
Q: How to integrate with other modules?
A: Integration methods include:
- Standard interfaces
- Event monitoring
- State synchronization
- Data validation
- Error handling
Q: How to implement cross-chain staking?
A: Implementation approaches include:
- Bridge protocols
- Message passing
- State verification
- Asset mapping
- Security measures
System Architecture
1. Core Components
- Staking Module: Manages staking operations
- Validator Module: Manages validators
- Delegation Module: Manages delegations
- Reward Module: Manages rewards
- Security Module: Manages security
2. Process Flow
- Validator registration
- Token staking
- Delegation processing
- Reward calculation
- Unbonding handling
3. State Management
- Validator states
- Delegation records
- Reward distribution
- System parameters
- Security status
4. Security Mechanism
- Access control
- State verification
- Transaction validation
- Emergency handling
- Event logging
Implementation Guidelines
1. Contract Setup
- Initialize parameters
- Set up validators
- Configure rewards
- Implement security
2. Operation Flow
- Request validation
- State updates
- Reward calculation
- Event emission
- Error handling
3. Security Measures
- Input validation
- State checks
- Access control
- Emergency pause
- Event logging
4. Optimization Strategies
- Gas optimization
- Batch processing
- State caching
- Code efficiency
- Performance monitoring
Usage Examples
1. Register Validator
const stake = ethers.utils.parseEther("1000");
await stakingToken.approve(pos.address, stake);
await pos.registerValidator(stake);
2. Delegate Stake
const amount = ethers.utils.parseEther("100");
await stakingToken.approve(pos.address, amount);
await pos.delegate(validator, amount);
3. Claim Rewards
await pos.claimRewards(validator);
4. Undelegate
const amount = ethers.utils.parseEther("50");
await pos.undelegate(validator, amount);
Development Tips
Security First
- Thorough testing
- Security audits
- Error handling
- Access control
- Event logging
Performance Optimization
- Gas efficiency
- Batch processing
- State management
- Code optimization
- Cache usage
User Experience
- Clear interface
- Status feedback
- Error messages
- Operation guidance
- Documentation
Maintenance
- Regular monitoring
- Parameter tuning
- Version control
- Upgrade planning
- Emergency response
Future Extensions
Advanced Features
- Governance integration
- Cross-chain staking
- Advanced rewards
- Dynamic parameters
- Analytics tools
System Upgrades
- Protocol improvements
- Security enhancements
- Performance optimization
- Feature additions
- User experience improvements
Integration Options
- DeFi protocols
- Governance systems
- Cross-chain bridges
- Analytics platforms
- User interfaces