Jolly Mauve Parakeet
High
Users pay all protocol fees, which are deducted from their positions when they make trades. However, they do not pay referral fees or solver fees; instead, the protocol covers those costs.
All fees should be subtracted from users account, so there is this code which update local position
function _response(
CheckpointAccumulationResult memory result
) private pure returns (CheckpointAccumulationResponse memory response) {
response.collateral = result.collateral
.add(result.priceOverride)
.sub(Fixed6Lib.from(result.tradeFee))
.sub(result.offset)
.sub(Fixed6Lib.from(result.settlementFee));
response.liquidationFee = result.liquidationFee;
response.subtractiveFee = result.subtractiveFee;
response.solverFee = result.solverFee;
}
packages/perennial/contracts/libs/CheckpointLib.sol#L108
Later there is an additional accumulation.liquidationFee
substraction here
function update(
Local memory self,
uint256 newId,
CheckpointAccumulationResponse memory accumulation
) internal pure {
self.collateral = self.collateral.add(accumulation.collateral).sub(Fixed6Lib.from(accumulation.liquidationFee));
self.latestId = newId;
}
perennial-v2/packages/perennial/contracts/types/Local.sol#L52
The subtractiveFee and solver fees are not accounted for anywhere inside CheckpointLib
like other fees, which leads to a situation where the coins in the market will not match the sum of local accounts.
No response
No response
No response
Broken accounting will lead to someone being unable to retrieve their funds. Whether it’s a user, liquidator, referral, or the protocol, they may not receive their funds due to the accounting issue.
No response
function _response(
CheckpointAccumulationResult memory result
) private pure returns (CheckpointAccumulationResponse memory response) {
response.collateral = result.collateral
.add(result.priceOverride)
.sub(Fixed6Lib.from(result.tradeFee))
.sub(result.offset)
.sub(Fixed6Lib.from(result.settlementFee))
+ .sub(Fixed6Lib.from(result.subtractiveFee))
+ .sub(Fixed6Lib.from(result.solverFee));
response.liquidationFee = result.liquidationFee;
response.subtractiveFee = result.subtractiveFee;
response.solverFee = result.solverFee;
}