code-423n4 / 2021-05-fairside-findings

0 stars 0 forks source link

Flash minting and burning can reduce the paid fees when purchasing a membership or opening a cost share request #76

Open code423n4 opened 3 years ago

code423n4 commented 3 years ago

Handle

shw

Vulnerability details

Impact

Users can pay fewer FSD tokens when purchasing a membership or opening a cost share request by flash minting and burning FSD tokens, which could significantly affect the FSD spot price.

Proof of Concept

The function getFSDPrice returns the current FSD price based on the reserves in the capital pool (see lines 353-364 in contract FSDNetwork). Notice that when minting and burning FSD tokens, the fsd.getReserveBalance() increases but not the fShare. Therefore, according to the pricing formula, FairSideFormula.f, the FSD price increases when minting, and vice versa, decreases when burning.

When purchasing a membership, the number of FSD tokens that a user should pay is calculated based on the current FSD price, which is vulnerable to manipulation by flash minting and burning. Consider a user performing the following actions (all are done within a single transaction or flashbot bundle):

  1. The user mints a large number of FSD (by using flash loans) to raise the current FSD price.
  2. The user purchases a membership by calling purchaseMembership. Since the price of FSD is relatively high, the user pays fewer FSD tokens for the membership fee than before.
  3. The user burns the previously minted FSD tokens, losing 3.5% of his capital for the tribute fees.

Although the user pays for the 3.5% tribute fees, it is still possible to make a profit. Suppose that the price of FSD to ETH is p_1 and p_2 before and after minting, respectively. The user purchases a membership with x ETH costShareBenefit, and uses y ETH to flash mint the FSD tokens. In a regular purchase, the user pays 0.04x / p_1 FSD tokens, equivalent to 0.04x ETH. By performing flash mints and burns, the user pays 0.04x / p_2 FSD tokens, which is, in fact, equivalent to 0.04x * p_1 / p_2 ETH. He also pays 0.035y ETH for tribute fees. The profit user made is 0.04x * (1 - p1 / p2) - 0.035y (ETH), where p2 and y are dependent to each other but independent to x. Thus, the profit can be positive if costShareBenefit is large enough.

The same vulnerability exists when a user opens a cost share request, where the bounty to pay is calculated based on the current price of FSD tokens.

Referenced code: FSDNetwork.sol#L353-L364 FSDNetwork.sol#L145-L146 FSDNetwork.sol#L217-L222

Recommended Mitigation Steps

Force users to wait for (at least) a block to prevent flash minting and burning.

fairside-core commented 3 years ago

The issue relies on costShareBenefit being large enough which is inherently limited to a % of the capital pool, meaning that the arbitrage opportunity present here is inexistent or highly unlikely to be beneficial. Can we reach out to the submitter to request them to prove that even with the costShareBenefit % limit this is a sustainable attack by providing us with numbers? If no such numbers are present, I would decrease the severity of this to either minor (1) or none (0).

cemozerr commented 3 years ago

Will wait for a proof from the auditer, shw, for this one.

x9453 commented 3 years ago

Hi, thanks for giving me a chance to clarify this finding.

After realizing that a user's costShareBenefit is limited to a % of the capital pool (5% as specified in the code), I would say this attack is not successful according to the following estimation of the upper-bound of user's profit:

   User's profit
 = 0.04x * (1 - p1 / p2) - 0.035y
<= 0.04x - 0.035y
<= 0.04 * 0.05 * (z + y) - 0.035y
 = 0.002z - 0.033y 

where z is the amount of ETH in the capital pool before minting. A negative coefficient of y implies that using a flash loan does not help to increase the profit but to decrease it.

x9453 commented 3 years ago

After some thoughts, I think the estimation should also consider how flash loan affects on the FSD's price to be more accurate. According to the price formula, we have p1 = A + z^4 / (C * fShare^3) and p2 = A + (z + y)^4 / (C * fShare^3) (assuming the best case, where fShare does not increase). Let r = y / z, the ratio of flash loan to the capital pool, then we can approximate p1 / p2 = z^4 / (z + y)^4 = 1 / (r + 1)^4. Therefore,

  User's profit
= 0.04x * (1 - p1 / p2) - 0.035y
= 0.04 * 0.05 * (z + y) * (1 - 1 / (r + 1)^4) - 0.035y
= (0.002 * (r + 1) * (1 - 1 / (r + 1)^4) - 0.035r) * z
= f(r) * z

WolframAlpha tells us that f(r) < 0 for all r > 0, meaning that the user does not make a profit no matter how much flash loan he borrowed.

It is worth mentioning that different % of withdrawal fee, cost share benefit limit, and tribute fee could lead to different results. That is, the constants, 0.002 and 0.035, determine whether user's profit can be positive (i.e., there exists r > 0 s.t. f(r) > 0). Further calculation shows that this happens iff the product of the withdrawal fee and cost share benefit limit is greater than the tribute fee divided by 4, which is unlikely in normal settings. Please let me know if you need more details or a PoC on this.