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
IERC20interface andSafeERC20wrappers 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
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
slashfunction.
Staker Management & Tracking
Each staker’s deposits, locked tokens and withdrawal schedules are stored in a
Stakes.Stakerstruct (imported fromStakes.sol). A mapping links staker addresses to their stake data, and an array records the list of stakers.Functions like
getAvailableStake,getStakedTokensandgetListOfStakersallow 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; theOwnablemodule allows an account (the owner) to have exclusive access to specific functions.Reentrancy protection – Inheriting from
ReentrancyGuardprovides anonReentrantmodifier. Functions markednonReentrantcannot be entered again until they complete, preventing nested calls and blocking reentrancy attacks.Safe token operations –
SafeERC20ensures that token transfers throw on failure and handle tokens that do not return a value.Explicit authorization – The
onlySlashermodifier 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_tokensis positive and that the staker’s total available stake (current available balance plus_tokens) meets the minimum stake. New stakers are appended to thestakersarray.The staker must have approved in advance in the token contract to the staking contract to allow
safeTransferFrom.Emits
StakeDepositedevent.
Unstake (initiate withdrawal)
Stakers call
unstake(_tokens)to start an unstake. The function verifies that_tokensis 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’stokensLockedandtokensLockedUntilfields are updated.Emists
StakeLockedevent.
Withdraw (complete withdrawal)
After the lock period has passed, a staker calls
withdraw(). The contract calculates the amount withdrawable via theStakes.Stakerstruct. If tokens are available,SafeERC20.safeTransfersends them back to the staker and resets the locked amount. The function uses thenonReentrantmodifier to prevent reentrancy.Emits
StakeWithdrawnevent.
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,_tokensis 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 tofeeBalance. The net slashed tokens are transferred to_slashRequester.Can be called by:
Owner.
Authorised slashers.
Emits
StakeSlashedevent.
Withdraw Fees
Only the owner can call
withdrawFees(). IffeeBalanceis greater than zero, the contract transfers the entire fee balance to the owner usingSafeERC20.safeTransferand resetsfeeBalance.Can be called by:
Owner.
Emits
FeeWithdrawnevent.
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 mappingslashersis 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_limitentries.
Last updated
Was this helpful?