Skip to main content

UnbondingStakingFactory

Overview

The UnbondingStakingFactory contract deploys staking contracts with built-in unbonding periods. These contracts implement a two-phase withdrawal process where users must initiate unbonding and wait for a specified period before completing withdrawals.

Contract Specification

contract UnbondingStakingFactory is IUnbondingStakingFactory, FactoryFeeManager

Inheritance:

  • IUnbondingStakingFactory: Unbonding factory interface specification
  • FactoryFeeManager: Fee management functionality

Constructor

constructor(
address feeCollector_,
uint256 defaultGasFee_,
uint256 defaultTokenFee_,
uint8 defaultFeeFunctions_
) FactoryFeeManager(feeCollector_, defaultGasFee_, defaultTokenFee_, defaultFeeFunctions_)

Parameters:

  • feeCollector_: Address designated to receive collected fees
  • defaultGasFee_: Default gas fee amount in wei
  • defaultTokenFee_: Default token fee in basis points (1-10000)
  • defaultFeeFunctions_: Bitmask defining which functions have fees applied

Requirements:

  • feeCollector_ must not be zero address
  • defaultFeeFunctions_ must be ≤ 7 (valid bitmask)

Functions

newStakingWithUnbonding

function newStakingWithUnbonding(UnbondingStakingParams calldata params) external returns (address)

Deploys a new StakingWithUnbonding contract instance with the provided parameters.

Parameters:

struct UnbondingStakingParams {
bytes32 merkleRoot; // Merkle root for whitelist verification
ITypes.WhitelistStatus whitelistStatus; // Whitelist configuration mode
address stakingToken; // ERC20 token contract address
uint256 poolMaxCap; // Maximum total tokens stakeable
uint256 tierUpperBound; // Maximum tokens per individual staker
uint256 tierLowerBound; // Minimum tokens per individual staker
uint64 unbondingPeriod; // Unbonding period duration in seconds
uint64 maxStakeDuration; // Maximum duration for reward accrual in seconds
uint64 apyPercentage; // Annual percentage yield in basis points
uint80 startStakingDate; // Staking operations start timestamp
uint80 endStakingDate; // Staking operations end timestamp
}

Returns:

  • Address of the newly deployed staking contract

Fee Application: The factory applies fees based on the caller's configuration:

  • If custom fees are set for the caller, those are used
  • Otherwise, default factory fees are applied

Events Emitted:

event StakingWithUnbondingCreated(
address indexed stakingContract,
bytes32 merkleRoot,
address token,
ITypes.FeeType feeType,
uint256 fee,
uint8 feeFunctions
);

Parameter Validation

The factory validates deployment parameters:

Whitelist Configuration:

  • If whitelistStatus is Merkle or MerkleAndTrustedDistributors, merkleRoot must be non-zero
  • If whitelistStatus is Disabled or TrustedDistributors, merkleRoot must be zero

Token Configuration:

  • stakingToken must be a valid ERC20 contract address
  • Cannot be zero address

Time Configuration:

  • startStakingDate must be in the future
  • endStakingDate must be after startStakingDate
  • maxStakeDuration must be > 0
  • unbondingPeriod must be ≤ MAX_UNBONDING_PERIOD (5 years)

Tier Configuration:

  • tierLowerBound must be ≤ tierUpperBound
  • Both bounds must be > 0

APY Configuration:

  • apyPercentage is in basis points (1-10000)
  • Represents annual percentage yield for reward calculations

Unbonding Mechanism

Two-Phase Withdrawal Process:

  1. Initiate Unbonding: User calls initiateUnbonding(amount)

    • Tokens move from staked to unbonding state
    • Unbonding timestamp is recorded
    • Rewards stop accruing for unbonded tokens
  2. Complete Unbonding: User calls completeUnbonding() after period expires

    • Tokens are transferred from contract to user
    • Fee is applied if configured

Unbonding Period Options:

  • 0: Immediate withdrawal (no unbonding delay)
  • > 0: Delay period in seconds before withdrawal can complete
  • Maximum: MAX_UNBONDING_PERIOD (1,825 days / 5 years)

Reward Calculation

UnbondingStakingWithUnbonding uses fixed APY-based rewards:

Formula:

reward = (stakedAmount × timeStaked × apyPercentage) / (365 days × BASIS_POINTS)

Key Characteristics:

  • Rewards accrue from staking timestamp to current time
  • Rewards are capped at maxStakeDuration from first stake time
  • No rewards accrue on tokens in unbonding state
  • APY is fixed per contract deployment (immutable)

Maximum Stake Duration: Rewards stop accruing after the maximum stake duration:

maxEndTime = timeOfFirstStake + maxStakeDuration
if (currentTime > maxEndTime) {
currentTime = maxEndTime; // Cap for reward calculation
}

Fee Management Integration

The factory integrates with the FactoryFeeManager system:

Default Fees: Applied to all deployments unless overridden by custom fees.

Custom Fees: Set per campaign creator address with specific fee types and amounts.

Fee Functions: Bitmask determines which contract functions have fees applied:

  • Bit 0 (1): Stake functions
  • Bit 1 (2): Withdraw/complete unbonding functions
  • Bit 2 (4): Claim functions

Deployed Contract Configuration

Each deployed staking contract receives:

Immutable Parameters:

  • Staking token address
  • Fee type and amount
  • Fee collector address
  • Fee functions bitmask
  • Tier bounds
  • Staking date range
  • Unbonding period
  • Maximum stake duration
  • APY percentage

Configurable Parameters:

  • Pool maximum capacity
  • Whitelist status and merkle root
  • Unbonding period (owner-controlled)

Contract State Management

Staker Information:

struct UnbondingStaker {
uint256 amountStaked; // Currently staked tokens
uint256 unclaimedRewards; // Accumulated unclaimed rewards
uint128 timeOfFirstStake; // Timestamp of first stake
uint128 timeOfLastUpdate; // Last reward update timestamp
uint128 unbondingTimestamp; // When unbonding was initiated
uint256 unbondingAmount; // Amount currently unbonding
uint64 stakersArrayIndex; // Index in stakers array
}

State Transitions:

  1. Initial: No tokens staked
  2. Staking: Tokens actively earning rewards
  3. Unbonding: Tokens waiting for unbonding period completion
  4. Withdrawn: Tokens removed from contract

Error Conditions

The factory may revert with these errors:

From StakingErrors:

  • InvalidAddress(): Zero address provided
  • InvalidFeeFunctionsMask(): Invalid fee functions bitmask
  • InvalidTierBounds(): Invalid tier bound configuration
  • InvalidStakingDates(): Invalid staking date range
  • StartDateInPast(): Start date is in the past
  • InvalidMerkleRoot(): Invalid merkle root for whitelist status
  • InvalidFeePercentage(): Fee percentage > BASIS_POINTS
  • InvalidMaxStakeDuration(): maxStakeDuration is zero
  • InvalidUnbondingPeriod(): unbondingPeriod > MAX_UNBONDING_PERIOD

From FactoryFeeManager:

  • FeeTooHigh(): Token fee > BASIS_POINTS
  • CustomFeeNotSet(): Attempting to use non-existent custom fee

Constants

uint64 public constant MAX_UNBONDING_PERIOD = 365 days * 5; // 5 years maximum
uint256 public constant BASIS_POINTS = 10_000; // 100% = 10,000 basis points