Increasing leverage can make the position have "0" initialMargin
Summary
Increasing the leverage of a cross position can make the position have "0" initialMargin.
Vulnerability Detail
When position leverage is increased the margin required in USD will decrease since positions QTY is not changing. However, when the margin in terms of token is decreased the current price will be used which can make the initialMargin to "0".
For example, let's assume a position where its 2x SHORT tokenA with 100$ margin where 1 tokenA is 1$.
Position in beginning:
initialMargin = 100
initialMarginInUsd = 100$
qty = 200$
Say the user wants to levers up to 10x. Reduce margin will be calculated as 100 - 20 = 80 as we can observe in PositionMarginProcess::updatePositionLeverage function's these lines
Moving on with the execution of the function we will execute the following lines in the PositionMarginProcess::_executeReduceMargin() internal function:
As we can observe above, we use the current price. Say the price of tokenA is 0.8$ at the time of updating leverage. reduceMarginAmount will be calculated as: 80 / 0.8 = 100 tokens.
When we reduce this amount from position.initialMargin which recall that it was 100 at the beginning, it will be "0".
Another case from same root cause:
Isolated accounts can close a LONG position that is in losses to secure their initial margin back, effectively escalating any losses that are occurred.
Test Logs:
account info Result(2) [
Result(4) [ 500000000000n, 0n, 0n, 0n ],
Result(4) [ 0n, 1000000000000000000n, 0n, 3000000000000000n ]
]
Position initial margin 997000000000000000n
Position initial margin in USD 24925000000000000000000n
Position initial margin from 0n
Position qty 49850000000000000000000n
account info Result(2) [
Result(4) [ 500000000000n, 0n, 0n, 0n ],
Result(4) [ 0n, 3000000000000000n, 0n, 3000000000000000n ]
]
Position initial margin 0nPosition initial margin from 0n
Position initial margin in USD 4985000000000000000000n
Position qty 49850000000000000000000n
Impact
Most obvious one I found is that the account no longer pays borrowing fees because of multiplication with "0" which is a high by itself alone. Also, please refer to the other case explained in vulnerability details section where isolated order escapes the losses and secures the initial margin.
mstpr-brainbot
High
Increasing leverage can make the position have "0"
initialMargin
Summary
Increasing the leverage of a cross position can make the position have "0" initialMargin.
Vulnerability Detail
When position leverage is increased the margin required in USD will decrease since positions QTY is not changing. However, when the margin in terms of token is decreased the current price will be used which can make the
initialMargin
to "0".For example, let's assume a position where its 2x SHORT tokenA with 100$ margin where 1 tokenA is 1$. Position in beginning: initialMargin = 100 initialMarginInUsd = 100$ qty = 200$
Say the user wants to levers up to 10x. Reduce margin will be calculated as 100 - 20 = 80 as we can observe in PositionMarginProcess::updatePositionLeverage function's these lines
Moving on with the execution of the function we will execute the following lines in the PositionMarginProcess::_executeReduceMargin() internal function:
As we can observe above, we use the current price. Say the price of tokenA is 0.8$ at the time of updating leverage.
reduceMarginAmount
will be calculated as: 80 / 0.8 = 100 tokens. When we reduce this amount fromposition.initialMargin
which recall that it was 100 at the beginning, it will be "0".When positions initial margin is "0" position no longer pays borrowing fees to pool. Completely bypassing it as we can see how the borrowing fee is calculated here: https://github.com/sherlock-audit/2024-05-elfi-protocol/blob/8a1a01804a7de7f73a04d794bf6b8104528681ad/elfi-perp-contracts/contracts/process/FeeProcess.sol#L82-L85
Another case from same root cause: Isolated accounts can close a LONG position that is in losses to secure their initial margin back, effectively escalating any losses that are occurred.
Coded PoC:
Test Logs: account info Result(2) [ Result(4) [ 500000000000n, 0n, 0n, 0n ], Result(4) [ 0n, 1000000000000000000n, 0n, 3000000000000000n ] ] Position initial margin 997000000000000000n Position initial margin in USD 24925000000000000000000n Position initial margin from 0n Position qty 49850000000000000000000n account info Result(2) [ Result(4) [ 500000000000n, 0n, 0n, 0n ], Result(4) [ 0n, 3000000000000000n, 0n, 3000000000000000n ] ] Position initial margin 0n Position initial margin from 0n Position initial margin in USD 4985000000000000000000n Position qty 49850000000000000000000n
Impact
Most obvious one I found is that the account no longer pays borrowing fees because of multiplication with "0" which is a high by itself alone. Also, please refer to the other case explained in vulnerability details section where isolated order escapes the losses and secures the initial margin.
Code Snippet
https://github.com/sherlock-audit/2024-05-elfi-protocol/blob/8a1a01804a7de7f73a04d794bf6b8104528681ad/elfi-perp-contracts/contracts/process/PositionMarginProcess.sol#L134-L229
https://github.com/sherlock-audit/2024-05-elfi-protocol/blob/8a1a01804a7de7f73a04d794bf6b8104528681ad/elfi-perp-contracts/contracts/process/PositionMarginProcess.sol#L370-L407
Tool used
Manual Review
Recommendation