WENBlocks
  • Getting Started
    • Overview
      • Technical Architecture
    • Key Features
  • Staking
    • Overview
    • Creating a Stake
    • Withdrawing the Stake
    • Claiming Rewards
  • Liquidity Program
    • How It Works
  • WNT
    • WNT — The Engine of the WEN Ecosystem
  • Airdrops
    • Airdrop Schedule
    • Server Management
    • Penalty Structure
    • How It Works
    • Example
  • Smart Contracts
  • Security
    • Overview
    • Internal Audits
    • External Audits
    • AI Audits
      • Grok
  • CODE
    • WENBlocksManager.sol
    • wnmContract.sol
    • wblkToken.sol
    • wuniContract.sol
    • wntToken.sol
    • syncnode.py
    • airdropGenerator.js
    • dayTrigger.js
  • Conclusion
    • Conclusion
  • Socials
    • Links
Powered by GitBook
On this page
  • The Withdrawal Process
  • Withdrawal Requirements
  • What Happens During Withdrawal
  • Reward Calculation
  • Example
  • Viewing Your Stakes
  1. Staking

Withdrawing the Stake

PreviousCreating a StakeNextClaiming Rewards

Last updated 1 month ago

Once a stake has matured (reached the end of its staking period), users can withdraw their WNM tokens along with any accumulated rewards (WNM, W.BLK, WUNI AND WNT) through the withdrawStake function.

The Withdrawal Process

The WNMToken contract provides a withdrawal function that allows users to claim both their original staked WNM and all accumulated rewards:

function withdrawStake(uint256 amount, uint256 stake_index) public nonReentrant {
    (uint256 wnmamount, uint256 wntamount, uint256 wblkamount, uint256 wuniamount) = _withdrawStake(amount, stake_index);
    // Return staked tokens to user
    _mint(msg.sender, wnmamount);
    wntContract.mint(msg.sender, wntamount);
    wblkContract.mint(msg.sender, wblkamount);
    wuniContract.mint(msg.sender, wuniamount);
}

This function calls the internal _withdrawStake function which handles the validation and reward calculations:

function _withdrawStake(uint256 _amount, uint256 index) internal returns (uint256, uint256, uint256, uint256) {
    // Grab user_index which is the index to use to grab the Stake[])
    uint256 user_index = stakes[msg.sender];
    Stake memory current_stake = stakeholders[user_index].address_stakes[index];
    uint256 stakeEndDay = current_stake.endDay;
    require(current_stake.amount > 0, "Stake already withdrawn or invalid");
    require(_amount == 0 || _amount == current_stake.amount);
    require(current_stake.user == msg.sender);
    (uint256 wntrewards, uint256 wnmrewards, uint256 wblkrewards, uint256 wunirewards) = calculateStakeRewards(current_stake);
    uint256 sharesFee;
    uint256 wblkBalance;

    if (_amount != 0) {
        require(currentDay >= stakeEndDay, "Stake is not mature yet.");
        totalwshares -= current_stake.wShares;
        current_stake.amount = 0;
        totalStaked -= _amount;
        wblkBalance = current_stake.wblkamount;
        _removeFutureExpiringShares(current_stake.endDay, current_stake.wShares);
    }

    // Additional code for early withdrawal (not covered in this page)
    // ...

    // If stake is empty, 0, then remove it from the array of stakes
    if (current_stake.amount == 0) {
        delete stakeholders[user_index].address_stakes[index];
    } else {
        // Stake update code for partial withdrawals
        // ...
    }
    return (_amount + wnmrewards, wntrewards, wblkrewards + wblkBalance, wunirewards);
}

Withdrawal Requirements

To successfully withdraw a matured stake:

  1. The stake must exist and have a positive amount (current_stake.amount > 0)

  2. The stake must have matured (currentDay >= stakeEndDay)

  3. The withdrawal amount must match the original stake amount (_amount == current_stake.amount)

  4. The caller must be the original staker (current_stake.user == msg.sender)

What Happens During Withdrawal

When a user withdraws a matured stake, the following actions occur:

  1. Reward Calculation: All accumulated rewards (WNT, WNM, WBLK, WUNI) are calculated for the entire staking period using the calculateStakeRewards function.

  2. wShares Removal: The wShares associated with the stake are deducted from the total wShares pool (totalwshares -= current_stake.wShares).

  3. Stake Clearance: The stake amount is set to 0 (current_stake.amount = 0) and the stake is removed from the stakeholder's array.

  4. Token Minting: New tokens are minted to the user:

    • The original WNM amount plus any WNM rewards

    • Earned WNT rewards

    • The original WBLK amount (that was committed with the stake) plus any WBLK rewards

    • Earned WUNI rewards

  5. Accounting Update: The total staked amount is reduced (totalStaked -= _amount) and future expiring shares are removed (_removeFutureExpiringShares).

Reward Calculation

The rewards are calculated based on the stake's wShares and the daily distribution of rewards:

function calculateStakeRewards(Stake memory _current_stake) internal view returns (uint256 _wntrewards, uint256 _wnmrewards, uint256 _wblkrewards, uint256 _wunirewards) {
    uint256 _startDay = _current_stake.startDay;
    uint256 _endDay = _current_stake.endDay;
    
    if (_startDay == currentDay || _current_stake.amount == 0) {
        return (0, 0, 0, 0);
    }

    uint256 _lastDay = _endDay > currentDay ? currentDay : _endDay;
    uint256 _wShares = _current_stake.wShares;

    for (uint256 _day = _startDay; _day < _lastDay; _day++) {
        StakingInfo storage info = stinfo[_day];
        if (info.inflationAmount > 0) {
            _wntrewards += (_wShares * PRECISION_RATE) / info.inflationAmount;
        }
        if (info.wnmAmount > 0) {
            _wnmrewards += (_wShares * PRECISION_RATE) / info.wnmAmount;
        }
        if (info.wblkAmount > 0) {
            _wblkrewards += (_wShares * PRECISION_RATE) / info.wblkAmount;
        }
        if (info.wuniAmount > 0) {
            _wunirewards += (_wShares * PRECISION_RATE) / info.wuniAmount;
        }
    }

    return (_wntrewards, _wnmrewards, _wblkrewards, _wunirewards);
}

For each day the stake was active, the user's proportion of the daily rewards is calculated based on their wShares relative to the total wShares on that day.

Example

Imagine a user has the following stake:

  • 100 WNM staked for 365 days

  • 50 WBLK committed

  • 2.625e18 wShares (calculated based on multipliers)

  • Stake mature after 365 days

When they withdraw after the stake has matured (day 366):

  1. The system calculates all rewards accumulated over the 365 days

  2. The user receives:

    • Their original 100 WNM plus any WNM rewards earned from penalties

    • WNT rewards calculated from daily inflation (from the 25,000 WNT daily distribution)

    • Their original 50 WBLK plus any WBLK rewards earned from penalties

    • Any WUNI rewards earned from penalties

  3. Their wShares (2.625e18) are removed from the total wShares pool

  4. The stake is cleared from the system

Viewing Your Stakes

Users can view their active stakes and pending rewards using the hasStake function:

function hasStake(address _staker) public view returns (StakingSummary memory) {
    // totalStakeAmount is used to count total staked amount of the address
    uint256 totalStakeAmount;
    // Keep a summary in memory since we need to calculate this
    StakingSummary memory summary = StakingSummary(0, stakeholders[stakes[_staker]].address_stakes);
    // Iterate all stakes and grab amount of stakes
    for (uint256 s = 0; s < summary.stakes.length; s += 1) {
        if (summary.stakes[s].amount > 0) {
            (uint256 wntrewards, uint256 wnmrewards, uint256 wblkrewards, uint256 wunirewards) = calculateStakeRewards(summary.stakes[s]);
            summary.stakes[s].claimableWNT = wntrewards;
            summary.stakes[s].claimableWNM = wnmrewards;
            summary.stakes[s].claimableWBLK = wblkrewards;
            summary.stakes[s].claimableWUNI = wunirewards;
            totalStakeAmount = totalStakeAmount + summary.stakes[s].amount;
        }
    }
    // Assign calculate amount to summary
    summary.total_amount = totalStakeAmount;
    return summary;
}

This function returns a comprehensive overview of all the user's stakes including:

  • Total staked amount

  • Individual stake details

  • Pending rewards for each stake

This information can help users decide when to withdraw mature stakes to maximize their rewards.

Example:

  • User stakes 100 WNM for 730 days and receives wShares.

  • After 730 days, they withdraw their 100 WNM along with the rewards earned in WNM, WBLK, WUNI, and WNT.

Users cannot close their stake until it is mature.