Skip to content

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

solidity
// 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

  1. Staking Security

    • Minimum stake limit
    • Unbonding delay
    • Slashing mechanism
    • Permission verification
  2. Reward Security

    • Reward calculation
    • Distribution rules
    • Reward claiming limits
    • Inflation control
  3. System Security

    • Reentrancy protection
    • Permission management
    • State checking
    • Emergency control
  4. Data Security

    • State synchronization
    • Data verification
    • Error handling
    • Event logging

Best Practices

  1. Staking Management

    • Reasonable minimum stake
    • Appropriate unbonding period
    • Fair distribution mechanism
    • Effective slashing mechanism
  2. Validator Management

    • Strict准入条件
    • Thorough monitoring
    • Timely punishment measures
    • Reasonable exit mechanism
  3. Delegation Management

    • Flexible delegation mechanism
    • Transparent reward calculation
    • Convenient operation process
    • Complete information display
  4. System Maintenance

    • Regular checks
    • Parameter optimization
    • Security audits
    • Upgrade plans

Extended Features

  1. Dynamic validator set
  2. Multi-layer delegation mechanism
  3. Governance voting weight
  4. Automatic reinvestment mechanism
  5. Cross-chain staking

Application Scenarios

  1. Network consensus

    • Block validation
    • Transaction confirmation
    • Network security
    • Consensus formation
  2. Governance participation

    • Proposal voting
    • Parameter adjustment
    • Protocol upgrade
    • Community decision
  3. 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

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

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

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

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

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

  1. Validator registration
  2. Token staking
  3. Delegation processing
  4. Reward calculation
  5. 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

javascript
const stake = ethers.utils.parseEther("1000");
await stakingToken.approve(pos.address, stake);
await pos.registerValidator(stake);

2. Delegate Stake

javascript
const amount = ethers.utils.parseEther("100");
await stakingToken.approve(pos.address, amount);
await pos.delegate(validator, amount);

3. Claim Rewards

javascript
await pos.claimRewards(validator);

4. Undelegate

javascript
const amount = ethers.utils.parseEther("50");
await pos.undelegate(validator, amount);

Development Tips

  1. Security First

    • Thorough testing
    • Security audits
    • Error handling
    • Access control
    • Event logging
  2. Performance Optimization

    • Gas efficiency
    • Batch processing
    • State management
    • Code optimization
    • Cache usage
  3. User Experience

    • Clear interface
    • Status feedback
    • Error messages
    • Operation guidance
    • Documentation
  4. Maintenance

    • Regular monitoring
    • Parameter tuning
    • Version control
    • Upgrade planning
    • Emergency response

Future Extensions

  1. Advanced Features

    • Governance integration
    • Cross-chain staking
    • Advanced rewards
    • Dynamic parameters
    • Analytics tools
  2. System Upgrades

    • Protocol improvements
    • Security enhancements
    • Performance optimization
    • Feature additions
    • User experience improvements
  3. Integration Options

    • DeFi protocols
    • Governance systems
    • Cross-chain bridges
    • Analytics platforms
    • User interfaces

Released under the MIT License by Vogeb.