NGOLis

The NGOLis contract manages staking and withdrawal functionalities for Non-Governmental Organizations (NGOs). It enables users to stake ETH, stETH, or wstETH while allocating a portion to NGO operations. The contract interacts with the Lido Finance protocol for staking and the withdrawal queue for managing withdrawals. It incorporates percentage-based sharing mechanisms, reward distributions, and comprehensive security controls. It includes various functions and modifiers to manage NGO operations, such as creating and updating NGO details, handling donations, and ensuring compliance with specific rules. The notBanned modifier is used to restrict access to stake, ensuring that only non-banned entities can stake while everyone can withdraw their staked funds. Supports staking and withdrawal support for ETH, stETH, wstETH tokens.

Contract Architecture

Upgrade Mechanism

The contract implements the UUPS (Universal Upgradeable Proxy Standard) pattern:

  • Uses OpenZeppelin's UUPSUpgradeable framework

  • Upgrades are controlled through the _authorizeUpgrade function

  • Only the contract owner can initiate upgrades

  • State variables are preserved during upgrades through proxy delegation

Upgrade Control

The upgrade process is controlled through two main components:

  1. Authorization Function

function _authorizeUpgrade(address newImplementation) internal override onlyOwner

Authorizes contract upgrades in the UUPS pattern.

Access Control:

  • Restricted to contract owner

Parameters:

  • newImplementation: Address of new implementation contract

Security Considerations:

  • Critical function for contract upgradeability

  • Must be called through proxy

  • Requires careful implementation validation

  • Should maintain contract invariants

Usage:

  • Part of upgrade process

  • Called automatically by upgrade mechanism

  • Validates upgrade permissions

  1. Proxy Pattern

  • Uses ERC1967 proxy standard

  • Maintains separation of concerns

  • Preserves contract state

Upgrade Process

  1. Owner initiates upgrade with new implementation

  2. _authorizeUpgrade validates permission

  3. Proxy updates implementation pointer

  4. State remains intact in proxy storage

Core Logic and Operations

Staking Mechanism

  1. Percentage Calculation

    • NGO share percentage uses a base of 10000 for precise calculations

    • 100% = 10000 and 1% = 100

    • Valid range: MIN_SHARE_PERCENT (100 = 1%) to MAX_SHARE_PERCENT (10000 = 100%)

    • Example: 5000 represents 50% share to NGO

  2. Minimum Stake Requirements

    • Minimum stake amount: 1000 wei (defined by MIN_AMOUNT constant)

    • All stake operations require user not to be banned

    • Stakes cannot be made after NGO is marked as finished

  3. Asset Distribution

    • User portion: (100% - NGO percentage) of staked amount

    • NGO portion: NGO percentage of staked amount

    • Rewards are calculated based on the User portion and donations on NGO portion

  4. Token Support

    • Native ETH (stake)

    • Liquid staked ETH (stakeStEth)

    • Wrapped staked ETH (stakeWStEth)

Reward Management

  1. Reward Calculation

    • Rewards tracked through lastNGOBalance

    • pendingRewardsCalculation() updates pending rewards by:

      • Converting current NGO assets to stETH value

      • Comparing with last recorded balance

      • Converting difference to wstETH

      • Adding to pendingNGORewards

  2. Reward Distribution

    • Handled by oracle through handleNGOShareDistribution

      • Calculate pending rewards

      • Take platform fee (5% - LIS_FEE)

      • Transfer fee to platform address

      • Transfer remaining rewards to rewardsOwner

      • Update lastNGOBalance

Withdrawal System

  1. Request Process

    • Users initiate withdrawals through requestWithdrawals

    • Amount constraints:

      • Minimum: Set by Lido withdrawal queue

      • Maximum: Set by Lido withdrawal queue

      • Cannot exceed user's total balance (direct assets + NGO share)

      • Minimum withdrawal amount: 100 wei (MIN_WITHDRAWAL_AMOUNT)

  2. Withdrawal Methods

    • Queue-based ETH withdrawal

      • Request withdrawal via requestWithdrawals

      • Claim via claimWithdrawal after finalization

      • Requires withdrawal request ID

    • Direct token withdrawal

      • claimWithdrawInStEth: Withdraw in stETH

      • claimWithdrawInWStEth: Withdraw in wstETH

      • No queue waiting period

      • Minimum withdrawal: 100 wei

  3. Asset Recalculation

    • Withdrawals trigger proportional reduction of:

      • User's direct assets

      • NGO shares

      • Total NGO assets

Inheritance Structure

NGOLis is
    Initializable,
    ERC721HolderUpgradeable,
    ReentrancyGuardUpgradeable,
    UUPSUpgradeable,
    OwnableUpgradeable

Sequential Diagram

Contract Storage Structure

State Variables

uint256 private id;                        // Stake ID counter
address private _lis;                      // LIS token address
ILido public lidoSC;                       // Lido protocol interface
IWithdrawalQueue public withdrawalSC;      // Withdrawal queue interface
IWstEth public wstETHSC;                   // Wrapped stETH interface
address public rewardsOwner;               // Rewards recipient
bool public isFinish;                      // NGO status flag
uint256 private pendingNGORewards;         // Storage variable for pending rewards
uint256 totalNGOAssets;                    // Total wstETH with NGO
uint256 totalNGOShares;                    // Total Shares with User
uint256 lastNGOBalance;                    // stETH balance at the time of the last NGO reward distribution

Key Storage Mappings

mapping(address => mapping(uint256 => StakeInfo)) private _userToStakeInfo;
mapping(address => bool) private _oracles;
mapping(uint256 => address) private _requestIdToUser;
mapping(address => mapping(uint256 => uint256)) public ngoShares;
mapping(address => bool) public isBanned;
mapping(address => mapping(uint256 => uint)) public assets;

Important Constants

uint8 constant MIN_SHARE_PERCENT = 100;    // 1%
uint16 constant MAX_SHARE_PERCENT = 10000;  // 100%
uint16 constant PERCENT_DIVIDER = 10000;      // Base for percentage calculations
uint256 constant DIVIDER = 10 * 10 ** 17;      // Precision divider
uint16 constant LIS_FEE = 500;                // 5% platform fee
uint8 constant MIN_WITHDRAWAL_AMOUNT = 100;   // minimum withdrawal amount
uint16 constant MIN_AMOUNT = 1000;            // minimum amount to stake
uint8 constant WITHDRAW_GAP = 100;           //If during withdrawal user's balance < WITHDRAW_GAP

Data Structures

Enums

enum EthType {
    Native,
    StEth,
    WStEth
}

Type of eth in function for event

Structs

struct StakeInfo {
    uint16 percent;    // Share percentage
    uint256 amount;       // Staked amount
    uint256 startDate;    // Timestamp
}

Struct representing initial stake information for a user.

Function Documentation

Initialization

constructor

constructor() {
    _disableInitializers();
}

Disables initializers at deployment.

initialize

function initialize(
    address lidoSCAddress,
    address _rewardOwnerAddress,
    address withdrawalSCAddress,
    address owner,
    address oracle,
    address _wstETHSC
) public initializer

Initializes the NGO contract.

  • Parameters

    • lidoSCAddress: Lido staking contract

    • _rewardOwnerAddress: Rewards recipient

    • withdrawalSCAddress: Withdrawal queue contract

    • owner: NGO owner address

    • oracle: Oracle address

    • _wstETHSC: Wrapped stETH contract

  • Validation

    • No zero addresses allowed

  • Effects

    • Initializes base contracts

    • Sets up initial configuration

Staking Functions

stake

function stake(uint16 _ngoPercent) public payable

Stakes native ETH in the NGO contract.

  • Parameters

    • _ngoPercent: NGO share percentage (100 = 1%, 10000 = 100%)

  • Constraints

    • Must not be banned

    • NGO must not be finished

    • Minimal amount to stake: 1000 wei

    • Percentage must be between MIN_SHARE_PERCENT and MAX_SHARE_PERCENT

stakeStEth

function stakeStEth(uint256 amount, uint16 _ngoPercent) public

Stakes stETH tokens in the NGO contract.

  • Parameters

    • amount: Amount of stETH to stake (in wei)

    • _ngoPercent: NGO share percentage (100 = 1%, 10000 = 100%)

  • Requirements

    • Caller must have approved contract for stETH transfer

    • Same constraints as stake

stakeWStEth

function stakeWStEth(uint256 amount, uint16 _ngoPercent) public

Stakes wstETH tokens directly in the NGO contract.

  • Parameters

    • amount: Amount of wstETH to stake (in wei)

    • _ngoPercent: NGO share percentage (100 = 1%, 10000 = 100%)

  • Requirements

    • User must approve contract for wstETH transfer before calling

    • Directly uses wstETH without wrapping

    • Same constraints as other stake functions

Withdrawal Functions

requestWithdrawals

function requestWithdrawals(uint256 _amount, uint256 _id) public

Initiates a withdrawal request.

  • Parameters

    • _amount: Amount of ETH to withdraw (in wei)

    • _id: Stake identifier

  • Constraints

    • Amount must be within Lido's min/max limits

    • Range: min - 100 wei , max - 1000 ETH

    • Amount cannot exceed user's balance for given stake ID

claimWithdrawal

function claimWithdrawal(uint256 _requestId) public nonReentrant

Claims completed withdrawal request.

  • Parameters

    • _requestId: Withdrawal request identifier

  • Requirements

    • Request must be finalized in Lido queue

    • Caller must be original requester

claimWithdrawInStEth

function claimWithdrawInStEth(uint256 _amount, uint256 _id) public

Claims stETH withdrawal. Note: expected amount to withdraw: min - 100 wei.

  • Parameters

    • _amount: Amount to withdraw

    • _id: Stake identifier

  • Effects

    • Transfers stETH

    • Updates state

claimWithdrawInWStEth

function claimWithdrawInWStEth(uint256 _amount, uint256 _id) public

Claims wstETH withdrawal.

Note: expected amount to withdraw: min - 100 wei.

  • Parameters

    • _amount: Amount to withdraw

    • _id: Stake identifier

  • Effects

    • Transfers wstETH

    • Updates state

withdrawCalculation

function withdrawCalculation(
    uint256 _amount,
    uint256 _id
) private returns (uint256 _amountWstETH)

Internal function for processing withdrawal mathematics.

  • Parameters

    • _amount: Amount to withdraw in stETH

    • _id: Stake identifier

  • Returns

    • _amountWstETH: Converted amount in wstETH

Calculation Steps With Explanation

  1. Calculate User's NGO Share

    _ngoShare = ngoShares[msg.sender][_id]
    • Retrieves the user's share of NGO tokens for the specific stake ID

    • This represents the user's portion of the total NGO shares

  2. Convert NGO Share to Assets

    _ngoAssets = _ngoShare.mulDiv(totalNGOAssets, totalNGOShares)
    • Converts user's NGO shares to actual wstETH tokens

    • Formula: user_ngo_share * total_ngo_assets / total_ngo_shares

    • This determines how many wstETH tokens user's NGO shares represent

  3. Calculate Total User Assets

    _totalUserWstETH = assets[msg.sender][_id] + _ngoAssets
    • Combines user's direct assets and NGO share assets

    • assets[msg.sender][_id]: Direct wstETH holdings

    • _ngoAssets: Converted NGO share in wstETH

    • Represents total user's withdrawable wstETH

  4. Convert Withdrawal Amount to wstETH

    _amountWstETH = wstETHSC.getWstETHByStETH(_amount)
    • Converts requested stETH withdrawal amount to wstETH

    • Uses Lido's conversion rate

    • Necessary because internal accounting uses wstETH

  5. Calculate Withdrawal Ratio

    _ratio = _amountWstETH.mulDiv(DIVIDER, _totalUserWstETH)
    • Determines what fraction of user's total assets is being withdrawn

    • DIVIDER (10 * 10**17) used for precision

    • Formula: (withdrawal_amount * DIVIDER) / total_user_assets

    • This ratio is used to proportionally reduce both direct assets and NGO shares

  • State Updates Based on Calculations

  1. Update User's Direct Assets

    assets[msg.sender][_id] -= _ratio.mulDiv(assets[msg.sender][_id], DIVIDER)
    • Reduces user's direct assets proportionally based on withdrawal ratio

    • Maintains correct balance proportion

  2. Update NGO Assets

    uint256 withdrawnNgoAssets = _ngoAssets.mulDiv(_ratio, DIVIDER)
    totalNGOAssets -= withdrawnNgoAssets
    • Calculates and removes withdrawn portion from NGO assets

    • Maintains NGO asset accounting

  3. Update NGO Shares

    totalNGOShares -= _ngoShare.mulDiv(_ratio, DIVIDER)
    ngoShares[msg.sender][_id] -= _ngoShare.mulDiv(_ratio, DIVIDER)
    • Reduces total NGO shares

    • Updates user's NGO share balance

    • Maintains share proportions

  4. Update NGO Balance

    lastNGOBalance -= wstETHSC.getStETHByWstETH(withdrawnNgoAssets)
    • Updates the tracked stETH balance

    • Used for reward calculations

  • Example Calculation Let's say:

  • User has 100 wstETH direct assets

  • User has NGO shares worth 50 wstETH

  • Total assets = 150 wstETH

  • User wants to withdraw 30 stETH

  1. Convert 30 stETH to wstETH (say 25 wstETH)

  2. Calculate ratio: 25 * DIVIDER / 150 = 0.1667 * DIVIDER

  3. Reduce direct assets: 100 * 0.1667 = -16.67 wstETH

  4. Reduce NGO assets: 50 * 0.1667 = -8.33 wstETH

  5. Final balances:

    • Direct assets: 83.33 wstETH

    • NGO share: 41.67 wstETH

    • Total withdrawn: 25 wstETH

Important Considerations

  1. All calculations maintain proportional relationships

  2. Precision is maintained using DIVIDER

  3. Both user assets and NGO shares are reduced proportionally

  4. Conversion between stETH and wstETH is handled appropriately

This function is critical for maintaining correct balances and proportions during withdrawals while ensuring both user assets and NGO shares are properly accounted for.

Internal Calculation Functions

pendingRewardsCalculation

function pendingRewardsCalculation() private

Calculates and updates pending rewards for the NGO based on asset value changes.

  • Process

    • Converts current NGO assets to stETH value using wstETHSC.getStETHByWstETH()

    • Compares current balance with lastNGOBalance

    • If current balance is higher:

      • Calculates the difference

      • Converts difference to wstETH

      • Adds to pendingNGORewards

      • Reduces totalNGOAssets by the reward amount

  • State Changes

    • Updates pendingNGORewards

    • Modifies totalNGOAssets

  • Usage

    • Called before stake asset calculations

    • Called during withdrawal processing

    • Called during reward distribution

  • Dependencies:

    • Requires wstETHSC interface for token conversions

    • Relies on lastNGOBalance for change detection

assetsCalculation

function assetsCalculation(uint256 _amount, uint16 _percent) private

Calculates and distributes staked assets between user and NGO portions.

  • Parameters:

    • _amount: Amount being staked in wstETH

    • _percent: NGO share percentage (100-10000)

  • Process:

    1. NGO Asset Calculation

      • Calculates NGO portion using percentage

      • Assigns remaining amount to user's direct assets

    2. Share Distribution

      • Creates stake information record

      • Calculates NGO shares based on total assets

    3. State Updates

      • Updates user's asset record

      • Increments total NGO assets

      • Updates share allocations

      • Updates lastNGOBalance

  • State Changes:

    • Updates assets[msg.sender][id]

    • Updates _userToStakeInfo mapping

    • Modifies totalNGOAssets

    • Updates totalNGOShares

    • Updates ngoShares mapping

    • Sets lastNGOBalance

  • Usage:

    • Called by stake()

    • Called by stakeStEth()

    • Called by stakeWStEth()

Administrative Functions

handleNGOShareDistribution

function handleNGOShareDistribution() public onlyOracle

Manages the distribution of NGO rewards.

  • Access Control

    • Only callable by oracle

  • Calculations

    • Converts current NGO assets to stETH value

    • Calculates reward difference since last distribution

    • Takes LIS platform fee (5%)

  • Effects

    • Updates NGO asset totals

    • Transfers fees to platform

    • Transfers remaining rewards to NGO

    • Updates last balance tracking

setOracle

function setOracle(address _newOracle, bool _state) public onlyOwner

Manages oracle permissions.

  • Parameters

    • _newOracle: Address to modify oracle status

    • _state: True to grant oracle role, false to revoke

setRewardsOwner

function setRewardsOwner(address _newRewOwner) public onlyOwner

Updates rewards recipient.

  • Parameters

    • _newRewOwner: New recipient address

endNGO

function endNGO() public notFinished onlyOwner

Terminates the NGO contract.

  • Effects

    • Sets isFinish to true

    • Prevents new stakes

    • Allows existing withdrawals

setUserBan

function setUserBan(address userAddress, bool isBan) public onlyOwner

Controls user access to staking functionality.

  • Parameters

    • userAddress: Address to ban/unban

    • isBan: True to ban, false to unban

  • Access Control

    • Only callable by owner

  • Effects

    • Updates user's ban status

    • Banned users can withdraw but cannot stake

emitEvent

function emitEvent(
    string memory _name,
    string calldata _imageLink,
    string calldata _description,
    string calldata _link,
    string calldata _location
) public onlyOwner

Emits NGO metadata for indexing.

  • Parameters

    • _name: NGO name

    • _imageLink: NGO image URL

    • _description: NGO description

    • _link: NGO website/resource link

    • _location: NGO location

  • Access Control

    • Only callable by owner

  • Usage

    • Used for updating NGO information in external systems

    • Enables graph indexing of NGO details

System Functions

receive

receive() external payable

Fallback function to receive ETH.

  • Usage

    • Enables direct ETH transfers to contract

    • Required for stake operations with native ETH

    • No additional logic executed

View Functions

getUserBalance

function getUserBalance(address _user, uint256 _id) public view returns (uint256)

Returns user's total balance including NGO share.

  • Parameters

    • _user: User address

    • _id: Stake identifier

  • Returns

    • Total balance in stETH

getUserStakeInfo

function getUserStakeInfo(address _user, uint256 _id) public view returns (StakeInfo)

Returns stake details for given user and ID.

  • Parameters

    • _user: User address

    • _id: Stake identifier

  • Returns

    • Struct containing:

      • percent: NGO share percentage

      • amount: Original stake amount

      • startDate: Stake timestamp

Modifiers

onlyOracle

modifier onlyOracle() {
        if (!_oracles[msg.sender]) {
            revert OnlyOracle(msg.sender);
        }
        _;
    }

Modifier to restrict access to only oracle.

notFinished

modifier notFinished() {
        if (isFinish) {
            revert NgoFinished();
        }
        _;
    }

Modifier to restrict access to only oracle.

validStake

modifier validStake(uint16 _ngoPercent) {
        if (
            _ngoPercent < MIN_SHARE_PERCENT || _ngoPercent > MAX_SHARE_PERCENT
        ) {
            revert InvalidPercent();
        }

        _;
    }

Modifier to check valid stake info.

notBanned

modifier notBanned() {
        if (_isBanned[msg.sender]) {
            revert UserBanned();
        }
        _;
    }

Modifier to check is user is banned.

validAmount

modifier validAmount(uint256 _amount) {
        if (_amount < MIN_AMOUNT) {
            revert InvalidStakeAmount();
        }
        _;
    }

Modifier to check valid minimum amount for ETH and stETH.

validWithdrawalAmount

modifier validWithdrawalAmount(uint256 _amount) {
        if (_amount < MIN_WITHDRAWAL_AMOUNT) {
            revert InvalidWithdrawalAmount();
        }
        _;
    }

Modifier to check valid minimum amount for ETH and stETH.

Events

Staking Events

Staked

event Staked(
    uint256 _id,
    address _staker,
    uint256 _amountStaked,
    uint16 _percentShare,
    address _ngo,
    uint256 _timestamp,
    uint256 _blockNumber,
    EthType _ethType
);

Emitted when a user stakes funds in the NGO.

  • Parameters

    • _id: Unique identifier for the stake

    • _staker: Address of the staking user

    • _amountStaked: Amount of tokens staked

    • _percentShare: Percentage shared with NGO (100-10000)

    • _ngo: Address of the NGO contract

    • _timestamp: Block timestamp of staking

    • _blockNumber: Block number of staking

    • _ethType: Type of staked token (Native/StEth/WStEth)

  • Tracks: stake ID, staker address, amount, NGO share percentage, timestamp

  • Usage: Track new stakes and type of tokens used

Reward Events

RewardsUpdated

event RewardsUpdated(
    uint256 _totalNGOAssets,
    uint256 _timestamp,
    uint256 _blockNumber
);

Emitted when NGO rewards are distributed.

  • Parameters

    • totalNGOAssets: Amount of tokens in the NGO pool.

    • _timestamp: Block timestamp of distribution

    • _blockNumber: Block number of distribution

  • Tracks: total tokens in NGO pool, share distribution timestamp and block number.

  • Usage: Monitor reward distributions and track NGO earnings

Withdrawal Events

WithdrawRequested

event WithdrawRequested(
    address _staker,
    address _ngo,
    uint256 _requestId,
    uint256 _timestamp,
    uint256 _blockNumber,
    uint256 _stakeId
);

Emitted when a withdrawal request is initiated.

  • Parameters

    • _staker: The address of the user requesting withdrawal

    • _ngo: The address of the NGO contract

    • _requestId: The ID of the withdrawal request

    • _timestamp: The block timestamp when withdraw was requested

    • _blockNumber: The block number when withdraw was requested

    • _stakeId: The id of the stake

  • Tracks: user address, request ID, stake ID

  • Usage: Track withdrawal requests in the queue

WithdrawClaimed

event WithdrawClaimed(
    address _claimer,
    address _ngo,
    uint256 _amount,
    uint256 _requestId,
    uint256 _timestamp,
    uint256 _blockNumber
);

Emitted when a user claims a withdrawal.

  • Parameters

    • _claimer: The address of the user claiming withdrawal

    • _ngo: The address of the NGO contract

    • _amount: The amount requested for withdrawal

    • _requestId: The ID of the withdrawal request

    • _timestamp: The block timestamp when withdraw was claimed

    • _blockNumber: The block number when withdraw was claimed

  • Tracks: claimer, amount, request ID

  • Usage: Track completed ETH withdrawals

WithdrawERC20Claimed

event WithdrawERC20Claimed(
    address _claimer,
    address _ngo,
    uint256 _amount,
    uint256 _timestamp,
    uint256 _blockNumber,
    uint256 _stakeId,
    EthType _ethType
);

Emitted when stETH or wstETH withdrawal is claimed.

  • Parameters

    • _claimer: The address of the user claiming withdrawal

    • _ngo: The address of the NGO contract

    • _amount: The amount of stEth or WStEth claimed

    • _timestamp: The block timestamp when withdraw was claimed

    • _blockNumber: The block number when withdraw was claimed

    • _stakeId: The id of the stake

    • _ethType: Type of Eth (stETH/wstETH)

    Note: if _ethType = 1 then amount of stETH is passed. if _ethType = 2 then amount of wstETH is passed.

  • Tracks: claimer, amount, token type

  • Usage: Track completed stETH or wstETH withdrawals

Administrative Events

GraphEvent

event GraphEvent(
    string _name,
    string _imageLink,
    string _description,
    string _link,
    string _location,
    address _ngo,
    uint256 _timestamp
);

Emitted when NGO metadata is updated.

  • Parameters

    • _name: The name of the NGO

    • _imageLink: The link to the image associated with the NGO

    • _description: A description of the NGO

    • _link: A link associated with the NGO

    • _location: Physical location of NGO

    • _ngo: The address of the NGO contract

    • _timestamp: The block timestamp when withdraw was claimed

  • Tracks: NGO details and location

  • Usage: Track NGO metadata updates for indexing

NGOFinished

event NGOFinished(
    address _ngo,
    uint256 _timestamp,
    uint256 _blockNumber
);

Emitted when NGO operations are terminated.

  • Parameters

    • _ngo: The address of the NGO contract

    • _timestamp: The timestamp when the NGO was finished

    • _blockNumber: The block number when the NGO was finished

  • Tracks: termination timestamp and block number and address of NGO Contract.

  • Usage: Signal end of NGO contract.

OracleChanged

event OracleChanged(
    address _newOracle,
    bool _state
);

Emitted when the oracle was added or status was changed.

  • Parameters

    • _newOracle: New oracle address

    • _state:Current oracle state

    Note: If state = true - current address active. If state = false - current address inactive.

  • Tracks: New oracle address and current oracle state.

  • Usage: Signals change of an Oracle.

RewardsOwnerChanged

event RewardsOwnerChanged(
    address _newRewOwner
);

Emitted when the rewards owner was changed.

  • Parameters

    • _newRewOwner: New reward owner address

  • Tracks: New Reward Owner address.

  • Usage: Signals change of Reward Owner.

BannedUser

event BannedUser(
    address _userAddress, 
    bool _isBan
);

Emitted when the state of user access is changed.

  • Parameters

    • _userAddress: User address

    • _isBan: Current user state

  • Tracks: User address and access state of user.

  • Usage: Signals change of User access status.

Error Conditions

Validation Errors

InvalidPercent

error InvalidPercent();
  • Trigger: Share percentage outside valid range (100-10000)

  • Prevention: Validate percentage before staking

  • Impact: Prevents invalid share calculations

InvalidStakeAmount

error InvalidStakeAmount();
  • Trigger: Invalid Stake amount maybe less than 1000 wei

  • Prevention: Make sure the stake amount is greater than 1000

  • Impact: Ensures economic viability of staking

InvalidWithdrawalAmount

error InvalidWithdrawalAmount();
  • Trigger: Withdrawal request below minimum limit 100 wei

  • Prevention: Make sure the withdrawal amount is greater than 100 wei

  • Impact: Ensures economic viability of withdrawals

InvalidWithdrawAmount

error InvalidWithdrawAmount();
  • Trigger: Withdrawal request below minimum limit 1 percent of stake

  • Prevention: Make sure the withdrawal amount is greater than 1% of your stake

  • Impact: Ensures economic viability of withdrawals

RequestAmountTooSmall

error RequestAmountTooSmall(uint256 _amount);
  • Trigger: Withdrawal request below minimum limit

  • Parameter: _amount - Requested amount

  • Prevention: Check Lido's minimum withdrawal amount

  • Impact: Ensures economic viability of withdrawals

RequestAmountTooLarge

error RequestAmountTooLarge(uint256 _amount);
  • Trigger: Withdrawal request above maximum limit or user balance

  • Parameter: _amount - Requested amount

  • Prevention: Check balance and Lido's maximum withdrawal amount

  • Impact: Prevents overdraw attempts

MinimumWstEthStakeError

error MinimumWstEthStakeError();
  • Trigger: Amount of stake lower than minimum for wstETH

  • Prevention: Check balance and Lido's minimum stake amount

  • Impact: Prevents failed stake attempts

MinimumWstEthWithdrawError

error MinimumWstEthWithdrawError();
  • Trigger: Amount of withdrawal lower than minimum for wstETH

  • Prevention: Check balance and Lido's minimum withdrawal amount

  • Impact: Prevents failed withdraw attempts

Access Control Errors

OnlyOracle

error OnlyOracle(address _sender);
  • Trigger: Non-oracle address calling oracle-restricted function

  • Parameter: _sender - Unauthorized caller address

  • Prevention: Use correct oracle address

  • Impact: Protects reward distribution mechanism

UserBanned

error UserBanned();
  • Trigger: Banned user attempting to stake

  • Prevention: Check ban status before staking

  • Impact: Enforces user restrictions

State Errors

NgoFinished

error NgoFinished();
  • Trigger: Attempting operations after NGO termination

  • Prevention: Check NGO status before operations

  • Impact: Prevents post-termination activities

NotFinalizedStatus

error NotFinalizedStatus();
  • Trigger: Claiming withdrawal before finalization

  • Prevention: Wait for withdrawal finalization

  • Impact: Ensures proper withdrawal sequence

RewardError

error RewardError();
  • Trigger: Attempting reward distribution with no rewards

  • Prevention: Check reward balance before distribution

  • Impact: Prevents empty reward distributions

Technical Errors

NullAddress

error NullAddress();
  • Trigger: Providing zero address for critical parameters

  • Prevention: Validate addresses before use

  • Impact: Prevents contract initialization with invalid addresses

InvalidRequestIdForUser

error InvalidRequestIdForUser(address _claimer, uint256 _requestId);
  • Trigger: Claiming withdrawal for wrong request ID

  • Parameters:

    • _claimer: Address attempting claim

    • _requestId: Invalid request ID

  • Prevention: Verify request ownership

  • Impact: Protects withdrawal ownership

ZeroAmount

error ZeroAmount();
  • Trigger: Attempting operation with zero amount

  • Prevention: Validate amount before operation

  • Impact: Prevents meaningless transactions

FeeError

error FeeError();
  • Trigger: Attempting to transfer zero fee

  • Prevention: Ensure fee is not zero

  • Impact: Handles failed fee transfers

Security Features

  1. Administrative Controls

    • Owner-only administrative functions

      • Contract upgrades (_authorizeUpgrade)

      • Oracle management (setOracle)

      • Rewards owner management (setRewardsOwner)

      • User banning (setUserBan)

      • NGO termination (endNGO)

    • Oracle-only functions

      • Reward distribution (handleNGOShareDistribution)

  2. User Restrictions

    • Ban system for malicious users

    • Banned users can withdraw but cannot stake

  3. Safety Checks

    • Reentrancy protection on withdrawals

    • Amount validation

    • Balance verification

    • Null address checks

  4. Upgradability

    • UUPS proxy pattern

    • Owner-controlled upgrades

    • State preservation during upgrades

Minimum Withdrawal Limit Protection

When withdrawing assets from the smart contract, there is a built-in protection mechanism that enforces a minimum withdrawal amount based on the total staked amount. This prevents potential attacks through micro-withdrawals.

Example:

  • Total Stake: 1000 ETH

  • Attempted Withdrawal: 999 wei

  • Result: Transaction reverts

Due to Solidity's integer division rules, the ratio calculation for very small withdrawals relative to the stake amount will round to 0, making such withdrawals impossible.

Key Point: The minimum withdrawal amount automatically scales with the size of the stake. For a 1000 ETH stake, the minimum withdrawal is 1000 wei.

Last updated