57348 sc insight incorrectly returned values and emitted data on staking emergency functionality

Submitted on Oct 25th 2025 at 12:16:31 UTC by @blackgrease for Audit Comp | Belongarrow-up-right

  • Report ID: #57348

  • Report Type: Smart Contract

  • Report severity: Insight

  • Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/periphery/Staking.sol

  • Impacts:

    • Contract fails to deliver promised returns, but doesn't lose value

Description

Affected Files: Staking.sol

The Staking contract has emergency withdrawal functions — emergencyWithdraw and emergencyRedeem — that allow a user to bypass the minimum staking period in order to remove their locked stakes.

However, the returned value in the emergencyWithdraw and emergencyRedeem functions is incorrect because it misrepresents the amount of assets/shares actually withdrawn/redeemed. The returned value does not factor in the penalty fee that is charged to users on locked tokens.

Scenario:

1

Scenario example

  1. User stakes 1000 LONG while the minimum staking period is 5 days.

  2. They initiate an emergency withdrawal of the full amount. The penalty is 10% meaning they will receive only 900 LONG.

  3. emergencyWithdraw and emergencyRedeem incorrectly return that the user has received 1000 LONG while in practice they have been transferred 900 LONG.

Furthermore, this incorrect data is emitted in the related events — EmergencyWithdraw and Withdraw — propagating the misrepresented data.

Note: The natspec includes a note: "// @return assets /shares Assets calculated from shares/assets before penalty." In practice, returning the actual payout after penalty would be more beneficial for users and for indexers/analytics.

This is a logic issue where an external function meant to return a value does not return the correct thing. Importantly, users are transferred the correct amount of tokens; no value is lost.

The problematic code

Below are the relevant functions highlighting where the issue exists:

Impact

This is a low impact issue because the external functions emergencyWithdraw and emergencyRedeem do not return the correct values, and the returned value is only provided to callers (it is not consumed internally). However, indexers and analytics that rely on returned values or emitted events will see incorrect data, misrepresenting the actual payout amounts. The user receives the correct token amount; no funds are lost.

Mitigation

Suggested fix: return the actual payout (after penalty) from the external functions and from the internal _emergencyWithdraw, and emit the correct values in EmergencyWithdraw.

A tested fix (applies small API change: the external functions return payout instead of pre-penalty assets/shares):

https://gist.github.com/blackgrease/fe2ecf8ec4a0e9793ea829dfd9247648

Proof of Concept

A Foundry PoC outlines the incorrect data returned and emitted and what data should be returned. It demonstrates that the returned value does not correctly represent the assets that the user receives.

  • Run with: forge test --mt testWrongDataReturnedAndEmittedOnEmergencyWithdraw -vvv --via-ir

Logs from the PoC:

Foundry setup (how the author ran the PoC):

1

1. Clone the repo

git clone https://github.com/belongnet/checkin-contracts.git

2

2. Install Foundry dependencies

  1. forge install OpenZeppelin/[email protected] --no-commit

  2. forge install OpenZeppelin/[email protected] --no-commit

  3. npm install solady --force

3

3. Update remappings in foundry.toml

Replace previous remappings (commented out in the PoC) with:

Was this helpful?