Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Valid

Fee Recipient Shares Cannot Be Decreased When Total Fee recipients’s share is at Max Limit

Summary

When the total fee recipient shares reach the maximum limit, reducing a recipient’s share is blocked due to a validation check. This prevents owners from updating feeBps for existing recipients.

Vulnerability Details

The configureFeeRecipient allows owner to add , remove or update shares of recipient’s . when we calls this function it first validate that the newShare value will not exceeds the max limit of allows recipients’s shares.

/home/aman/Desktop/audits/2025-01-zaros-part-2/src/market-making/branches/MarketMakingEngineConfigurationBranch.sol:613
613: function configureFeeRecipient(address feeRecipient, uint256 share) external onlyOwner {
614: // revert if protocolFeeRecipient is set to zero
615: if (feeRecipient == address(0)) revert Errors.ZeroInput("feeRecipient");
616:
617: // load market making engine configuration data from storage
618: MarketMakingEngineConfiguration.Data storage marketMakingEngineConfiguration =
619: MarketMakingEngineConfiguration.load();
620:
621: // check if share is greater than zero to verify the total will not exceed the maximum shares
622: if (share > 0) {
623: UD60x18 totalFeeRecipientsSharesX18 = ud60x18(marketMakingEngineConfiguration.totalFeeRecipientsShares);
624:
625: if (
626: totalFeeRecipientsSharesX18.add(ud60x18(share)).gt(
627: ud60x18(Constants.MAX_CONFIGURABLE_PROTOCOL_FEE_SHARES)
628: )
629: ) {
630: revert Errors.FeeRecipientShareExceedsLimit();
631: }
632: }
633:
634: (, uint256 oldFeeRecipientShares) = marketMakingEngineConfiguration.protocolFeeRecipients.tryGet(feeRecipient);
635:
636: // update protocol total fee recipients shares value
637: if (oldFeeRecipientShares > 0) {
638: if (oldFeeRecipientShares > share) {
639: marketMakingEngineConfiguration.totalFeeRecipientsShares -=
640: (oldFeeRecipientShares - share).toUint128();
641: } else {
642: marketMakingEngineConfiguration.totalFeeRecipientsShares +=
643: (share - oldFeeRecipientShares).toUint128();
644: }
645: } else {
646: marketMakingEngineConfiguration.totalFeeRecipientsShares += share.toUint128();
647: }
648:
649: // update protocol fee recipient
650: marketMakingEngineConfiguration.protocolFeeRecipients.set(feeRecipient, share);
651:
652: // emit event LogConfigureFeeRecipient
653: emit LogConfigureFeeRecipient(feeRecipient, share);
654: }

The above code will not work as intended , as in case if the totalFeeRecipientsSharesX18=MAX_CONFIGURABLE_PROTOCOL_FEE_SHARES and owner wants to decrease share of specfic recipient’s it will always revert due to check before removal of shares. The following POC will demonstrates it.

POC

/test/integration/market-making/market-making-engine-configuration-branch/configureFeeRecipient/configureFeeRecipieint.t.sol:39
39: function test_totalFeeRecipientsShare_is_max_poc() external { // @audit POC
40: address user1 = address(0x1234);
41: address user2 = address(0x5678);
42: marketMakingEngine.configureFeeRecipient(user1, 0.8e18); // set user1 share to 0.8
43: marketMakingEngine.configureFeeRecipient(user2, 0.1e18); // set user2 share to 0.1
44: // shares are already at max limit i.e 0.9e18
45: // will not allow to update user1 share after words
46: marketMakingEngine.configureFeeRecipient(user1, 0.7e18); // update user1 share to 0.7
47: }

run the Test with Command : forge test --mt test_totalFeeRecipientsShare_is_max_poc

Impact

Owners cannot reduce a recipient’s feeBps when the total fee recipients’ shares are at the maximum limit.

Tools Used

Manual Review

Recommendations

Modify the configureFeeRecipient function to allow fee share reductions even when the total shares are at the max limit. Proposed Fix:

diff --git a/src/market-making/branches/MarketMakingEngineConfigurationBranch.sol b/src/market-making/branches/MarketMakingEngineConfigurationBranch.sol
index 6fcb388..c374564 100644
--- a/src/market-making/branches/MarketMakingEngineConfigurationBranch.sol
+++ b/src/market-making/branches/MarketMakingEngineConfigurationBranch.sol
@@ -621,17 +621,7 @@ contract MarketMakingEngineConfigurationBranch is OwnableUpgradeable {
// check if share is greater than zero to verify the total will not exceed the maximum shares
// @audit : what if share is already on 0.9e18 limit , and we want to decrease share of a user how can we do that ?
- if (share > 0) {
- UD60x18 totalFeeRecipientsSharesX18 = ud60x18(marketMakingEngineConfiguration.totalFeeRecipientsShares);
-
- if (
- totalFeeRecipientsSharesX18.add(ud60x18(share)).gt(
- ud60x18(Constants.MAX_CONFIGURABLE_PROTOCOL_FEE_SHARES)
- )
- ) {
- revert Errors.FeeRecipientShareExceedsLimit();
- }
- }
+
(, uint256 oldFeeRecipientShares) = marketMakingEngineConfiguration.protocolFeeRecipients.tryGet(feeRecipient);
@@ -649,7 +639,17 @@ contract MarketMakingEngineConfigurationBranch is OwnableUpgradeable {
} else {
marketMakingEngineConfiguration.totalFeeRecipientsShares += share.toUint128();
}
+ if (share > 0) {
+ UD60x18 totalFeeRecipientsSharesX18 = ud60x18(marketMakingEngineConfiguration.totalFeeRecipientsShares);
+ if (
+ totalFeeRecipientsSharesX18.gt(
+ ud60x18(Constants.MAX_CONFIGURABLE_PROTOCOL_FEE_SHARES)
+ )
+ ) {
+ revert Errors.FeeRecipientShareExceedsLimit();
+ }
+ }
// update protocol fee recipient
marketMakingEngineConfiguration.protocolFeeRecipients.set(feeRecipient, share);
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

MarketMakingEngineConfigurationBranch::configureFeeRecipient can cause DOS when attempting to change share value of an existing address

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.