[VPD-1598] Hashdit Audit Mitigations for BstockLiquidator#696
[VPD-1598] Hashdit Audit Mitigations for BstockLiquidator#696Debugger022 wants to merge 8 commits into
Conversation
There was a problem hiding this comment.
Claude Code Review
Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.
Tip: disable this comment in your organization's Code Review settings.
There was a problem hiding this comment.
Pull request overview
This PR implements the HashDit audit mitigations for BStockLiquidator, spanning on-chain hardening (swap accounting + ownership footgun prevention), off-chain liquidation tooling correctness (borrower-aware seize estimation + quote freshness checks), and corresponding tests/mocks to validate the new behaviors.
Changes:
- Adds
PartialSwapLeftoverobservability for partial-fill swap hops and updates swap accounting to measure actual input consumption. - Disables
renounceOwnership()to prevent bricking owner-only recovery/admin controls; addsnonReentranttosweepNativefor defense-in-depth consistency. - Updates scripts and fork helpers to use the borrower-aware 4-arg
liquidateCalculateSeizeTokensoverload and adds a pre-submit Native-quote TTL margin check (with tests).
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/hardhat/Fork/helpers/bstock.ts | Fork helper updated to use borrower-aware 4-arg seize calculation and thread borrower through two-hop builder. |
| tests/hardhat/Fork/BStockLiquidatorFork.ts | Updates fork test call sites to pass borrower into the two-hop helper. |
| tests/hardhat/BStockLiquidator.ts | Adds unit tests for partial-fill leftover event + sweep recovery and renounceOwnership no-op semantics. |
| tests/hardhat/BStockAtomicLiquidate.ts | Adds tests for SETTLE_TTL_MARGIN validation and TTL-below-margin abort behavior. |
| scripts/bstock/safe-fallback.ts | Switches to 4-arg seize overload and adds seizeTokens > 0 sanity guard. |
| scripts/bstock/atomic-liquidate.ts | Switches to 4-arg seize overload, adds seizeTokens > 0 guard, and re-checks quote TTL against SETTLE_TTL_MARGIN immediately before submit. |
| deploy/019-deploy-bstock-liquidator.ts | Documents governance-gated flash-loan whitelist step required for FLASH mode. |
| contracts/test/BStockLiquidationMocks.sol | Extends MockComptrollerLite with the 4-arg liquidateCalculateSeizeTokens overload. |
| contracts/BStock/IBStockLiquidator.sol | Introduces PartialSwapLeftover event to surface unconsumed input residuals. |
| contracts/BStock/BStockLiquidator.sol | Implements leftover emission + swap accounting, adds nonReentrant to sweepNative, and disables renounceOwnership. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Surface the swap router's own revert reason instead of an opaque SwapFailed(), so a failed hop reports the actual cause (e.g. insufficient allowance). SwapFailed() is kept only as the empty-returndata fallback.
Summary
BStockLiquidator: five Low findings (L02–L06) and one Informational (I01) are fixed; the Medium (M01) and one Low (L01) are acknowledged as latent/out-of-threat-model.Changes
Contract (
contracts/BStock/)_swapnow measures the input actually consumed (balBefore - balAfter) and emitsPartialSwapLeftoverwhen a router fills less than approved (e.g. a partial RFQ fill), leaving the residual observable and sweepable; overstated NatSpec corrected.renounceOwnership()overridden to a no-op, so an accidental call cannot zero the owner and brick this fund-custody contract.sweepNativegivennonReentrantfor consistency with the liquidation entrypoints (defense-in-depth).Off-chain scripts (
scripts/bstock/)atomic-liquidate.tsandsafe-fallback.tsswitched to the borrower-aware 4-argliquidateCalculateSeizeTokensoverload (matchesvToken.liquidateBorrowFresh); addedseizeTokens > 0sanity guards.setWhiteListFlashLoanAccountstep required before FLASH mode.atomic-liquidate.tsre-verifies the Native quote's remaining TTL immediately before submission, aborting below a configurableSETTLE_TTL_MARGIN(default 10s).Tests & mocks
MockComptrollerLitegained the 4-arg overload.renounceOwnershipno-op (L03), TTL-below-margin abort + invalid-margin rejection (L06).Test plan
npx hardhat compile— clean.npx hardhat test tests/hardhat/BStockLiquidator.ts tests/hardhat/BStockAtomicLiquidate.ts tests/hardhat/BStockSafeFallback.ts— 64 passing.tests/hardhat/Fork/BStockLiquidatorFork.ts) requires a BSC archive RPC.Audit disposition
forceVAILiquidateisfalseon mainnet, gate condition currently unreachable; governance-gated with an off-chain workaround