57650 sc low wrapped native token routing can fail without full validation

Submitted on Oct 27th 2025 at 20:56:34 UTC by @Oxv1bh4 for Audit Comp | Belongarrow-up-right

  • Report ID: #57650

  • Report Type: Smart Contract

  • Report severity: Low

  • 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

The _buildPath function constructs a Uniswap V3 swap path dynamically, choosing either a direct pool or routing through a configured wrapped native token. However, in the two-hop scenario, the function only checks if the first pool exists (tokenIn → W_NATIVE) and assumes the second pool (W_NATIVE → tokenOut) exists. If the second pool does not exist, the swap will revert at execution, causing the transaction to fail.

Vulnerability Details

In the current implementation, the function only validates the existence of the first hop in a two-hop swap path and assumes that the second hop (from the wrapped native token to the final output token) exists. As a result, the function can produce a path that is invalid, leading to failed swaps at runtime when executed through the Uniswap V3 router. If the second pool does not exist, a swap call using this path will revert, blocking users from completing the transaction.

Code excerpt:

function _buildPath(PaymentsInfo memory _paymentsInfo, address tokenIn, address tokenOut)
        internal
        view
        returns (bytes memory path)
    {
        // Direct pool
        if (
            IV3Factory(_paymentsInfo.swapV3Factory).getPool(tokenIn, tokenOut, _paymentsInfo.swapPoolFees) != address(0)
        ) {
            path = abi.encodePacked(tokenIn, _paymentsInfo.swapPoolFees, tokenOut);
        }
        // tokenIn -> W_NATIVE_CURRENCY -> tokenOut
        // @audit - W_NATIVE_CURRENCY to tokenOut pool validation is missing
        else if (
            IV3Factory(_paymentsInfo.swapV3Factory)
                    .getPool(tokenIn, _paymentsInfo.wNativeCurrency, _paymentsInfo.swapPoolFees) != address(0)
        ) {
            path = abi.encodePacked(
                tokenIn, _paymentsInfo.swapPoolFees, _paymentsInfo.wNativeCurrency, _paymentsInfo.swapPoolFees, tokenOut
            );
        } else {
            revert NoValidSwapPath();
        }
    }

Impact Details

Failed swaps stop the protocol from sending the expected output tokens to promoters, escrows, or venues, resulting in the protocol not delivering the promised returns. The issue is classified as LOW severity because it prevents the expected transfer but does not result in direct loss of funds from the protocol.

References

https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/platform/BelongCheckIn.sol?utm_source=immunefi#L741-L763

Proof of Concept

The following steps reproduce the issue by mocking Uniswap V3 components and showing a missing second hop causes a swap to fail at execution time.

1

1) Add mock Uniswap V3 contracts

Create contracts/mocks/MockUniswapV3.sol with:

2

2) Add helper to set up mocks in tests

Add the following helper to test/v2/platform/belong-check-in.test.ts:

3

3) Update the test fixture to inject mock Uniswap addresses

Update fixture in test/v2/platform/belong-check-in.test.ts to call setUpMockUniswap() and set mockPaymentsInfo using returned addresses:

4

4) Add the test case that demonstrates the failing swap

Add this test inside the Venue Flow describe block in test/v2/platform/belong-check-in.test.ts:

5

5) Run tests

Run:

Expected behavior demonstrated by the test:

  • The path builder does not revert with NoValidSwapPath because it validated only the first hop.

  • The Uniswap router simulation reverts during swap execution due to the missing second hop, causing SwapFailed.

Notes:

  • The root cause is missing validation of the second hop (W_NATIVE → tokenOut) when building a two-hop path.

  • Fixing the issue requires adding an extra pool existence check for the second hop before returning the two-hop encoded path. The report does not include a suggested patch; it only documents the detection and reproduction.

Was this helpful?