_globalPositions.marginDepositedTotal can underflow
Summary
The _globalPositions.marginDepositedTotal could underflow.
Vulnerability Detail
This is very similar to a finding that I reported but has a different cause.
Let's take a look at a settleFundingFees function. This function is used to settle the currently unrecorded funding fees and update the _globalPositions.marginDepositedTotal.
In an edge case where funding fees haven't been settled for long, this can produce an incorrect state. First, we need to look at the _accruedFundingTotalByLongs function. By looking at a function we can see that the result can be either positive or negative based on the unrecodedFunding.
If the unrecordedFunding < 0 this means that shorts have to pay to the longs and if unrecordedFunding > 0 the longs have to pay to the shorts.
When unrecordedFunding > 0 this means profit for the shorts and the return value of the function is negative.
function _accruedFundingTotalByLongs(
FlatcoinStructs.GlobalPositions memory globalPosition,
int256 unrecordedFunding
) internal pure returns (int256 accruedFundingLongs) {
return -int256(globalPosition.sizeOpenedTotal)._multiplyDecimal(unrecordedFunding);
}
Consider the following scenario:
_globalPositions.marginDepositedTotal = 1 ether
_fundingFees = -1.1 ether => it should go to the shorts so we subtract the amount from the longs
Since _fundingFees are negative it means they have to be subtracted from the marginDepositedTotal as the fee for the shorts. Since marginDepositedTotal > _fundingFees the marginDepositedTotal will underflow because
If we plug in the numbers
= uint256(int256(1 ether) - 1.1 ether) => the problem is that the intermediate calculation results into int256 and is unsafely cast to uint256. Even with a new solidity version >0.8.0 this can underflow.
evmboi32
medium
_globalPositions.marginDepositedTotal can underflow
Summary
The
_globalPositions.marginDepositedTotal
could underflow.Vulnerability Detail
This is very similar to a finding that I reported but has a different cause.
Let's take a look at a
settleFundingFees
function. This function is used to settle the currently unrecorded funding fees and update the_globalPositions.marginDepositedTotal
.In an edge case where funding fees haven't been settled for long, this can produce an incorrect state. First, we need to look at the
_accruedFundingTotalByLongs
function. By looking at a function we can see that the result can be either positive or negative based on the unrecodedFunding.If the
unrecordedFunding < 0
this means that shorts have to pay to the longs and ifunrecordedFunding > 0
the longs have to pay to the shorts.When
unrecordedFunding > 0
this means profit for the shorts and the return value of the function is negative.Consider the following scenario:
_globalPositions.marginDepositedTotal
=1 ether
_fundingFees
=-1.1 ether
=> it should go to the shorts so we subtract the amount from the longsSince
_fundingFees
are negative it means they have to be subtracted from themarginDepositedTotal
as the fee for the shorts. SincemarginDepositedTotal > _fundingFees
themarginDepositedTotal
will underflow because_globalPositions.marginDepositedTotal = uint256(int256(_globalPositions.marginDepositedTotal) + _fundingFees)
If we plug in the numbers =
uint256(int256(1 ether) - 1.1 ether)
=> the problem is that the intermediate calculation results intoint256
and isunsafely cast
touint256
. Even with a new solidity version>0.8.0
this can underflow.Try it out in remix. The return value underflows.
Impact
marginDepositedTotal
could underflow.Code Snippet
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/FlatcoinVault.sol#L216-L237
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/libraries/PerpMath.sol#L219-L224
Tool used
Manual Review
Recommendation
Instead of directly casting to uint256 use a safe cast that detects the underflow and accordingly sets the value to 0 instead.
Duplicate of #195