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 interfaceOwnable
: Access control functionalityReentrancyGuardTransient
: 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:
- Disabled: No whitelist restrictions
- Merkle: Requires valid Merkle proof
- TrustedDistributors: Only trusted addresses can stake for others
- 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:
- Staking period validation
- Amount validation (> 0)
- Tier bounds validation
- Pool capacity validation
- Whitelist validation
- 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 functionOwnableInvalidOwner()
: Invalid owner addressOnlyFeeCollector()
: Only fee collector can call function
Validation Errors:
InvalidAddress()
: Zero address providedInvalidAmount()
: Zero amount providedInvalidFeeFunctionsMask()
: Invalid fee functions bitmaskInvalidFeePercentage()
: Fee percentage > BASIS_POINTS
Staking Period Errors:
StakingNotStarted()
: Staking before start dateStakingEnded()
: Staking after end dateStartDateInPast()
: Start date is in the pastInvalidStakingDates()
: Invalid staking date range
Pool Management Errors:
PoolMaxCapExceeded()
: Total pool capacity exceededInvalidPoolMaxCap()
: Invalid pool capacity valueStakingAmountExceedsUpperBound()
: Stake exceeds tier upper boundStakingAmountBelowLowerBound()
: Stake below tier lower bound
Whitelist Errors:
InvalidMerkleRoot()
: Invalid merkle root for whitelist statusInvalidMerkleProof()
: Invalid whitelist proofOnlyTrustedDistributor()
: Only trusted distributor can stake for others
Fee Management Errors:
InsufficientFee()
: Insufficient fee providedFeeTooHigh()
: Fee percentage exceeds maximumInsufficientFeesAvailable()
: 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