Skip to content

✨ auditor: add optional haircuts per market#11

Open
cruzdanilo wants to merge 1 commit into
mainfrom
haircut
Open

✨ auditor: add optional haircuts per market#11
cruzdanilo wants to merge 1 commit into
mainfrom
haircut

Conversation

@cruzdanilo
Copy link
Copy Markdown
Member

@cruzdanilo cruzdanilo commented May 12, 2026

Summary by CodeRabbit

  • New Features
    • Added optional per-market haircuts to auditor calculations, enabling fine-tuned collateral and debt adjustments for improved risk management across different markets.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Warning

Rate limit exceeded

@cruzdanilo has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 22 minutes and 59 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ff9d20ce-e6f8-4c73-b630-c614a6fc5196

📥 Commits

Reviewing files that changed from the base of the PR and between 663a4af and d7e6b99.

📒 Files selected for processing (6)
  • .changeset/brave-hoops-live.md
  • src/auditor/accountLiquidity.ts
  • src/auditor/borrowLimit.ts
  • src/auditor/healthFactor.ts
  • src/auditor/withdrawLimit.ts
  • test/auditor.test.ts

Walkthrough

The PR adds optional per-market haircuts to the auditor module, allowing collateral and debt to be adjusted by a per-market factor. The core accountLiquidity function is extended to accept and apply haircuts, with bounds validation. Dependent functions (borrowLimit, healthFactor, withdrawLimit) are updated to accept and forward the haircuts parameter. Tests validate haircut application and rejection of invalid values.

Changes

Auditor Optional Haircuts Per Market

Layer / File(s) Summary
Core haircut implementation and normalization
src/auditor/accountLiquidity.ts
Introduces Haircuts type as an optional mapping of per-market haircut factors. accountLiquidity gains a haircuts parameter (defaulting to defaultHaircuts) and applies per-market haircuts to collateral and debt adjustments. Validates each haircut is within [0, WAD], with special overflow handling when haircut equals WAD. Extends normalizeCollateral and normalizeDebt helpers with optional haircut parameters that scale WAD-based normalization.
Haircut propagation through dependent functions
src/auditor/borrowLimit.ts, src/auditor/healthFactor.ts, src/auditor/withdrawLimit.ts
borrowLimit, healthFactor, and withdrawLimit each accept an optional haircuts parameter and forward it to accountLiquidity. borrowLimit and withdrawLimit additionally apply per-market haircuts to their respective normalizeDebt and normalizeCollateral calls, enabling haircut-aware limit calculations.
Test coverage and release metadata
test/auditor.test.ts, .changeset/brave-hoops-live.md
Adds tests verifying accountLiquidity applies haircuts correctly, rejects invalid haircuts outside [0, 1] with error message, and validates that withdrawLimit and borrowLimit propagate haircuts and return smaller limits when haircuts are applied. Changeset documents patch release with "auditor: add optional haircuts per market" feature.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding optional per-market haircuts to the auditor module. It is concise, specific, and clearly conveys the primary feature addition.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch haircut

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces optional "haircuts" per market to the auditor's liquidity and limit calculations, allowing for more granular risk management. The changes update core functions like accountLiquidity, borrowLimit, and withdrawLimit to incorporate these factors into collateral and debt adjustments. Feedback identifies a critical ReferenceError due to an undefined default variable, a potential division-by-zero vulnerability in normalizeCollateral when a haircut is 100%, and recommends using case-insensitive lookups for market addresses to ensure consistent behavior.

Comment thread src/auditor/accountLiquidity.ts Outdated
Comment thread src/auditor/accountLiquidity.ts Outdated
Comment thread src/auditor/accountLiquidity.ts
Comment thread src/auditor/borrowLimit.ts Outdated
Comment thread src/auditor/withdrawLimit.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 94b5b796-39f0-4c78-b939-a01f0dbcec38

📥 Commits

Reviewing files that changed from the base of the PR and between f139e77 and 663a4af.

📒 Files selected for processing (6)
  • .changeset/brave-hoops-live.md
  • src/auditor/accountLiquidity.ts
  • src/auditor/borrowLimit.ts
  • src/auditor/healthFactor.ts
  • src/auditor/withdrawLimit.ts
  • test/auditor.test.ts

Comment thread src/auditor/accountLiquidity.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 663a4af24b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/auditor/accountLiquidity.ts Outdated
Comment thread src/auditor/accountLiquidity.ts Outdated
Comment thread src/auditor/accountLiquidity.ts
@sentry
Copy link
Copy Markdown

sentry Bot commented May 12, 2026

Codecov Report

❌ Patch coverage is 92.72727% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.36%. Comparing base (d9fedbc) to head (d7e6b99).

Files with missing lines Patch % Lines
src/auditor/accountLiquidity.ts 93.93% 0 Missing and 2 partials ⚠️
src/auditor/withdrawLimit.ts 77.77% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #11      +/-   ##
==========================================
+ Coverage   80.75%   81.36%   +0.61%     
==========================================
  Files          46       46              
  Lines         691      730      +39     
  Branches       96      109      +13     
==========================================
+ Hits          558      594      +36     
- Misses        128      129       +1     
- Partials        5        7       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: be0d59ccc2

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

}
adjDebt += adjustDebt(totalDebt, usdPrice, baseUnit, adjustFactor);
const debt = adjustDebt(totalDebt, usdPrice, baseUnit, adjustFactor);
adjDebt += haircut ? (haircut === WAD && debt !== 0n ? MAX_UINT256 : divWadUp(debt, WAD - haircut)) : debt;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Return zero debt for fully haircut zero balances

When a market has a 100% haircut and no borrow balance or fixed borrow positions, debt is 0n, so this falls through to divWadUp(0n, WAD - haircut) with a zero denominator. That makes otherwise valid collateral-only or unused markets crash in accountLiquidity (and therefore healthFactor, borrowLimit, and withdrawLimit) as soon as callers supply { [market]: WAD }; zero debt under a full haircut should contribute 0n rather than divide by zero.

Useful? React with 👍 / 👎.

}
adjDebt += adjustDebt(totalDebt, usdPrice, baseUnit, adjustFactor);
const debt = adjustDebt(totalDebt, usdPrice, baseUnit, adjustFactor);
adjDebt += haircut ? (haircut === WAD && debt !== 0n ? MAX_UINT256 : divWadUp(debt, WAD - haircut)) : debt;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't model infinite debt as a finite cap

When a fully haircut market has any debt, this substitutes the division-by-zero result with MAX_UINT256, but the rest of these helpers use unbounded bigint sums for collateral across markets. With enough collateral in other markets (for example two large collateral markets whose adjusted collateral totals above MAX_UINT256), healthFactor can still report a healthy account and borrowLimit can allow more borrowing even though debt divided by zero should make the account insolvent; represent this case as an explicit infinite/insolvent state rather than a finite additive value.

Useful? React with 👍 / 👎.

) {
if (haircut === WAD) return adjustedCollateral ? MAX_UINT256 : 0n;
return divWad(
mulDiv(haircut ? divWad(adjustedCollateral, WAD - haircut) : adjustedCollateral, baseUnit, usdPrice),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid over-withdrawing after haircut rounding

When a partially haircut market has prices or adjust factors that cause truncation, this floors the unhaircuted adjusted amount before converting back to raw assets, but accountLiquidity later floors the haircuted collateral contribution again. In those cases withdrawLimit can return a raw amount whose removal exceeds adjCollateral - minAdjCollateral by one adjusted unit and leaves the account just below the requested target health factor (for example with a 50% haircut and non-1e18 price/adjust factor), so the haircut path needs to round conservatively or verify the post-withdrawal contribution.

Useful? React with 👍 / 👎.

co-authored-by: itofarina <farinalvaro@gmail.com>
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.

1 participant