Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add premium doesn't collect fees #54

Open
c4-bot-5 opened this issue Dec 21, 2023 · 6 comments
Open

Add premium doesn't collect fees #54

c4-bot-5 opened this issue Dec 21, 2023 · 6 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working M-04 primary issue Highest quality submission among a set of duplicates selected for report This submission will be included/highlighted in the audit report sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons

Comments

@c4-bot-5
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2023-12-particle/blob/a3af40839b24aa13f5764d4f84933dbfa8bc8134/contracts/protocol/ParticlePositionManager.sol#L501

Vulnerability details

Summary

Fees are applied to premiums when a new position is opened, but the same mechanism is not enforced when margin is added to an existing position.

Impact

When a new position is created in the LAMM protocol, fees are collected in favor of the LP owner that provides the liquidity for the position. The fee is calculated by applying a configurable rate over the tokens "from" amounts:

https://github.com/code-423n4/2023-12-particle/blob/a3af40839b24aa13f5764d4f84933dbfa8bc8134/contracts/protocol/ParticlePositionManager.sol#L191-L201

191:         // pay for fee
192:         if (FEE_FACTOR > 0) {
193:             cache.feeAmount = ((params.marginFrom + cache.amountFromBorrowed) * FEE_FACTOR) / Base.BASIS_POINT;
194:             cache.treasuryAmount = (cache.feeAmount * _treasuryRate) / Base.BASIS_POINT;
195:             _treasury[cache.tokenFrom] += cache.treasuryAmount;
196:             if (params.zeroForOne) {
197:                 lps.addTokensOwed(params.tokenId, uint128(cache.feeAmount - cache.treasuryAmount), 0);
198:             } else {
199:                 lps.addTokensOwed(params.tokenId, 0, uint128(cache.feeAmount - cache.treasuryAmount));
200:             }
201:         }

The fee is applied to amountFromBorrowed, the "from" amount from the LP liquidity, and marginFrom, the user provided margin to cover the required amount for the swap and provide a premium in the position.

However, the same logic is not followed when the borrower adds more margin using addPremium(). In this case, the amounts are added in full to the position's premiums without incurring any fees.

This not only represents an inconsistent behavior (which may be a design decision), but allows the borrower to avoid paying part of the fees. The borrower can provide enough marginTo so that the swap can reach the required collateralTo amount, leaving the token "from" premium at zero. Then, in a second call, provide the needed premium to cover for eventual LP fees using addPremium(). This can be done with null liquidation risk and is greatly simplified by leveraging the multicall functionality. The borrower can bundle both operations in a single transaction, without even deploying a contract.

Proof of Concept

A user can skip paying part of the fees by bundling two operations in a single transaction:

  1. A call to openPosition() with the minimal required amount of marginFrom so that amountReceived + amountToBorrowed + marginTo >= collateralTo.
  2. A call to addPremium() to provide the required premiums to cover for eventual fees.

Recommendation

Apply the same fee schedule to addPremium(). Depending on the value of zeroForOne, determine the "from" token, apply the FEE_FACTOR to it, and accrue the fee to the corresponding liquidity position.

Assessed type

Other

@c4-bot-5 c4-bot-5 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Dec 21, 2023
c4-bot-5 added a commit that referenced this issue Dec 21, 2023
@c4-judge
Copy link
Contributor

0xleastwood marked the issue as primary issue

@c4-judge c4-judge added the primary issue Highest quality submission among a set of duplicates label Dec 21, 2023
@wukong-particle
Copy link

I think this fee free premium is by design. We were only targeting the minimum required margin + the borrowed amount to calculate for fees. More friendly for traders.

@romeroadrian
Copy link

We were only targeting the minimum required margin + the borrowed amount to calculate for fees.

Correct, this is exactly what the issue is about (the title might be a bit misleading). The borrower can skip paying the "minimum required margin" part of the fees.

@wukong-particle
Copy link

Hmm sorry "minimum required margin" is the amount to meet collateralFrom/To. This margin cannot be skipped because otherwise opening a position won't have enough to cover collateralFrom/To.

@c4-sponsor
Copy link

wukong-particle (sponsor) acknowledged

@c4-sponsor c4-sponsor added the sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons label Dec 24, 2023
@c4-judge c4-judge added the selected for report This submission will be included/highlighted in the audit report label Dec 24, 2023
@c4-judge
Copy link
Contributor

0xleastwood marked the issue as selected for report

@C4-Staff C4-Staff added the M-04 label Jan 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working M-04 primary issue Highest quality submission among a set of duplicates selected for report This submission will be included/highlighted in the audit report sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons
Projects
None yet
Development

No branches or pull requests

6 participants