Skip to content

fix: apply minimal dLEND directional rounding patch#23

Draft
Git-on-my-level wants to merge 3 commits intomainfrom
fix/dlend-directional-rounding
Draft

fix: apply minimal dLEND directional rounding patch#23
Git-on-my-level wants to merge 3 commits intomainfrom
fix/dlend-directional-rounding

Conversation

@Git-on-my-level
Copy link
Contributor

@Git-on-my-level Git-on-my-level commented Mar 6, 2026

Draft PR: dLEND minimal directional rounding fix for pre-v3.5 extraction loops

Summary

This PR applies the smallest patch I am comfortable shipping from Aave v3.5 / PR 133 to close the supply-withdraw and borrow-repay rounding extraction class on Fraxtal dLEND.

It intentionally limits scope to the tokenization path and the withdraw-side balance calculation:

  • directional rayMul / rayDiv helpers
  • directional mint/burn accounting in ScaledBalanceTokenBase
  • aToken rounding biased in favor of the protocol/user-safe direction
  • variable debt rounding biased in favor of the protocol
  • SupplyLogic.executeWithdraw() using floor semantics for the user balance

It does not pull in the wider base-currency, liquidation, treasury, flashloan, or borrow-cap/account-data rounding refactors from upstream.

Why this scope

Upstream PR 133 is a superset. The core exploit fix for the loop-extraction issue is the directional rounding in the scaled token path (upstream commit e371a6b, plus the same withdraw-side floor behavior).

Broader upstream commits touch:

  • liquidation math
  • treasury accrual
  • available borrow calculations in base currency
  • flashloan/account-data rounding consistency

Those changes are useful, but they materially increase blast radius. For Fraxtal, where current practical exposure is already very low, the minimal safe fix is preferable.

Included files

  • contracts/lending/core/protocol/libraries/math/WadRayMath.sol
  • contracts/lending/core/protocol/tokenization/base/ScaledBalanceTokenBase.sol
  • contracts/lending/core/protocol/tokenization/AToken.sol
  • contracts/lending/core/protocol/tokenization/VariableDebtToken.sol
  • contracts/lending/core/protocol/libraries/logic/SupplyLogic.sol
  • contracts/lending/core/mocks/tests/RoundingHarnesses.sol
  • test/dlend/DirectionalRounding.test.ts

Semantics implemented

  • aToken mint: floor
  • aToken burn: ceil
  • aToken balanceOf: floor
  • aToken totalSupply: floor
  • aToken transfer scaled amount: ceil
  • variable debt mint: ceil
  • variable debt burn: floor
  • variable debt balanceOf: ceil
  • variable debt totalSupply: ceil
  • withdraw userBalance: floor

Test coverage

Focused Hardhat test added for the exact rounding semantics we want:

  • live dUSD liquidity index case
  • live dUSD variable borrow index case
  • upstream-style exact edge case for aToken floor mint/burn
  • upstream-style exact edge case for variable debt ceil mint/burn

Command run:

  • yarn hardhat compile
  • yarn hardhat test test/dlend/DirectionalRounding.test.ts

Result:

  • compile passed
  • focused rounding test: 4 passing

Upgrade path for Fraxtal

This patch changes logic only. It does not introduce new storage fields in upgradeable contracts.

Expected onchain rollout:

  1. Keep the affected market paused/frozen during rollout.
  2. Deploy new Pool implementation containing the SupplyLogic change.
  3. Update the pool proxy via PoolAddressesProvider.setPoolImpl(newPoolImpl).
  4. Deploy new AToken implementation.
  5. Deploy new VariableDebtToken implementation.
  6. For the affected reserve(s), call PoolConfigurator.updateAToken(...).
  7. For the affected reserve(s), call PoolConfigurator.updateVariableDebtToken(...).
  8. Verify reserve behavior on a fork:
    • supply/withdraw dust loop no longer extracts value
    • borrow/repay dust loop no longer extracts value
    • withdraw(type(uint256).max) behaves correctly at non-integer indices
  9. Move from pause to freeze if desired, then unfreeze after verification.

Explicitly deferred follow-ups

These are not part of this PR and should be evaluated separately if dLEND wants full v3.5 rounding parity:

  • GenericLogic available borrows base-currency rounding
  • liquidation debt/collateral base-currency rounding
  • treasury mint/accrual rounding fixes
  • flashloan rounding consistency
  • broader invariant/gas snapshot updates

Risk assessment

Low-to-moderate for the targeted issue class.

Reasons:

  • patch surface is narrow
  • no storage layout changes
  • behavior aligns with upstream directional semantics for the tokenization path
  • focused tests cover the known problematic edge cases

Residual risk:

  • this is not a full Aave v3.5 port
  • other non-extraction rounding inconsistencies remain until follow-up work is done

Added after initial draft

Attack reproduction

A focused regression reproduction now exists in test/dlend/DirectionalRounding.test.ts.

It demonstrates a concrete legacy supply-withdraw loop at the live dUSD liquidity index:

  • deposit 29 base units
  • legacy half-up mint rounds to 27 scaled units
  • legacy displayed balance rounds to 30
  • withdrawing that displayed balance extracts +1 base unit per loop

The test runs that loop 10 times side-by-side:

  • legacy path profit: +10 base units
  • fixed path profit: <= 0

Upgrade rollout scripts

Governance-aware rollout scripts were added:

  • deploy/25_dlend_directional_rounding/00_deploy_minimal_directional_rounding_impls.ts
  • deploy/25_dlend_directional_rounding/01_upgrade_minimal_directional_rounding.ts
  • shared helpers in utils/lending/directional-rounding-upgrade.ts

Behavior:

  • deploys the new L2Pool, AToken, and VariableDebtToken implementations
  • upgrades the Pool proxy and reserve token proxies
  • defaults to reserve dUSD
  • supports override via DLEND_DIRECTIONAL_ROUNDING_ASSETS=dUSD,...
  • uses direct execution when permissions exist, otherwise queues Safe governance transactions
  • skips already-upgraded proxies by reading the EIP-1967 implementation slot

Commands:

  • deploy implementations only:
    • yarn hardhat deploy --network fraxtal_mainnet --tags dlend-directional-rounding-deploy
  • queue/apply the upgrade:
    • yarn hardhat deploy --network fraxtal_mainnet --tags dlend-directional-rounding-upgrade
  • do both:
    • yarn hardhat deploy --network fraxtal_mainnet --tags dlend-directional-rounding

Validation

Ran:

  • yarn hardhat compile
  • yarn hardhat test test/dlend/DirectionalRounding.test.ts
  • yarn ts-typecheck

Results:

  • compile passed
  • rounding test: 5 passing
  • typecheck still has one pre-existing unrelated error in deploy/24_dusd_rate_update/00_update_dusd_rate_strategy.ts:58

@claude
Copy link
Contributor

claude bot commented Mar 6, 2026

Claude finished @Git-on-my-level's task —— View job


Code Review Analysis

I've completed a comprehensive review of this dLEND directional rounding fix PR. Here's my analysis:

Todo List:

  • Read repository CLAUDE.md for setup and guidelines
  • Review WadRayMath.sol directional rounding implementation
  • Analyze tokenization changes in AToken.sol and VariableDebtToken.sol
  • Examine ScaledBalanceTokenBase.sol modifications
  • Review SupplyLogic.sol withdrawal change
  • Evaluate test coverage in DirectionalRounding.test.ts
  • Assess security implications of rounding changes
  • Check for potential performance impacts
  • Provide comprehensive code review feedback

Overall Assessment: ✅ LGTM with Minor Suggestions

This is a well-scoped, security-focused fix that implements minimal directional rounding changes to prevent supply-withdraw and borrow-repay extraction loops. The implementation follows Aave v3.5 patterns with appropriate conservatism.

Code Quality & Best Practices: ⭐⭐⭐⭐⭐

Strengths:

  • Excellent scope discipline: Only touches the core tokenization path, avoiding risky broader changes
  • Consistent directional bias: aToken operations favor protocol, debt operations favor protocol safety
  • Clean abstractions: WadRayMath.Rounding enum provides clear intent
  • Proper assembly optimization: Maintains gas efficiency while adding directional logic
  • Conservative approach: Minimal changes vs full v3.5 port reduces risk

Minor suggestions:

  • Consider adding inline comments explaining the directional bias rationale (e.g., "Floor mint favors protocol")

Security Analysis: 🔒 Strong

✅ Prevents extraction loops:

  • rayMulFloor/rayDivFloor in aToken mint/balanceOf prevents over-crediting users
  • rayMulCeil/rayDivCeil in variable debt prevents under-debiting protocol
  • Floor withdrawal balance calculation in SupplyLogic.sol:line 298 prevents over-withdrawal

✅ Directional consistency:

  • AToken: Floor mint ➜ Ceil burn (protocol-favorable)
  • Variable debt: Ceil mint ➜ Floor burn (protocol-safe)
  • Transfer: Ceil scaled amount calculation is protocol-conservative

✅ No storage layout changes: Upgrade-safe implementation

⚠️ Residual considerations:

  • Other rounding inconsistencies remain (as acknowledged in PR description)
  • This doesn't address liquidation/treasury/flashloan rounding mentioned in the deferred items

Performance Analysis: ⚡ Minimal Impact

✅ Gas efficiency maintained:

  • Assembly optimizations preserved in WadRayMath.sol
  • Additional conditional overhead is minimal (single enum comparison)
  • No new external calls or storage operations

✅ Computational complexity unchanged:

  • Same mathematical operations, just with directional control
  • rayMulFloor/rayMulCeil variants use efficient assembly

Test Coverage: 🧪 Adequate for Scope

✅ Good edge case coverage:

  • Live dUSD indices (realistic scenarios)
  • Upstream-style exact edge cases at 2*RAY + 1
  • Both aToken and variable debt scenarios

✅ Comprehensive test scenarios:

  • DirectionalRounding.test.ts covers all four main rounding semantics
  • Harness contracts enable direct testing of internal methods

Suggestion for future:

  • Integration tests with actual supply/withdraw/borrow/repay loops would strengthen confidence
  • Fuzzing tests around index boundaries could catch edge cases

Potential Issues: ⚠️ Minor

  1. No validation of rounding parameter in _mintScaled/_burnScaled - While the enum constrains values, explicit validation could improve robustness

  2. Transfer function directional choice (rayDivCeil at ScaledBalanceTokenBase.sol:164) could be documented - the choice appears correct but rationale unclear

  3. Testing harness exposure - RoundingHarnesses.sol exposes internal methods; ensure this stays in test scope only

Code Specific Observations:

WadRayMath.sol (/contracts/lending/core/protocol/libraries/math/WadRayMath.sol):

  • Lines 97-102, 143-148: Clean enum-based routing to directional variants
  • Lines 104-123: Efficient floor/ceil implementations with proper overflow checks
  • Line 121: iszero(iszero(mod(product, RAY))) is a clever way to add 1 if remainder exists

ScaledBalanceTokenBase.sol (/contracts/lending/core/protocol/tokenization/base/ScaledBalanceTokenBase.sol):

  • Lines 87, 121: Proper parameterized rounding in mint/burn
  • Line 125: reverseRounding() usage is mathematically sound for balance calculations

AToken.sol (/contracts/lending/core/protocol/tokenization/AToken.sol):

  • Lines 106, 116, 127: Consistent Floor/Ceil pattern for mint/burn/treasury
  • Lines 139, 150: Floor semantics in balanceOf/totalSupply prevent over-reporting

VariableDebtToken.sol (/contracts/lending/core/protocol/tokenization/VariableDebtToken.sol):

  • Lines 100, 113, 118, 124: Proper ceil operations ensuring protocol never under-reports debt

Recommendations:

  1. ✅ Approve and merge - This addresses the stated security concern effectively
  2. 📝 Document the directional choices in comments for future maintainers
  3. 🧪 Consider adding integration-level loop extraction tests in follow-up
  4. 📋 Track the deferred v3.5 items in your backlog per the PR description

This PR successfully implements targeted directional rounding to prevent extraction loops while maintaining minimal scope and risk. The implementation is mathematically sound and follows established Aave patterns.

@claude
Copy link
Contributor

claude bot commented Mar 6, 2026

Claude finished @Git-on-my-level's task —— View job


Code Review Analysis

I've completed a comprehensive review of this dLEND directional rounding fix PR. Here's my analysis:

Todo List:

  • Read repository CLAUDE.md for setup and guidelines
  • Review WadRayMath.sol directional rounding implementation
  • Analyze tokenization changes in AToken.sol and VariableDebtToken.sol
  • Examine ScaledBalanceTokenBase.sol modifications
  • Review SupplyLogic.sol withdrawal change
  • Evaluate test coverage in DirectionalRounding.test.ts
  • Assess security implications of rounding changes
  • Check for potential performance impacts
  • Provide comprehensive code review feedback

Overall Assessment: ✅ LGTM with Minor Suggestions

This is a well-scoped, security-focused fix that implements minimal directional rounding changes to prevent supply-withdraw and borrow-repay extraction loops. The implementation follows Aave v3.5 patterns with appropriate conservatism.

Code Quality & Best Practices: ⭐⭐⭐⭐⭐

Strengths:

  • Excellent scope discipline: Only touches the core tokenization path, avoiding risky broader changes
  • Consistent directional bias: aToken operations favor protocol, debt operations favor protocol safety
  • Clean abstractions: WadRayMath.Rounding enum provides clear intent
  • Proper assembly optimization: Maintains gas efficiency while adding directional logic
  • Conservative approach: Minimal changes vs full v3.5 port reduces risk

Minor suggestions:

  • Consider adding inline comments explaining the directional bias rationale (e.g., "Floor mint favors protocol")

Security Analysis: 🔒 Strong

✅ Prevents extraction loops:

  • rayMulFloor/rayDivFloor in aToken mint/balanceOf prevents over-crediting users
  • rayMulCeil/rayDivCeil in variable debt prevents under-debiting protocol
  • Floor withdrawal balance calculation in SupplyLogic.sol:line 298 prevents over-withdrawal

✅ Directional consistency:

  • AToken: Floor mint ➜ Ceil burn (protocol-favorable)
  • Variable debt: Ceil mint ➜ Floor burn (protocol-safe)
  • Transfer: Ceil scaled amount calculation is protocol-conservative

✅ No storage layout changes: Upgrade-safe implementation

⚠️ Residual considerations:

  • Other rounding inconsistencies remain (as acknowledged in PR description)
  • This doesn't address liquidation/treasury/flashloan rounding mentioned in the deferred items

Performance Analysis: ⚡ Minimal Impact

✅ Gas efficiency maintained:

  • Assembly optimizations preserved in WadRayMath.sol
  • Additional conditional overhead is minimal (single enum comparison)
  • No new external calls or storage operations

✅ Computational complexity unchanged:

  • Same mathematical operations, just with directional control
  • rayMulFloor/rayMulCeil variants use efficient assembly

Test Coverage: 🧪 Adequate for Scope

✅ Good edge case coverage:

  • Live dUSD indices (realistic scenarios)
  • Upstream-style exact edge cases at 2*RAY + 1
  • Both aToken and variable debt scenarios

✅ Comprehensive test scenarios:

  • DirectionalRounding.test.ts covers all four main rounding semantics
  • Harness contracts enable direct testing of internal methods

Suggestion for future:

  • Integration tests with actual supply/withdraw/borrow/repay loops would strengthen confidence
  • Fuzzing tests around index boundaries could catch edge cases

Potential Issues: ⚠️ Minor

  1. No validation of rounding parameter in _mintScaled/_burnScaled - While the enum constrains values, explicit validation could improve robustness

  2. Transfer function directional choice (rayDivCeil at ScaledBalanceTokenBase.sol:164) could be documented - the choice appears correct but rationale unclear

  3. Testing harness exposure - RoundingHarnesses.sol exposes internal methods; ensure this stays in test scope only

Code Specific Observations:

WadRayMath.sol (/contracts/lending/core/protocol/libraries/math/WadRayMath.sol):

  • Lines 97-102, 143-148: Clean enum-based routing to directional variants
  • Lines 104-123: Efficient floor/ceil implementations with proper overflow checks
  • Line 121: iszero(iszero(mod(product, RAY))) is a clever way to add 1 if remainder exists

ScaledBalanceTokenBase.sol (/contracts/lending/core/protocol/tokenization/base/ScaledBalanceTokenBase.sol):

  • Lines 87, 121: Proper parameterized rounding in mint/burn
  • Line 125: reverseRounding() usage is mathematically sound for balance calculations

AToken.sol (/contracts/lending/core/protocol/tokenization/AToken.sol):

  • Lines 106, 116, 127: Consistent Floor/Ceil pattern for mint/burn/treasury
  • Lines 139, 150: Floor semantics in balanceOf/totalSupply prevent over-reporting

VariableDebtToken.sol (/contracts/lending/core/protocol/tokenization/VariableDebtToken.sol):

  • Lines 100, 113, 118, 124: Proper ceil operations ensuring protocol never under-reports debt

Recommendations:

  1. ✅ Approve and merge - This addresses the stated security concern effectively
  2. 📝 Document the directional choices in comments for future maintainers
  3. 🧪 Consider adding integration-level loop extraction tests in follow-up
  4. 📋 Track the deferred v3.5 items in your backlog per the PR description

This PR successfully implements targeted directional rounding to prevent extraction loops while maintaining minimal scope and risk. The implementation is mathematically sound and follows established Aave patterns.

@claude
Copy link
Contributor

claude bot commented Mar 6, 2026

Claude finished @Git-on-my-level's task —— View job


Code Review Analysis

I've completed a comprehensive review of this dLEND directional rounding fix PR. Here's my analysis:

Todo List:

  • Read repository CLAUDE.md for setup and guidelines
  • Review WadRayMath.sol directional rounding implementation
  • Analyze tokenization changes in AToken.sol and VariableDebtToken.sol
  • Examine ScaledBalanceTokenBase.sol modifications
  • Review SupplyLogic.sol withdrawal change
  • Evaluate test coverage in DirectionalRounding.test.ts
  • Assess security implications of rounding changes
  • Check for potential performance impacts
  • Provide comprehensive code review feedback

Overall Assessment: ✅ LGTM with Minor Suggestions

This is a well-scoped, security-focused fix that implements minimal directional rounding changes to prevent supply-withdraw and borrow-repay extraction loops. The implementation follows Aave v3.5 patterns with appropriate conservatism.

Code Quality & Best Practices: ⭐⭐⭐⭐⭐

Strengths:

  • Excellent scope discipline: Only touches the core tokenization path, avoiding risky broader changes
  • Consistent directional bias: aToken operations favor protocol, debt operations favor protocol safety
  • Clean abstractions: WadRayMath.Rounding enum provides clear intent
  • Proper assembly optimization: Maintains gas efficiency while adding directional logic
  • Conservative approach: Minimal changes vs full v3.5 port reduces risk

Minor suggestions:

  • Consider adding inline comments explaining the directional bias rationale (e.g., "Floor mint favors protocol")

Security Analysis: 🔒 Strong

✅ Prevents extraction loops:

  • rayMulFloor/rayDivFloor in aToken mint/balanceOf prevents over-crediting users
  • rayMulCeil/rayDivCeil in variable debt prevents under-debiting protocol
  • Floor withdrawal balance calculation in SupplyLogic.sol:line 298 prevents over-withdrawal

✅ Directional consistency:

  • AToken: Floor mint ➜ Ceil burn (protocol-favorable)
  • Variable debt: Ceil mint ➜ Floor burn (protocol-safe)
  • Transfer: Ceil scaled amount calculation is protocol-conservative

✅ No storage layout changes: Upgrade-safe implementation

⚠️ Residual considerations:

  • Other rounding inconsistencies remain (as acknowledged in PR description)
  • This doesn't address liquidation/treasury/flashloan rounding mentioned in the deferred items

Performance Analysis: ⚡ Minimal Impact

✅ Gas efficiency maintained:

  • Assembly optimizations preserved in WadRayMath.sol
  • Additional conditional overhead is minimal (single enum comparison)
  • No new external calls or storage operations

✅ Computational complexity unchanged:

  • Same mathematical operations, just with directional control
  • rayMulFloor/rayMulCeil variants use efficient assembly

Test Coverage: 🧪 Adequate for Scope

✅ Good edge case coverage:

  • Live dUSD indices (realistic scenarios)
  • Upstream-style exact edge cases at 2*RAY + 1
  • Both aToken and variable debt scenarios

✅ Comprehensive test scenarios:

  • DirectionalRounding.test.ts covers all four main rounding semantics
  • Harness contracts enable direct testing of internal methods

Suggestion for future:

  • Integration tests with actual supply/withdraw/borrow/repay loops would strengthen confidence
  • Fuzzing tests around index boundaries could catch edge cases

Potential Issues: ⚠️ Minor

  1. No validation of rounding parameter in _mintScaled/_burnScaled - While the enum constrains values, explicit validation could improve robustness

  2. Transfer function directional choice (rayDivCeil at ScaledBalanceTokenBase.sol:164) could be documented - the choice appears correct but rationale unclear

  3. Testing harness exposure - RoundingHarnesses.sol exposes internal methods; ensure this stays in test scope only

Code Specific Observations:

WadRayMath.sol (/contracts/lending/core/protocol/libraries/math/WadRayMath.sol):

  • Lines 97-102, 143-148: Clean enum-based routing to directional variants
  • Lines 104-123: Efficient floor/ceil implementations with proper overflow checks
  • Line 121: iszero(iszero(mod(product, RAY))) is a clever way to add 1 if remainder exists

ScaledBalanceTokenBase.sol (/contracts/lending/core/protocol/tokenization/base/ScaledBalanceTokenBase.sol):

  • Lines 87, 121: Proper parameterized rounding in mint/burn
  • Line 125: reverseRounding() usage is mathematically sound for balance calculations

AToken.sol (/contracts/lending/core/protocol/tokenization/AToken.sol):

  • Lines 106, 116, 127: Consistent Floor/Ceil pattern for mint/burn/treasury
  • Lines 139, 150: Floor semantics in balanceOf/totalSupply prevent over-reporting

VariableDebtToken.sol (/contracts/lending/core/protocol/tokenization/VariableDebtToken.sol):

  • Lines 100, 113, 118, 124: Proper ceil operations ensuring protocol never under-reports debt

Recommendations:

  1. ✅ Approve and merge - This addresses the stated security concern effectively
  2. 📝 Document the directional choices in comments for future maintainers
  3. 🧪 Consider adding integration-level loop extraction tests in follow-up
  4. 📋 Track the deferred v3.5 items in your backlog per the PR description

This PR successfully implements targeted directional rounding to prevent extraction loops while maintaining minimal scope and risk. The implementation is mathematically sound and follows established Aave patterns.

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