This issue revolves around the depositMargin()
function, which performs a check to ensure that the newly deposited amount plus the existing totalDeposited
does not exceed the configured depositCap
. However, the contract never increments marginCollateralConfiguration.totalDeposited
after a successful deposit. Consequently, the system repeatedly verifies against an unchanged (often zero) total, allowing users to make multiple smaller deposits, each deemed individually permissible, until they collectively surpass the intended limit. This logic flaw invalidates the protective mechanism of the depositCap
by failing to track the cumulative amount actually deposited.
The core issue lies in the depositMargin()
function, which only checks if the new deposit plus the current totalDeposited
stays under depositCap
without ever incrementing totalDeposited
afterward. As a result, repeated deposits that each appear individually valid can be made until the actual sum far exceeds the intended cap. Because totalDeposited
remains effectively static (often at zero), the contract’s logic fails to track the accumulated total and thus does not enforce the deposit limit as designed.
Because the contract never increments totalDeposited
, it effectively ignores the enforced cap. This allows users to deposit an amount of collateral that vastly exceeds the configured limit, undermining any protective measures intended to manage risk or cap exposure. Consequently, the protocol’s expectations regarding collateral limits are violated, increasing both operational and financial risks.
In depositMargin()
, the contract checks if amountX18 + marginCollateralConfiguration.totalDeposited
exceeds the depositCap
. However, the code does not increment marginCollateralConfiguration.totalDeposited
after a successful deposit. As a result, the contract treats each deposit as if no prior deposits had been made, thus allowing multiple successive deposits to cumulatively exceed the global depositCap
.
Below is a condensed view of the relevant portion of depositMargin()
, with comments highlighting the issue:
(!) The root cause is that
marginCollateralConfiguration.totalDeposited
is never incremented post-deposit. Despite a valid cap check, the system fails to maintain the aggregated deposit total, allowing repeated small deposits to eventually exceed the overall limit.
The depositCap
becomes ineffective because the contract never updates the real deposit count. By performing multiple smaller deposits, each seemingly within the cap, a user can surpass the intended total deposit limit since totalDeposited
remains unchanged (e.g., it stays at zero if not initialized otherwise).
depositCap
is set to 1,000 tokens.
totalDeposited
starts at 0 and is never updated.
A user deposits 500 tokens:
The check passes since 500 + 0 <= 1,000
.
totalDeposited
remains 0.
The user deposits another 500 tokens:
The check passes again (500 + 0 <= 1,000
).
This process repeats endlessly, surpassing the actual limit of 1,000 tokens.
Because the deposit tracking is never incremented, the contract cannot detect that the combined deposits exceed the limit.
The testExceedDepositCapWithMultipleDeposits
function deposits 500 USDC twice and then an additional 200 USDC, resulting in a total of 1,200 USDC. Despite exceeding the supposed cap of 1,000 USDC, the test passes without reverting. This confirms that the contract is not updating marginCollateralConfiguration.totalDeposited
and is therefore allowing multiple deposits that cumulatively go beyond the set depositCap
. The final line [PASS]
demonstrates the flaw: if the cap were enforced correctly, the third deposit would revert instead of passing.
Add the following test to test/integration/perpetuals/trading-account-branch/depositMargin/depositMargin.t.sol
This confirms that depositCap
is disregarded due to the missing update of marginCollateralConfiguration.totalDeposited
. Repeated deposits easily bypass the intended cap, demonstrating a clear logical flaw.
Manual Code Review: A thorough, line-by-line analysis of the depositMargin()
function was performed to identify the absence of state updates for totalDeposited
and confirm the vulnerability.
The simplest and most direct remedy is to update marginCollateralConfiguration.totalDeposited
immediately after each successful deposit. Specifically, add the newly deposited amount to totalDeposited
to ensure the contract accurately tracks the total collateral deposited over time. Once implemented, this change will prevent multiple smaller deposits from bypassing the configured depositCap
, thereby restoring the intended protection against excessive collateral inflows.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.