68879 sc insight essential function declarations missing from istakingv1
Submitted on Mar 11th 2026 at 19:30:41 UTC by @ZenHunter for Audit Comp | Folks Finance: Staking Contracts
Report ID: #68879
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/Folks-Finance/folks-staking-contracts/blob/main/src/Staking.sol
Impacts:
Contract fails to deliver promised returns, but doesn't lose value
Description
Brief/Intro
IStakingV1 is the interface third-party integrators and users use to interact with Staking. It is missing paused() — an essential read for any caller before invoking stake(), which reverts when the contract is paused — and optionally activeTotalStaked() and activeTotalRewards(), which track total locked funds. Without these declarations, callers holding an IStakingV1 reference must bypass the interface, and supportsInterface returns false for any integrator who adds them to their local copy of the interface — breaking ERC-165 introspection.
Vulnerability Details
Staking inherits Pausable and applies whenNotPaused to stake():
// src/Staking.sol#L48-L55
function stake(uint8 periodIndex, uint256 amount, StakeParams calldata params)
external
nonReentrant
whenNotPaused // reverts if paused
returns (uint8)paused() is the standard guard a caller checks before submitting a stake. It is not declared in IStakingV1, so an integrator holding an IStakingV1 reference cannot call it:
Similarly, Staking.sol#L33–L34 declares two public state variables whose compiler-generated getters are absent from the interface:
The interface currently exposes only user-facing actions and per-period/per-stake queries:
Impact Details
paused() (essential): Any integration that needs to gate stake() on the paused state must either downcast to the concrete Staking type or use a raw staticcall — both of which couple the caller to the implementation and defeat the purpose of the interface.
activeTotalStaked / activeTotalRewards (optional): Dashboards, monitoring bots, and manager tooling that hold an IStakingV1 reference cannot verify the fund-health invariant TOKEN.balanceOf(address(this)) >= activeTotalStaked + activeTotalRewards without bypassing the interface.
On-chain supportsInterface: type(IStakingV1).interfaceId is computed as the XOR of every function selector declared in IStakingV1. The three missing selectors are excluded from that XOR. If an integrator builds a complete version of IStakingV1 that includes them, they compute a different interfaceId, and Staking.supportsInterface returns false for it — even though the contract implements every function — breaking ERC-165 introspection.
Impact category: Low
References
Missing declarations:
src/IStakingV1.solpaused(): inherited fromPausable—src/Staking.sol#L20activeTotalStaked,activeTotalRewards:src/Staking.sol#L33–L34supportsInterface:src/Staking.sol#L230–L239
Recommendation
Add the missing declarations to IStakingV1:
No implementation change is needed — paused() is already provided by the inherited Pausable contract, and the public state variables in Staking.sol already satisfy the getter signatures automatically.
Proof of Concept
Command:
Output:
Was this helpful?