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 andSafeERC20
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
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 fromStakes.sol
). A mapping links staker addresses to their stake data, and an array records the list of stakers.Functions like
getAvailableStake
,getStakedTokens
andgetListOfStakers
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; theOwnable
module allows an account (the owner) to have exclusive access to specific functions.Reentrancy protection – Inheriting from
ReentrancyGuard
provides anonReentrant
modifier. Functions markednonReentrant
cannot be entered again until they complete, preventing nested calls and blocking reentrancy attacks.Safe token operations –
SafeERC20
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 thestakers
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’stokensLocked
andtokensLockedUntil
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 theStakes.Staker
struct. If tokens are available,SafeERC20.safeTransfer
sends them back to the staker and resets the locked amount. The function uses thenonReentrant
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 tofeeBalance
. 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()
. IffeeBalance
is greater than zero, the contract transfers the entire fee balance to the owner usingSafeERC20.safeTransfer
and resetsfeeBalance
.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 mappingslashers
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?