57399 sc critical erc4626 staking lockbook breaks share fungibility partial transfers can dos withdrawals
Submitted on Oct 25th 2025 at 20:36:18 UTC by @TECHFUND_inc for Audit Comp | Belong
Report ID: #57399
Report Type: Smart Contract
Report severity: Critical
Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/periphery/Staking.sol
Impacts: Permanent freezing of funds
Critical: transferred shares are not tracked in the per-deposit lockbook. This can permanently freeze balances or force users into penalized emergency flows.
Description
Brief/Intro The Staking vault enforces time-locks via per-deposit “Stake” entries that are only created on deposit. Withdraw/redeem consume only unlocked Stake entries. Since share transfers do not create Stake entries for recipients, transferred-in sLONG are invisible to the unlock logic. This breaks ERC4626 share fungibility and causes stuck balances or forces users into penalized emergency flows.
Vulnerability Details
Root cause
On deposit:
_depositpushesStake({shares, timestamp})tostakes[to].On withdraw/redeem:
_withdrawcalls_consumeUnlockedSharesOrRevert(owner, shares), which iteratesstakes[owner]and must fully cover the requested shares from unlocked entries.On transfer: no Stake entries are created/updated; the receiver’s transferred shares have no corresponding Stake entries, so they can never be “consumed” by the unlock logic.
BUG — transferred-in sLONG are non-redeemable
Scenario:
Alice holds 100 sLONG and transfers 50 to Bob.
Bob deposits 100 LONG (mints 100 sLONG). Even after unlocking, Bob’s stakes sum to 100 (his deposit only).
redeem(150)reverts withMinStakePeriodNotMet; the extra 50 sLONG (received by transfer) are irredeemable via withdraw/redeem and only convertible via emergency flow with penalty.
Impact:
Recipients of transferred sLONG can end up with permanent or penalized-only access to those shares.
BUG — partial transfer can DoS standard withdrawals before unlock
Scenario:
Alice deposits 100 sLONG (single stake entry).
Alice transfers 50 away.
Alice then attempts to withdraw/redeem 50 (the remaining balance). The call reverts with
MinStakePeriodNotMetbecause the single Stake entry (100) remains locked and the algorithm cannot source unlocked shares from any other entry.
Impact:
Legitimate positions become partially inaccessible via standard withdraw/redeem paths until the original stake entry unlocks.
Demonstrates brittle coupling between balance and per-deposit stake entries.
Recommendations
Ensure transferred shares are represented in the lockbook (e.g., create/merge Stake entries on incoming transfers), or track a single per-user lock bucket that follows the shares on transfer.
Alternatively, disallow transferring locked shares (enforce transfer restrictions) to prevent creation of irredeemable balances.
Impact Details
Funds stuck for recipients of sLONG; only recoverable via
emergencyWithdraw/emergencyRedeemwith penalty.Legitimate positions can become partially inaccessible via standard withdraw/redeem.
References
https://github.com/immunefi-team/audit-comp-belong/blob/a17f775dcc4c125704ce85d4e18b744daece65af/contracts/v2/periphery/Staking.sol#L258-L290
Proof of Concept
Include the below code in staking.test.ts file:
Observed test output:
Was this helpful?