57374 sc low staking tier misclassification

Submitted on Oct 25th 2025 at 16:06:24 UTC by @failsafe_intern for Audit Comp | Belongarrow-up-right

  • Report ID: #57374

  • Report Type: Smart Contract

  • Report severity: Low

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

  • Impacts:

    • Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

Description

Vulnerability Overview

BelongCheckIn.sol determines staking tiers for fee discounts using staking.balanceOf(user) (share count) instead of staking.convertToAssets(balanceOf(user)) (actual LONG exposure). After reward distributions via Staking.distributeRewards(), the vault's exchange rate increases (more assets per share), but tier calculation ignores this rebase effect. Users with rebased shares are systematically under-tiered, paying 1-5% higher fees than their actual LONG exposure warrants.

Root Cause

Helper expects asset amounts but receives share counts.

Helper.sol: stakingTiers expects asset amounts (LONG, 18 decimals):

function stakingTiers(uint256 amountStaked) external pure returns (StakingTiers tier) {
    // Expects LONG amount (18 decimals) but receives share balance
    if (amountStaked < 50000e18) {
        return StakingTiers.NoStakes;
    } else if (amountStaked >= 50000e18 && amountStaked < 250000e18) {
        return StakingTiers.BronzeTier;
    } else if (amountStaked >= 250000e18 && amountStaked < 500000e18) {
        return StakingTiers.SilverTier;
    } else if (amountStaked >= 500000e18 && amountStaked < 1000000e18) {
        return StakingTiers.GoldTier;
    }
    return StakingTiers.PlatinumTier;
}

BelongCheckIn.sol uses share counts when looking up tiers:

Venue deposit fee uses shares instead of assets:

Promoter payout fee uses shares instead of assets:

Staking.sol distributes rewards by increasing assets without minting shares (rebase):

Attack Flow (Passive Economic Error)

This is not an attacker-exploitable vulnerability but a systematic calculation error that occurs passively:

  • Initial state: Vault exchange rate 1:1 (1 share = 1 LONG)

  • User stakes 40,000 LONG → receives 40,000 shares

  • Protocol distributes rewards via distributeRewards(1_000_000 LONG)

  • Vault rebases: total assets increase, exchange rate becomes >1

  • User's actual exposure = shares × exchange rate

  • Tier calculation uses share count (undervalues the user's actual LONG exposure), causing under-tiering and higher fees

Impact

  • Impact Category: Griefing (no profit motive for an attacker, but damage to the users or the protocol)

  • User Financial Impact:

    • Venue deposits: 1–5% excess deposit fees depending on tier gap

    • Promoter payouts: 1% excess platform fee on LONG distributions

    • Cumulative: Every transaction post-rebase can incur overcharge

    • Scale: All users with rebased shares near tier boundaries affected

Example scenarios:

User Shares
Exchange Rate
Actual LONG
Classified As
Correct Tier
Excess Fee

40,000

1.5:1

60,000

NoStakes (10%)

BronzeTier (9%)

+1%

200,000

1.3:1

260,000

BronzeTier (9%)

SilverTier (8%)

+1%

450,000

1.2:1

540,000

SilverTier (8%)

GoldTier (6%)

+2%

900,000

1.15:1

1,035,000

GoldTier (6%)

PlatinumTier (3%)

+3%

Concrete example:

System impact:

  • Protocol collects unintended excess fees

  • Users experience negative ROI on staking rewards (fees cancel rewards)

  • Staking incentive system undermined

  • Trust erosion when users discover overcharges

https://gist.github.com/Joshua-Medvinsky/7b8684a54d5034bda8338d99f4051e4a

Proof of Concept

Prerequisites

Demonstration

1

Step 1: User Stakes Before Rebase

2

Step 2: Protocol Distributes Rewards

3

Step 3: User's Actual Exposure Exceeds Threshold

4

Step 4: Misclassification Occurs

5

Step 5: User Overpays Fees

6

Step 6: Verify Systemic Impact

Expected vs Actual Behavior

  • Expected: Users with >50k LONG exposure (via shares * exchange rate) receive BronzeTier fee discounts (9% deposit fee, 10%/7% promoter fee).

  • Actual: System uses share count instead of asset value. Users with 40k shares (60k LONG exposure post-rebase) classified as NoStakes, paying 10% deposit fee and 10%/8% promoter fees. 1% overcharge per transaction.

Immediate Fix

Replace balanceOf() with convertToAssets(balanceOf()).

Example fixes:

Comprehensive Fix with Helper Function

Add a conversion helper to BelongCheckIn.sol:

Replace tier lookups with the helper:

Defense-in-Depth Recommendations

  1. Add explicit asset calculation comments:

  1. Add tier verification events:

  1. Document ERC4626 behavior:

  1. Consider tier caching with refresh mechanism:

User Refund Consideration

Optional: implement fee adjustment for affected users (retroactive refunds). Example patterns shown in the original report:

5. References

  • Tier Function: stakingTiers (Helper.sol:104-117)

  • Venue Deposit Tier Lookup: BelongCheckIn.sol:375-380 (LINE 378)

  • Promoter Payout Tier Lookup: BelongCheckIn.sol:545-548 (LINE 547)

  • Reward Distribution: distributeRewards (Staking.sol:113-116)

  • ERC4626 Standard: convertToAssets() method for share-to-asset conversion


Severity: MEDIUM Impact: Griefing (systematic user damage via excess fee collection) User Loss: 1–5% excess fees per transaction post-rebase Protocol Gain: Unintended excess revenue undermining staking incentives Fix Complexity: Low (replace balanceOf() with convertToAssets(balanceOf()))

Was this helpful?