#46997 [SC-Medium] The vault performs an unsafe conversion on the getAccountValue result.
Submitted on Jun 7th 2025 at 15:37:52 UTC by @shaflow1 for IOP | Paradex
Report ID: #46997
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/tradeparadex/audit-competition-may-2025/tree/main/paraclear
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Temporary freezing of funds for at least 1 hour
Description
Brief/Intro
In the _total_assets function, after obtaining the getAccountValue result, an unsafe type conversion is performed. When the system experiences significant asset price volatility causing one of the vault's operators to fall into bad debt (and before liquidation occur), the vault will convert a negative value to u256, resulting in _total_assets becoming abnormally large.
Vulnerability Details
fn getAccountValue(self: @ContractState, account: ContractAddress) -> felt252 {
Self::get_account_value(self, account)
}
fn get_account_value(self: @ContractState, account: ContractAddress) -> felt252 {
let account_state = self._load_account_v2(account);
account_state.account_value().into()
}
fn _total_assets(self: @ContractState) -> u256 {
...
let mut vault_value: u256 = paraclear_dispatcher.getAccountValue(assets_holder).into();
// Skip sub-operators account values if vault is closed
let status = self.status.read();
if status == VaultStatus::Closed {
return self._convert_value_to_usdc(vault_value);
}
...
if sub_operators.len() > 0 {
let mut i = 0;
loop {
if i >= sub_operators.len() {
break;
}
let sub_operator = sub_operators.at(i);
let sub_operator_value: u256 = paraclear_dispatcher
.getAccountValue(*sub_operator)
.into();
vault_value += sub_operator_value;
i += 1;
};
}
...
}
In futures assets, there exist highly volatile meme assets whose prices may fluctuate drastically. Positions could become undercollateralized (bad debt) before liquidation occurs, resulting in negative account values.
At this point, if the getAccountValue function in _total_assets directly converts the felt252 type to u256, it will cause _total_assets to return an extremely large value.
Impact Details
When users deposit in this abnormal state, since
_total_assets
returns an extremely large value, any amount of USDC deposited will result in 0 shares minted. The deposited tokens will be effectively lost and donated to the vault.If the vault has
WITHDRAWAL_MODE_FAST
enabled orprofit_share_percentage
set, withdrawals will revert due to calculation failures.
The probability of occurrence is low, but it could potentially affect any user deposits, therefore the severity is assessed as Medium.
References
https://github.com/tradeparadex/audit-competition-may-2025/blob/0eb81b26a67666c399b4e16b39a96c19848ab7fd/vaults/src/vault/vault.cairo#L973
Proof of Concept
Proof of Concept
A sub-operator in the vault opens a small long position in a meme asset.
A user then submit the transaction of depositing 10,000 USDC into the vault.
The meme price plummets, causing the sub-operator's account value to fall below zero (undercollateralized), but liquidation hasn't yet occurred.
During the user's deposit transaction execution, _total_assets becomes extremely large due to truncation, resulting in the user's shares being rounded down to 0.
The user loses their deposited funds.
Was this helpful?