Impacts: Smart contract unable to operate due to lack of token funds
Description
Brief/Intro
BelongCheckIn.payToVenue() always attempts to withdraw a per-venue LONG subsidy from Escrow before delivering funds. When the venue’s LONG subsidy bucket (Escrow.venueDeposits[venue].longDeposits) is depleted, this withdrawal reverts, making all LONG payments for that venue fail until the venue redeposits (and pays the convenience fee again). USDC payments still work, but the LONG path is bricked, creating a venue-level denial of service that can occur naturally with usage or be forced cheaply by an adversary.
Vulnerability Details
When a customer pays a venue in LONG, the contract first calculates a subsidy amount derived from the platform’s configuration and attempts to withdraw it from the venue’s LONG pool in Escrow. The withdrawn subsidy is then combined with the customer’s own LONG payment to form the total amount transferred or staked for the venue. The subsidy is meant to be sourced from the venue’s previously deposited LONG balance, which is finite and decreases with every LONG payment.
In the LONG payment branch of BelongCheckIn::payToVenue(), the function computes the subsidy and immediately requests it from the escrow contract:
The call to Escrow::distributeLONGDiscount() reverts if the venue’s LONG balance is insufficient to cover the requested amount:
Once the venue’s longDeposits reach zero, this require statement fails, reverting the entire transaction. There is no fallback behavior to cap the subsidy at the remaining balance, nor to skip subsidy withdrawal entirely when the pool is empty. Because of this, any subsequent LONG payments to the venue will consistently revert until new funds are deposited to replenish its LONG balance in escrow.
This logic makes LONG payments depend entirely on the venue’s available subsidy balance. Once that balance is depleted, every LONG transaction to the venue fails, effectively disabling this payment method until the subsidy is replenished. Meanwhile, USDC payments remain unaffected and continue to work as normal.
Impact Details
Selected impact: Smart contract unable to operate due to lack of token funds.
Once a venue’s Escrow.venueDeposits[venue].longDeposits reaches zero, all subsequent LONG payments to that venue revert with NotEnoughLONGs. This disables one of the two accepted payment paths and effectively halts all LONG-based activity for that venue until a redeposit occurs.
The issue can appear naturally after enough LONG payments deplete the subsidy pool or be triggered intentionally by an attacker repeatedly making LONG payments to exhaust the pool (a cheap griefing vector). Although USDC payments remain functional, the protocol fails to deliver on its intended functionality for LONG payments, which makes the LONG payment path unusable for that venue.
INITIAL STATE
LONG pool: 11.154730921775894517
Payment size: 743.6487281183929678
Subsidy per payment: 3.718243640591964839
Payment 1: LONG remaining = 7.436487281183929678
Payment 2: LONG remaining = 3.718243640591964839
Payment 3: LONG remaining = 0.0
AFTER 3 PAYMENTS
LONG pool: 0.0
Pool depleted: YES
ATTEMPTING 4TH PAYMENT
4th payment reverted: DoS CONFIRMED
✔ [PoC] payToVenue() LONG subsidy depletion causes DoS (27449ms)