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.sol

  • paused(): inherited from Pausablesrc/Staking.sol#L20

  • activeTotalStaked, activeTotalRewards: src/Staking.sol#L33–L34

  • supportsInterface: 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?