Closed sherlock-admin closed 6 months ago
1 comment(s) were left on this issue during the judging contest.
auditsea commented:
The issue describes about DOSing setPool function by manipulating the Curve pool, but it's assumed that the Curve pool deployment, LP deposit, and setPool will be handled in one tx using multicall structure
1 comment(s) were left on this issue during the judging contest.
auditsea commented:
The issue describes about DOSing setPool function by manipulating the Curve pool, but it's assumed that the Curve pool deployment, LP deposit, and setPool will be handled in one tx using multicall structure
unforgiven
medium
attacker can DOS admins calls to setPool and prevent protocol from updating
Summary
Admin can call
setPool()
to set curve MetaPool to be used as a TWAP oracles in the protocol. the issue is that insetPool()
's code checks that for that pool_reserve0 == _reserve1
but attacker can always manipulate and change the reserves in the pool by performing swaps. so attacker can DOS and prevent admins from callingsetPool()
and admins can't update the curve pool and it may cause wrong TWAP price as it has to work with the old pool while the token of the protocol is updated to new address.also these lines in
setPool()
are incorrect too(this can be considered a separate issue):because there is no guarantee that price of the pool would be 1 to 1 always but the
require(_reserve0 == _reserve1)
bug prevents it. so ifrequired
has been removed then the average price should be calculated based on pool's real reserves.Vulnerability Detail
This is part of the
setPool()
code, as you can see it checks to make sure that reserve's of the pool for token 0 and 1 is equal:but reserves of the pool can be manipulated by attacker by performing swaps in the curve MetaPool and attacker can revert admins calls to
setPool()
just by performing swaps in the pool (attacker can front run any call tosetPool()
and change pool's reserves). the assumption that reserves should be equal because they are both stable coin is wrong and exact equality of reserves is not guaranteed in AMM pools even for stable coins. as protocol token is migrated to new address admins need to callsetPool()
to change the target pool and TWAP prices required correct pool to work. so by preventing update of the pool TWAP price would be wrong and mint and redeem functionality depends on the TWAP price and they will be broken too. This is the POC:setPool()
setting the
price0Average
andprice1Average
to 1 ether is wrong too(wrong assumptions about the pool) but it won't cause problem in the current code becauserequire(reserve0 == reserve1)
makes sure that price is 1 to 1, but if require has been removed then the average prices should be calculated correctly. in general this could be a separate issue that will be exploitable if therequire(reserve0 == reserve1)
has been fixed. setting wrong average price would give attacker opportunity to exploit other logics that depends on the TWAP price(logics that callsconsult()
). there are multiple logics in the code that calls TWAP price without updating the price first(like_incentivizeBuy()
or_incentivizeSell()
in LibCurveDollarIncentive,getDollarsToMint()
in LibDollarMintCalculator,mintClaimableDollars()
in LibCreditNftManager). attacker can call those logics aftersetPool()
transaction, and while the real average price is not 1 ether, code would execute those logics based on 1 ether average price.Impact
attacker can DOS updating the target metapool for TWAP price and it would break the core functionality of the protocol like mint and redeem.
Code Snippet
https://github.com/sherlock-audit/2023-12-ubiquity/blob/d9c39e8dfd5601e7e8db2e4b3390e7d8dff42a8e/ubiquity-dollar/packages/contracts/src/dollar/libraries/LibTWAPOracle.sol#L50-L51
Tool used
Manual Review
Recommendation
remove the unnecessary check or don't check for exact equality (perform this check: reserves should be in N% of each other)
Duplicate of #14