Staking.sol

The Staking contract allows users to deposit (stake) ERC‑20 tokens, lock them for a period measured in blocks and later withdraw them. It is used as a security mechanism in the HUMAN Protocol by using slashing – a mechanism that penalizes misbehaving stakers by reducing their stake.

Key Features and Components

ERC‑20 Token Support

  • Uses the IERC20 interface and SafeERC20 wrappers to interact with any ERC‑20 compliant token (HMT).

  • The HMT contract address is supplied during deployment; all staking and fee transfers use this token.

Roles

Role
Capabilities

Owner

Sets the minimum stake, lock period and fee percentage; adds/removes slashers; withdraws accumulated fees.

Staker

Any address that deposits tokens into the contract. Stakers can stake, initiate unstaking, and withdraw after the lock period.

Slasher

Addresses authorized by the owner (including the owner) to penalize misbehaving stakers. Slashers call slash to reduce a staker’s balance and redistribute tokens.

Minimum Stake and Lock Period

  • A minimum stake threshold ensures that each staker’s total stake meets or exceeds a specified value. The owner can update this threshold at any time. Deposits below this threshold are rejected.

  • A lock period, measured in blocks, defines how long tokens remain locked after an unstake request. During this period the staker cannot access the tokens. The owner can modify the lock period.

Fee Mechanism and Slashers

  • A fee percentage (0–100) determines the portion of slashed tokens retained by the contract. When slashing occurs, a fraction of the slashed amount equal to (tokens × feePercentage / 100) is accumulated as fee balance. The remainder is transferred to the slash requester.

  • The owner can withdraw accumulated fees at any time. This incentivizes participation in network enforcement.

  • Slasher management: a mapping tracks authorized slashers. The owner can add or remove slashers; only addresses in this list may call the slash function.

Staker Management & Tracking

  • Each staker’s deposits, locked tokens and withdrawal schedules are stored in a Stakes.Staker struct (imported from Stakes.sol). A mapping links staker addresses to their stake data, and an array records the list of stakers.

  • Functions like getAvailableStake, getStakedTokens and getListOfStakers allow users to query the amount available for withdrawal, the total stake, and a paginated list of stakers.

Security Measures

  • Access control – By inheriting from Ownable, the contract restricts privileged operations to the owner; the Ownable module allows an account (the owner) to have exclusive access to specific functions.

  • Reentrancy protection – Inheriting from ReentrancyGuard provides a nonReentrant modifier. Functions marked nonReentrant cannot be entered again until they complete, preventing nested calls and blocking reentrancy attacks.

  • Safe token operationsSafeERC20 ensures that token transfers throw on failure and handle tokens that do not return a value.

  • Explicit authorization – The onlySlasher modifier restricts slashing to approved addresses. The minimum stake and lock period discourage trivial staking and enable orderly withdrawals.

Workflow/Functions

Initialization

  • The constructor receives the ERC‑20 token address, a minimum stake, a lock period and a fee percentage. It sets these parameters, assigns the deployer as the owner, and marks the owner as an authorized slasher. Fee percentages are validated to ensure they do not exceed 100 percent.

Stake (deposit)

  • Stakers call stake(_tokens) to deposit tokens. The function checks that _tokens is positive and that the staker’s total available stake (current available balance plus _tokens) meets the minimum stake. New stakers are appended to the stakers array.

  • The staker must have approved in advance in the token contract to the staking contract to allow safeTransferFrom.

  • Emits StakeDeposited event.

Unstake (initiate withdrawal)

  • Stakers call unstake(_tokens) to start an unstake. The function verifies that _tokens is positive, the staker has no other unstake in progress, and the available stake is at least _tokens. If previously locked tokens are withdrawable, they are withdrawn first.

  • The requested tokens are then locked for the defined lockPeriod (measured in blocks). The staker’s tokensLocked and tokensLockedUntil fields are updated.

  • Emists StakeLocked event.

Withdraw (complete withdrawal)

  • After the lock period has passed, a staker calls withdraw(). The contract calculates the amount withdrawable via the Stakes.Staker struct. If tokens are available, SafeERC20.safeTransfer sends them back to the staker and resets the locked amount. The function uses the nonReentrant modifier to prevent reentrancy.

  • Emits StakeWithdrawn event.

Slash

  • slash(_slashRequester, _staker, _escrowAddress, _tokens) is called to penalize a staker. The function validates that the slash requester and escrow address are non‑zero, _tokens is positive, and the staker has enough tokens staked.

  • The fee portion is calculated as _tokens × feePercentage / 100. The staker’s stake is reduced by the net slashed amount (_tokens − feeAmount), and the fee is added to feeBalance. The net slashed tokens are transferred to _slashRequester.

  • Can be called by:

    • Owner.

    • Authorised slashers.

  • Emits StakeSlashed event.

Withdraw Fees

  • Only the owner can call withdrawFees(). If feeBalance is greater than zero, the contract transfers the entire fee balance to the owner using SafeERC20.safeTransfer and resets feeBalance.

  • Can be called by:

    • Owner.

  • Emits FeeWithdrawn event.

Add / Remove Slasher

  • addSlasher(_slasher) allows the owner to authorize a new slasher. The address must be non‑zero and not already a slasher. The mapping slashers is updated accordingly.

  • removeSlasher(_slasher) revokes slasher privileges; it can only be called by the owner and only for addresses currently marked as slashers.

  • Can be called by:

    • Owner.

Getters

  • getAvailableStake(_staker) returns the number of tokens the staker can currently withdraw.

  • getStakedTokens(_staker) returns the total amount a staker has deposited, including locked and available tokens.

  • getListOfStakers(_startIndex, _limit) returns arrays of staker addresses and their stake data, allowing off‑chain clients to iterate through the stakers list. It validates the start index and returns up to _limit entries.

Last updated

Was this helpful?