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

KupiaSec - The protocol should consider the variance of quote tokens' price #113

Closed
sherlock-admin3 opened this issue Sep 9, 2024 · 5 comments
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Escalation Resolved This issue's escalations have been approved/rejected Medium A Medium severity issue. Reward A payout will be made for this issue

Comments

@sherlock-admin3
Copy link
Contributor

sherlock-admin3 commented Sep 9, 2024

KupiaSec

Medium

The protocol should consider the variance of quote tokens' price

Summary

The protocol uses the USD price of base token and it assumes quote token is stablecoin: fixed conversion rate of 1 USD = 1 quote token.
But the price of stablecoin can be changed.
There is a recent depeg event in March 2023, where USDC price went as low as 87 cents(Reference).
As a result, if there is variance of quote token, all the conversion between base and quote is incorrect and this can break the protocol's design.

Root Cause

In oracle.vy:89, it returns the USD price of base token regardless of quote token's price.

Internal pre-conditions

None

External pre-conditions

None

Attack Path

None

Impact

The quote token's price variance causes incorrect calculation of token amount and breaks the protocol's design.

PoC

The oracle provides the USD price of base token and the protocol uses the USD price regardless of quote token's price here.

def base_to_quote(tokens: uint256, ctx: Ctx) -> uint256:
  lifted : Tokens  = self.lift(Tokens({base: tokens, quote: ctx.price}), ctx)
  amt0   : uint256 = self.to_amount(lifted.quote, lifted.base, self.one(ctx))
  lowered: Tokens  = self.lower(Tokens({base: 0, quote: amt0}), ctx)
  return lowered.quote
def quote_to_base(tokens: uint256, ctx: Ctx) -> uint256: # tokens(0, 100ke6), ctx(50ke12, 18, 6)
  l1     : Tokens  = self.lift(Tokens({base: 0, quote: tokens}),    ctx) # tokens(0,100ke18) 
  l2     : Tokens  = self.lift(Tokens({base: 0, quote: ctx.price}), ctx) # tokens(0,50ke18) 
  vol0   : uint256 = self.from_amount(l1.quote, l2.quote, self.one(ctx)) # 100ke18 * 1e18 / 50ke18 = 2e18
  lowered: Tokens  = self.lower(Tokens({base: vol0, quote: 0}), ctx) # 2e18
  return lowered.base

If the quote token's price is changed, these functions return incorrect value.

Mitigation

Ideally, there needs to be an additional oracle to check current Price of quote token and take it's price into the consideration.

Duplicate of #52

@github-actions github-actions bot added the Excluded Excluded by the judge without consulting the protocol or the senior label Sep 11, 2024
@sherlock-admin3 sherlock-admin3 changed the title Dancing Topaz Perch - The protocol should consider the variance of quote tokens' price KupiaSec - The protocol should consider the variance of quote tokens' price Sep 11, 2024
@sherlock-admin3 sherlock-admin3 added the Non-Reward This issue will not receive a payout label Sep 11, 2024
@KupiaSecAdmin
Copy link

Escalate

This issue deserves Medium.
Information required for this issue to be rejected.

@sherlock-admin3
Copy link
Contributor Author

Escalate

This issue deserves Medium.
Information required for this issue to be rejected.

You've created a valid escalation!

To remove the escalation from consideration: Delete your comment.

You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.

@WangSecurity
Copy link

After additionally considering this issue, here's my understanding. Let's assume a scenario of 30% depeg and USDT = 0.7 USD.

  1. The pool has 10 BTC and 500k USDT.
  2. User deposits 1 BTC and 50k USDT, assuming 1 BTC = 50k USDT = 50k USD.
  3. USDT depegs to 0.7 USD, i.e. 1 USDT = 0.7 USD. Then BTC = 50k USD = ~71.5k USDT.
  4. The user withdraws 1 BTC and 50k USDT. They receive it because the code still considers 1 USDT = 1 USD. There are 10 BTC and 500k USDT left in the contracts.
  5. The protocol didn't lose any funds, the amount of BTC and USDT remained the same as it was before the depeg.
  6. But, in reality, the user has withdrawn 50k worth of BTC and 35k worth of USDT since 1 USDT = 0.7 USD.
  7. Hence, if the protocol accounted for the depeg, there had to be 10 BTC and 515k USDT left in the contract after the user had withdrawn during the depeg.

Hence, even though it's not a direct loss of funds but a loss in value, this should be a valid medium (considering depeg as an extensive limitation). Thus, planning to accept the escalation and duplicate with #52, since it does a better job of explaining the issue.
Are there additional duplicates?

@WangSecurity WangSecurity added Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Medium A Medium severity issue. and removed Excluded Excluded by the judge without consulting the protocol or the senior labels Oct 2, 2024
@sherlock-admin2 sherlock-admin2 added Reward A payout will be made for this issue and removed Non-Reward This issue will not receive a payout labels Oct 2, 2024
@WangSecurity
Copy link

Result:
Medium
Duplicate of #52

@sherlock-admin2 sherlock-admin2 removed the Escalated This issue contains a pending escalation label Oct 2, 2024
@sherlock-admin3 sherlock-admin3 added the Escalation Resolved This issue's escalations have been approved/rejected label Oct 2, 2024
@sherlock-admin4
Copy link
Contributor

Escalations have been resolved successfully!

Escalation status:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Escalation Resolved This issue's escalations have been approved/rejected Medium A Medium severity issue. Reward A payout will be made for this issue
Projects
None yet
Development

No branches or pull requests

5 participants