#46942 [SC-Low] set perpetual asset balance link there is no cycle checks

Submitted on Jun 6th 2025 at 14:37:44 UTC by @gln for IOP | Paradex

  • Report ID: #46942

  • Report Type: Smart Contract

  • Report severity: Low

  • Target: https://github.com/tradeparadex/audit-competition-may-2025/tree/main/paraclear

  • Impacts:

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

Description

Brief/Intro

By calling set_perpetual_asset_balance_link function admin could create cycles in Paraclear_perpetual_asset_balance list. As a result, any function which loads account state from storage will revert.

Vulnerability Details

Let's look at how contract handles account loading from storage, code from paraclear.cairo:

   fn _load_account_no_asset_data(
            self: @ContractState, account: ContractAddress,
        ) -> AccountState {
            // load fees and referral
            let fee_rates = self.account._get_account_fee_rate(account);
            let referral = self.account.get_account_referral(account);

            // load perpetual markets (both futures and options)
            let (perp_names, perp_balances) = self.perpetual_future._get_account_markets(account);

            // load token markets
            let (mut token_names, mut token_balances) = self.token._get_account_markets(account);
             ...
 }
 fn _load_account_v2(self: @ContractState, account: ContractAddress) -> AccountState {
            let mut account_state = self._load_account_no_asset_data(account);
            if account_state.perpetual_names.is_empty() && account_state.token_names.is_empty() {
                return account_state;
            }
            account_state
                .asset_data = self
                ._load_asset_data(account_state.perpetual_names, account_state.token_names);
            account_state
        }

Now look at the function _get_account_markets from future.cairo:

  1. If we manage to create cycle here, this function will always revert due to out of gas error

The only function which is capable of createing such loop is set_perpetual_asset_balance_link() :

There is no cycle check, such that prev_market could equal to market.

Malicious or compromised admin could create cycle by calling this function.

As a result any contract functions which load account data from storage will fail with out of gas error.

Impact Details

After creating cycle in Paraclear_perpetual_asset_balance list, Paradex contract becomes unusable.

Proof of Concept

Proof of Concept

How to reproduce:

  1. Add test to paraclear/tests/test_paraclear.cairo.

See gist link - https://gist.github.com/gln7/871b2e0d4cdc04a69718923ca332c7a9

  1. Run the test:

Was this helpful?