Skip to main content

StakingBase

Overview

StakingBase is the foundational abstract contract that provides core functionality for all staking contracts in the system. It implements common features including fee management, whitelist controls, reward funding, and administrative functions, allowing derived contracts to focus on their specific staking logic.

Contract Specification

abstract contract StakingBase is IStakingBase, Ownable, ReentrancyGuardTransient

Inheritance:

  • IStakingBase: Base staking interface
  • Ownable: Access control functionality
  • ReentrancyGuardTransient: Gas-efficient reentrancy protection

Inheritance Pattern:

StakingBase (Abstract)
├── Staking (Basic staking implementation)
└── StakingWithUnbonding (Unbonding staking implementation)

Data Structures

BaseParams

struct BaseParams {
address stakingToken; // ERC20 token to be staked
bytes32 merkleRoot; // Merkle root for whitelist
ITypes.WhitelistStatus whitelistStatus; // Whitelist configuration
uint256 tierLowerBound; // Minimum stake amount
uint256 tierUpperBound; // Maximum stake amount
uint80 startStakingDate; // When staking begins
uint80 endStakingDate; // When staking ends
uint256 poolMaxCap; // Maximum total pool capacity
ITypes.FeeType feeType; // Gas or Token fee type
uint256 fee; // Fee amount/percentage
address feeCollector; // Address to receive fees
uint8 feeFunctions; // Bitmask for fee-enabled functions
address owner; // Contract owner address
}

State Variables

Constants

uint256 public constant BASIS_POINTS = 10_000;     // 100% = 10,000 basis points

Immutable Parameters

address public immutable STAKING_TOKEN;            // Token being staked
uint256 public immutable TIER_UPPER_BOUND; // Max stake per user
uint256 public immutable TIER_LOWER_BOUND; // Min stake per user
uint80 public immutable START_STAKING_DATE; // Staking start time
uint80 public immutable END_STAKING_DATE; // Staking end time
ITypes.FeeType public immutable FEE_TYPE; // Fee payment method
uint256 public immutable FEE; // Fee amount
uint8 public immutable FEES_FUNCTIONS; // Fee function bitmask

Pool Management

uint256 public stakingTokenBalance;    // Total tokens staked in pool
uint256 public poolMaxCap; // Maximum pool capacity
address[] public stakersArray; // List of all stakers

Rewards Management

uint256 public rewardsAvailable;       // Tokens available for rewards
uint256 public numTokenReservedForFee; // Tokens reserved for fees

Access Control

address public feeCollector;           // Fee collection address
mapping(address => bool) public trustedDistributors; // Authorized distributors

Whitelist Management

bytes32 public merkleRoot;             // Merkle root for whitelist
ITypes.WhitelistStatus public whitelistStatus; // Current whitelist mode

Core Functions

Reward Management

fundStakingContract

function fundStakingContract(uint256 _amount) external onlyOwner

Funds the contract with tokens for reward distribution.

Parameters:

  • _amount: Amount of tokens to add to rewards pool

Requirements:

  • Only contract owner
  • Amount must be > 0
  • Caller must approve tokens first

Events: ContractFunded(address indexed funder, uint256 amount)

withdrawExcessRewards

function withdrawExcessRewards(uint256 _amount, address _recipient, bool _fromExcessTokens) external onlyOwner

Withdraws excess rewards or accidentally sent tokens.

Parameters:

  • _amount: Amount to withdraw
  • _recipient: Address to receive tokens
  • _fromExcessTokens: If true, withdraws excess tokens; if false, withdraws from rewards

Requirements:

  • Only contract owner
  • Amount must be > 0
  • Recipient cannot be zero address

Events: ExcessRewardsWithdrawn(address indexed admin, uint256 amount, bool fromExcessTokens)

Whitelist Management

setWhitelistStatus

function setWhitelistStatus(ITypes.WhitelistStatus _status, bytes32 _merkleRoot) external onlyOwner

Updates whitelist configuration.

Parameters:

  • _status: New whitelist status
  • _merkleRoot: Merkle root (required for Merkle-based whitelist)

Requirements:

  • Only contract owner
  • Valid merkle root for merkle-based whitelist

Events: WhitelistStatusUpdated(ITypes.WhitelistStatus oldStatus, ITypes.WhitelistStatus newStatus, bytes32 merkleRoot)

Whitelist Status Options:

  1. Disabled: No whitelist restrictions
  2. Merkle: Requires valid Merkle proof
  3. TrustedDistributors: Only trusted addresses can stake for others
  4. MerkleAndTrustedDistributors: Combines both methods

setBatchTrustedDistributors

function setBatchTrustedDistributors(address[] calldata distributors) external onlyOwner

Adds multiple trusted distributors.

Parameters:

  • distributors: Array of distributor addresses

Requirements:

  • Only contract owner
  • Non-empty array
  • No zero addresses

Events: TrustedDistributorUpdated(address distributor, bool status) for each distributor

removeTrustedDistributor

function removeTrustedDistributor(address distributor) external onlyOwner

Removes a trusted distributor.

Parameters:

  • distributor: Address to remove

Requirements:

  • Only contract owner
  • Address must not be zero

Events: TrustedDistributorUpdated(address distributor, bool status)

Pool Capacity Management

updatePoolMaxCap

function updatePoolMaxCap(uint256 _newPoolMaxCap) external onlyOwner

Updates the maximum pool capacity.

Parameters:

  • _newPoolMaxCap: New maximum capacity

Requirements:

  • Only contract owner
  • New cap must be ≥ current staked amount

Events: PoolMaxCapUpdated(uint256 oldPoolMaxCap, uint256 newPoolMaxCap)

Fee Management

withdrawTokenFee

function withdrawTokenFee(address _recipient, uint256 _amount) external

Withdraws collected token fees.

Parameters:

  • _recipient: Address to receive fees
  • _amount: Amount to withdraw (0 = withdraw all)

Requirements:

  • Only fee collector
  • Recipient cannot be zero address

Events: TokenFeeWithdrawn(address indexed recipient, uint256 amount)

setFeeCollector

function setFeeCollector(address _newFeeCollector) external onlyOwner

Updates the fee collector address.

Parameters:

  • _newFeeCollector: New fee collector address

Requirements:

  • Only contract owner
  • Address cannot be zero

Events: FeeCollectorUpdated(address indexed oldFeeCollector, address indexed newFeeCollector)

View Functions

Staking Information

stakingSettings

function stakingSettings() external view returns (StakingSettings memory)

Returns comprehensive staking contract configuration.

Returns:

struct StakingSettings {
address stakingToken;
uint256 tierLowerBound;
uint256 tierUpperBound;
uint80 startStakingDate;
uint80 endStakingDate;
uint256 poolMaxCap;
ITypes.FeeType feeType;
uint256 fee;
address feeCollector;
uint8 feeFunctions;
bytes32 merkleRoot;
ITypes.WhitelistStatus whitelistStatus;
}

getStakersArray

function getStakersArray() external view returns (address[] memory)

Returns the complete array of staker addresses.

getStakersArrayLength

function getStakersArrayLength() external view returns (uint256)

Returns the number of stakers in the array.

Whitelist Verification

isWhitelisted

function isWhitelisted(address _address, bytes32[] calldata _merkleProof) external view returns (bool)

Verifies if an address is whitelisted using Merkle proof.

Parameters:

  • _address: Address to verify
  • _merkleProof: Merkle proof for verification

Returns:

  • Boolean indicating if address is whitelisted

checkWhitelistStatus

function checkWhitelistStatus(address _staker, address _receiver, bytes32[] calldata _merkleProof) external view returns (bool)

Comprehensive whitelist status check for staking operations.

Parameters:

  • _staker: Address initiating the stake
  • _receiver: Address receiving the staked tokens
  • _merkleProof: Merkle proof for verification

Returns:

  • Boolean indicating if the staking operation is allowed

Internal Functions

Staking Core Logic

_stake

function _stake(uint256 _amount, address _receiver, address _staker, bytes32[] calldata _merkleProof) internal virtual

Core staking logic with comprehensive validation.

Parameters:

  • _amount: Amount of tokens to stake
  • _receiver: Address receiving the staked tokens
  • _staker: Address providing the tokens
  • _merkleProof: Merkle proof for whitelist verification

Validations:

  1. Staking period validation
  2. Amount validation (> 0)
  3. Tier bounds validation
  4. Pool capacity validation
  5. Whitelist validation
  6. Fee collection

_beforeTokenTransfer

function _beforeTokenTransfer(address _from, address _to, uint256 _amount) internal virtual

Hook called before token transfers for additional validation.

_afterTokenTransfer

function _afterTokenTransfer(address _from, address _to, uint256 _amount) internal virtual

Hook called after token transfers for cleanup operations.

Fee System

Fee Types

enum FeeType {
Gas, // Fixed ETH amount per transaction
DistributionToken // Percentage of tokens being operated on
}

Fee Functions Bitmask

uint8 constant FEE_ON_STAKE = 1;     // Bit 0: Fee on staking
uint8 constant FEE_ON_WITHDRAW = 2; // Bit 1: Fee on withdrawal
uint8 constant FEE_ON_CLAIM = 4; // Bit 2: Fee on claiming

Fee Calculation

Gas Fees:

  • Fixed ETH amount charged per transaction
  • Collected immediately during function execution
  • Sent directly to fee collector

Token Fees:

  • Percentage of tokens being operated on
  • Calculated as: (amount * fee) / BASIS_POINTS
  • Deducted from token amounts and reserved for withdrawal

Modifiers

Access Control

modifier onlyOwner()

Restricts function access to contract owner only.

modifier onlyFeeCollector()

Restricts function access to fee collector only.

Validation

modifier nonZeroAmount(uint256 _amount)

Validates that amount is greater than zero.

modifier validAddress(address _address)

Validates that address is not zero address.

Staking Period

modifier onlyDuringStakingPeriod()

Validates that current time is within staking period.

modifier onlyAfterStakingPeriod()

Validates that current time is after staking period.

Error Conditions

Access Control Errors:

  • OwnableUnauthorizedAccount(): Unauthorized access to owner function
  • OwnableInvalidOwner(): Invalid owner address
  • OnlyFeeCollector(): Only fee collector can call function

Validation Errors:

  • InvalidAddress(): Zero address provided
  • InvalidAmount(): Zero amount provided
  • InvalidFeeFunctionsMask(): Invalid fee functions bitmask
  • InvalidFeePercentage(): Fee percentage > BASIS_POINTS

Staking Period Errors:

  • StakingNotStarted(): Staking before start date
  • StakingEnded(): Staking after end date
  • StartDateInPast(): Start date is in the past
  • InvalidStakingDates(): Invalid staking date range

Pool Management Errors:

  • PoolMaxCapExceeded(): Total pool capacity exceeded
  • InvalidPoolMaxCap(): Invalid pool capacity value
  • StakingAmountExceedsUpperBound(): Stake exceeds tier upper bound
  • StakingAmountBelowLowerBound(): Stake below tier lower bound

Whitelist Errors:

  • InvalidMerkleRoot(): Invalid merkle root for whitelist status
  • InvalidMerkleProof(): Invalid whitelist proof
  • OnlyTrustedDistributor(): Only trusted distributor can stake for others

Fee Management Errors:

  • InsufficientFee(): Insufficient fee provided
  • FeeTooHigh(): Fee percentage exceeds maximum
  • InsufficientFeesAvailable(): Not enough fees available for withdrawal

Events

Staking Events

event TokensStaked(address indexed staker, uint256 amount, uint256 feeAmount);
event TokensWithdrawn(address indexed staker, uint256 amount, uint256 feeAmount);
event RewardsClaimed(address indexed staker, uint256 rewardAmount, uint256 feeAmount);

Administrative Events

event ContractFunded(address indexed funder, uint256 amount);
event ExcessRewardsWithdrawn(address indexed admin, uint256 amount, bool fromExcessTokens);
event PoolMaxCapUpdated(uint256 oldPoolMaxCap, uint256 newPoolMaxCap);
event FeeCollectorUpdated(address indexed oldFeeCollector, address indexed newFeeCollector);
event TokenFeeWithdrawn(address indexed recipient, uint256 amount);

Whitelist Events

event WhitelistStatusUpdated(ITypes.WhitelistStatus oldStatus, ITypes.WhitelistStatus newStatus, bytes32 merkleRoot);
event TrustedDistributorUpdated(address distributor, bool status);

Security Features

Reentrancy Protection

Uses ReentrancyGuardTransient for gas-efficient reentrancy protection on all state-changing functions.

Input Validation

Comprehensive validation of all inputs including:

  • Zero address checks
  • Zero amount checks
  • Range validation for percentages
  • Time validation for staking periods

Access Control

Role-based access control with:

  • Owner privileges for configuration changes
  • Fee collector privileges for fee withdrawal
  • Trusted distributor privileges for staking on behalf of others

Overflow Protection

Uses Solidity 0.8+ built-in overflow protection for all arithmetic operations.

Inherited Functionality

StakingBase provides the following functionality to derived contracts:

Core Operations:

  • Token staking with validation
  • Fee collection and management
  • Whitelist verification
  • Pool capacity management

Administrative Functions:

  • Reward funding and withdrawal
  • Configuration updates
  • Fee collector management
  • Trusted distributor management

Security Features:

  • Reentrancy protection
  • Access control
  • Input validation
  • Event emission