Skip to content

Liquity V2 report#203

Open
RickGriff wants to merge 12 commits intodeficollective:mainfrom
RickGriff:main
Open

Liquity V2 report#203
RickGriff wants to merge 12 commits intodeficollective:mainfrom
RickGriff:main

Conversation

@RickGriff
Copy link

No description provided.

@vercel
Copy link

vercel bot commented Jul 7, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
defiscan ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 5, 2025 5:04pm

Copy link
Member

@emduc emduc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for your submission Rick! It's a high-quality review, and I appreciate that you adapted to our new layout.

It looks like there are compilation issues, could you please look into it? Happy to help out if you have any issues.

My main comment is on the autonomy section, I left a few clarification questions that should help us clarify how to consider the chainlink dependency.

Most other comments are about style; we try to use codestyle for contract and token names, as well as Cursive Text for module names.

For completeness, could you please add the permissions for the BoldToken's setBranchAddresses and setCollateralRegistry functions? When it's not obvious in the name that a function is used to initialise the contract, we still document it and specify that in the description.

Comment on lines +54 to +58
If the market oracle or LST exchange rate fails on a given collateral branch, the system shuts that branch down: it freezes new debt issuance, and enables “urgent redemptions” in order to clear debt and collateral as fast as possible. Borrowers are free to repay BOLD, withdraw collateral and close their loans on the shut down branch.

Additionally, if a branch’s LST market oracle fails, the branch falls back to pricing collateral via a combination of the LST exchange rate and ETH-USD price.

Finally, each collateral branch uses the "last good price" as a last resort if all its price sources become untrusted. This ensures the protocol can continue pricing collateral without interruption, minimizing the impact of oracle failure on its operations. Despite its reliance on external oracles, Liquity v2’s branch shutdown mechanism and fallback pricing logic mitigate the risk of disruption due to price source failure.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify a few points, so that we can ensure this fits a Low centralization score for autonomy:

  • How do you qualify an "Oracle failure", is it simply the Oracle returning 0, or do you also have other measures to prevent Oracle manipulation?
  • As I understand it you use RETH's smart contract exchange rates first, is that also the case for WSTEH or do you use Chainlink's WSTETH-USD primarily?
  • Is the "Last good price" stored in Liquity v2 contracts, or are you referring to Chainlink oracle's last pushed price?
  • Can you define "Urgent redemption" ? Do all positions become redeemable?

Copy link
Author

@RickGriff RickGriff Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you qualify an "Oracle failure", is it simply the Oracle returning 0, or do you also have other measures to prevent Oracle manipulation?

V2 deems a Chainlink market oracle to have failed if 1) it returns a price of 0, 2) the call to the oracle reverts or 3) the oracle price has been stale for too long. The staleness thresholds are 24 hours for ETH-USD and STETH-USD (which have update heartbeats of 1 hour) and 48 hours for RETH-ETH (which has an update heartbeat of 24 hours).

Additionally, V2 deems an LST exchange rate to have failed if 1) it returns a value of 0 or 2) the call to the LST contract reverts.

There's no way for any protocol to rigorously detect and prevent all possible oracle manipulation. Whatever thresholds/logic a protocol implements, a malicious actor with technical or economic control over the oracle's price can "fly under the radar" of the protocol's logic/thresholds.

However, V2 still has measures to protect users against oracle manipulation. It uses the "worst" (highest) price for redemptions on WSTETH and RETH branches in order to mitigate adverse redemption arbs, and on the RETH branch, it uses the "worst" (lowest) price for borrowing and liquidations. This mitigates excessive BOLD minting if the RETH market oracle were to be manipulated upwards. This last protection was added since RETH historically has lower liquidity than STETH and market oracle may be more manipulable.

As I understand it you use RETH's smart contract exchange rates first, is that also the case for WSTEH or do you use Chainlink's WSTETH-USD primarily?

It's a bit more involved - the price calculation depends on both the branch and the operation (i.e. borrowing/liquidation vs redemption). The full logic is laid out here:
https://github.com/liquity/bold?tab=readme-ov-file#choice-of-oracles-and-price-calculations

Is the "Last good price" stored in Liquity v2 contracts, or are you referring to Chainlink oracle's last pushed price?

Yes, it's stored in v2 contracts. At a given price fetch, the price is calculated according to the logic above - i.e. based on the branch, the user operation and the state of the branch's price sources (i.e. if any have failed or not). That calculated price is then stored as the lastGoodPrice.

Can you define "Urgent redemption" ? Do all positions become redeemable?

Yes, urgent redemptions are a special operation that is enabled once a branch has been shut down (due to oracle failure or insufficient collateralization). With urgent redemptions:

  • Any Trove can be directly redeemed from, regardless of interest rate ordering
  • No redemption fee is charged
  • The redeemer earns a 2% collateral bonus - i.e. for every 1 BOLD redeemed they receive $1.02 worth of collateral

The intent is to clear the debt of the shut down branch as quickly as possible. Borrowers can also close their Trove at any point after a shut down.

https://github.com/liquity/bold?tab=readme-ov-file#urgent-redemptions

Co-authored-by: Emilien Duc <56789637+emduc@users.noreply.github.com>
RickGriff and others added 5 commits July 24, 2025 13:10
Co-authored-by: Emilien Duc <56789637+emduc@users.noreply.github.com>
Co-authored-by: Emilien Duc <56789637+emduc@users.noreply.github.com>
Co-authored-by: Emilien Duc <56789637+emduc@users.noreply.github.com>
Co-authored-by: Emilien Duc <56789637+emduc@users.noreply.github.com>
Co-authored-by: Emilien Duc <56789637+emduc@users.noreply.github.com>
@RickGriff
Copy link
Author

Thanks! Addressed the questions and added the additional permissioned functions. Will look into the compilation issue shortly

@RickGriff
Copy link
Author

RickGriff commented Jul 25, 2025

Btw, I'm unable to view the Vercel preview / deployment - think I don't have permission. Can you let me know what needs fixing and/or give permission?

@emduc
Copy link
Member

emduc commented Jul 25, 2025

Btw, I'm unable to view the Vercel preview / deployment - think I don't have permission. Can you let me know what needs fixing and/or give permission?

Yes the error is regarding the date, the publish date should be non-empty even though it's not published yet. You can also check locally by running npm run dev or npm run build

@RickGriff
Copy link
Author

Yes the error is regarding the date, the publish date should be non-empty even though it's not published yet. You can also check locally by running npm run dev or npm run build

Thanks! Fixed, I set all dates (submission, publish, update) to today.

@emduc
Copy link
Member

emduc commented Aug 19, 2025

Thanks for incorporating the diagram and explanation. It would actually be in the section "Protocol Analysis", which you already have but is currently empty.

Regarding "Autonomy", and "Dependencies", here is a suggestion. Unfortunately, that would bring the score to High for Autonomy, and Stage 0 as a result.

Autonomy

Liquity v2 relies on a combination of external Chainlink market oracles - ETH-USD, RETH-ETH and STETH-USD - as well as LST smart contract exchange rates in order to price collateral.

Several mitigations are in place to handle oracle failure and minimise its impact. If the market oracle or LST exchange rate fails on a given collateral branch, the system shuts that branch down: it freezes new debt issuance, and enables “urgent redemptions” in order to clear debt and collateral as fast as possible. Borrowers are free to repay BOLD, withdraw collateral and close their loans on the shut down branch.

Additionally, if a branch’s LST direct oracle fails, the branch falls back to pricing collateral via a combination of the LST exchange rate and ETH-USD price.

Finally, each collateral branch uses the "last good price" as a last resort if all its price sources fail. This ensures the protocol can continue pricing collateral without interruption, minimizing the impact of oracle failure on its operations.

Nonetheless, although different price sources might be used, each price calculation includes an oracle provided by Chainlink. Chainlink was reviewed to be of High centralization in a separate report. Since none of the mitigations account for oracle manipulation of both price feeds, this results in a High centralization risk score for the Autonomy section.

Autonomy score: High

Depedencies

The system has the following external dependencies:

  • LST ERC20 tokens: RocketPool ETH (RETH) and Lido Wrapped Staked ETH (WSTETH)

  • Chainlink market oracles: ETH-USD, RETH-ETH and STETH-USD

Any problem or failure with the collateral contracts could have a significant impact on the Liquity v2 system. However, the system separates different collateral branches and shuts a collateral branch down if the branch collateralization ratio falls too low, or if the LST’s smart contract exchange rate fails. Thus, it does its best to mitigate economic or technical collateral failure and remain functional.

Similarly, if a market oracle fails, the system shuts down the corresponding branch and falls back to a backup price calculation (see the Autonomy section for details).

In either case of LST exchange rate or market oracle failure, the branch blocks new debt issuance and allows existing users to withdraw their assets.

For LST collateral branches which have two price sources (direct rate and LST contract rate combined with ETH-USD), the protocol has different dynamics to mitigate the manipulation of one of the two price feeds. Nonetheless, both sources include a Chainlink price feed. Chainlink was reviewed to be of High centralization in a separate report. None of the mitigations account for oracle manipulation of both price feeds. Chainlink, therefore, has the power to trigger liquidations or branch shutdowns, with the additional power to sell off the debt (urgent redemption) at an arbitrary price. For those reasons, the Autonomy centralization risk score is High.

Thoughts

I realise this is both surprising and annoying. Since the protocol is immutable, there are actually no ways for Bold to become Stage 2 now...
We do realise that those are extreme cases, and that manipulation can also go undetected in smart contracts. The key critical factor here is that the entire protocol could be almost instantly liquidated, leading to the complete loss of user funds. On the other hand, with max price deviations or using multiple oracle sources, you're not bulletproof, but those cases are not theoretically feasible anymore.

Mitigations that would have been valid include: max price slippage tolerance / bounds, Using multiple price sources., etc.

Happy to hear your thoughts and debate further

@RickGriff
Copy link
Author

RickGriff commented Sep 16, 2025

Coming back to this, we would question the ranking relative to other DeFi systems with similar oracle dependencies.

Of the systems currently ranked in DefiScan, it seems there are only two that a) use external oracles and b) have ratings better than Stage 0: Liquity v1 and Morpho.

Your main concern with Liquity v2 seems to be the Chainlink oracle dependency. As you mention, if that oracle were controlled by a malicious actor, they could push very low ETH & LST prices and liquidate and/or urgent-redeem all branches.

We’d add that very similar risks exist for both Liquity v1 and Morpho vaults:

  • A malicious actor with control of Liquity v1’s primary oracle could push successively lower ETH prices with consecutive 49% deviations, i.e. below the fallback threshold. The manipulated price would decrease extremely rapidly, declining by ~97% within just 5 blocks, e.g. 1 minute. That would be sufficient to liquidate/redeem the entire v1 system without triggering the switch to the fallback oracle.

  • A large fraction of Morpho vaults use Chainlink oracles - your report mentions they secure ~30% of Morpho’s TVL. The remaining vaults also use external oracles with Chainlink interfaces - presumably the majority of those are Chainlink competitors such as Pyth and Redstone, etc. These have centralization risks comparable to Chainlink - so it seems that Morpho vaults inherit very similar oracle dependency risks as Liquity v1 and v2. Any given vault could be wrecked by its rogue oracle.

Since oracle risk is the limiting factor, then it seems to us that Liquity v1, Morpho and Liquity v2 should all be rated at the same Stage for consistency. Happy to hear your thoughts.

@emduc
Copy link
Member

emduc commented Sep 18, 2025

Thanks for following up!

To complement the existing DeFiScan reviews, Sky would have a medium autonomy score in terms of oracle because they use Chronicle. In addition to that, they also have a 1-hour delay on price updates to allow emergency freezes. The reason their Autonomy score is High risk is because of Circle. Similarly, Spark would actually have Low risk in terms of oracle provider, as they use 3 oracle providers and take the median price (chainlink, redstone, chronicle), they used to only use chronicle which was already medium risk, the review is to be updated, the reason they have high autonmy risk is due to the dependency on Sky (Stage 0).

I hear your point for Liquity V1 and Morpho. As you highlight, using oracles is not a black-and-white issue; we can find a better balance and criteria for the V2 of the framework, with more granular consideration. Nonetheless, in the current framework, our quite straightforward approach doesn't leave a lot of wiggle room for a better Autonomy score in Liquity V2.

  • Is the dependency centralized -> Yes -> Does it have mitigations in case of malicious use -> No -> How much of the TVL relies on this dependency -> 100%

On the other hand, I absolutely understood that you make many more efforts than a lot of other DeFi protocols, even with immutable contracts, cases like the oracles retiring or failures are all taken into account, with the protection of user funds at heart, the deal breaker for the current framework lies solely in the fact that Chainlink is trusted to not act maliciously.

@RickGriff
Copy link
Author

Btw, we've discussed this with one of the primary Liquity v2 auditors, ChainSecurity - and this was the feedback they gave:

I’d say Liquity V1 and V2 Oracles address different sets of failure cases. Permanent failure of the oracles is a scenario that is better handled by V2. As described the docs

V2: “Verify each oracle answer. If any oracle used is deemed to have failed, disable the PriceFeed and shut the branch down.”
.
V1: "We believe the benefit of the fallback logic is worth the complexity, given that our system is entirely immutable - if we had no fallback logic and Chainlink were to be hacked or permanently fail, Liquity would become permanently unusable anyway."
.
The Oracle contract in Liquity V2 is much simpler, however the rest of the protocol handles oracle failures far more gracefully. In V2, if the oracle detects a failure, it triggers a shutdown of the affected branch, whereas in V1 the system continues operating with the last known good price. The V2 shutdown prevents new positions from being opened, and the urgent redemption mechanism incentivizes bots to reduce the overall debt (and hereby risk) of the system. In my (personal) opinion, this design does a better job at protecting existing Trove and BOLD holders better from losses caused by stale prices.

We think this is an important point - while both V1 and V2 are equally exposed to the risk of the primary oracle going rogue, in case of a technical oracle failure, V2 immediately atttempts to limit the damage (branch shutdown + borrowing restrictions), and clear the branch debt as quickly as possible (urgent redemptions).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants