57310 sc medium unaccounted processing fees in long payment path

Submitted on Oct 25th 2025 at 06:20:57 UTC by @flora for Audit Comp | Belongarrow-up-right

  • Report ID: #57310

  • Report Type: Smart Contract

  • Report severity: Medium

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

  • Impacts:

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

Description

Brief / Intro

A critical accounting error exists within the payToVenue function of the BelongCheckIn contract. When customers pay using the LONG token, the platform's 2.5% processing fee is calculated but never actually collected from the Escrow contract. This flaw leads to a direct and systematic loss of platform revenue with every LONG transaction. The uncollected fees are either unintentionally credited to venues as an excess subsidy or become permanently locked within the Escrow contract, creating significant accounting and reconciliation challenges.

Vulnerability Details

The vulnerability originates in the logic branch that handles non-USDC payments within the payToVenue function. The design intends to pull a platform subsidy from a venue's longDeposits in the Escrow contract, subtract the platform's processing fee, and forward the net amount to the venue.

However, the implementation only performs this subtraction mathematically, without executing the necessary fund transfers for the fee itself.

Flawed Code Logic in BelongCheckIn.sol:

// ... existing code ...
        } else {
            // platform subsidy - processing fee
            uint256 subsidyMinusFees =
                _storage.fees.platformSubsidyPercentage.calculateRate(customerInfo.amount)
                - _storage.fees.processingFeePercentage.calculateRate(customerInfo.amount);
            _storage.contracts.escrow
                .distributeLONGDiscount(customerInfo.venueToPayFor, address(this), subsidyMinusFees);

            // ... customer payment logic ...
// ... existing code ...
1

Incorrect Withdrawal

The code calculates subsidyMinusFees by subtracting the processingFee from the platformSubsidy. It then calls distributeLONGDiscount on the Escrow contract to withdraw only this net amount (subsidyMinusFees).

2

Missing Fee Collection

There is no subsequent call to withdraw the processingFee amount itself from Escrow.

3

Missing Revenue Handling

Crucially, the internal function _handleRevenue, which is responsible for processing platform income and emitting a RevenueBuybackBurn event, is never invoked for the fee. This is inconsistent with other fee-collecting functions in the contract, such as venueDeposit and distributePromoterPayments, which correctly call _handleRevenue.

As a result, the processingFee is left behind in the venue's longDeposits mapping within the Escrow contract during every LONG transaction.

Impact Details

The impact of this vulnerability is a direct, quantifiable, and ongoing financial loss for the platform, coupled with a breakdown in accounting integrity.

1

Systematic Revenue Loss

The platform loses 100% of its intended 2.5% processing fee on every transaction conducted in LONG. This constitutes a persistent drain on protocol revenue that scales linearly with the volume of LONG payments. Based on transaction volume estimates, this could lead to hundreds of thousands of dollars in lost revenue annually.

2

Misappropriation or Locking of Funds

The uncollected processing fees face two potential outcomes, neither of which benefits the platform:

  • Unintended Subsidy: The fees remain in the venue's longDeposits pool within the Escrow contract. This pool is used to fund platform subsidies for future transactions at that venue. The leftover fees effectively become an excess subsidy, allowing the venue to support more subsidized transactions than intended, directly transferring value from the platform to the venue.

  • Permanent Fund Lock: If a venue stops accepting LONG payments or becomes inactive, the accumulated processing fees are permanently locked in its corresponding longDeposits slot in the Escrow contract. There are no functions available for the platform owner or the venue to withdraw these trapped funds.

3

Accounting Discrepancies

The absence of the _handleRevenue call means no RevenueBuybackBurn events are emitted for these fees. This creates a significant gap in the on-chain audit trail, making it extremely difficult to track protocol revenue, reconcile accounts, and understand the true financial state of the platform.

References

  • Vulnerable Contract: contracts/v2/platform/BelongCheckIn.sol

  • Vulnerable Function: payToVenue(CustomerInfo calldata customerInfo)

  • Affected Logic: Lines 471-477 (in the else block for LONG payments)

  • Related Contract: contracts/v2/periphery/Escrow.sol

Proof of Concept

End-to-end POC demonstrating the LONG payment path processing fee not being recorded. This POC deploys, configures, and exercises the relevant contracts to show that the processingFee is not extracted from Escrow and _handleRevenue is not invoked.

Was this helpful?