-
Notifications
You must be signed in to change notification settings - Fork 202
[VPD-1430, 1431, 1432] feat(bstock): atomic backstop liquidator + off-chain scripts #683
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
84 commits
Select commit
Hold shift + click to select a range
62c90b2
feat(bstock): add atomic backstop liquidator
Debugger022 fc0cbbd
feat(bstock): add offchain liquidation scripts and driver test
Debugger022 46d9558
feat(bstock): add Safe fallback liquidation batch generator
Debugger022 6846758
refactor(bstock): drop shortfall pre-check, rename validation helper
Debugger022 a1ffe53
refactor(bstock): always route liquidation through the gate
Debugger022 7df4df2
refactor(bstock): drop redundant flash guard, harden sweep
Debugger022 8db3946
refactor(bstock): rename usdt* vars to debt* for clarity
Debugger022 7d9d1e0
fix(bstock): deduct Venus Liquidator cut in seize precompute
Debugger022 81fa8df
fix(bstock): route safe-fallback batch through the Liquidator gate
Debugger022 14729b7
docs(bstock): generalize debt-asset wording, drop stale comments
Debugger022 08eff13
fix(bstock): quote the debt asset, assert it matches Native output
Debugger022 d17b5ba
refactor(bstock): resolve bStock token from orderbook, drop hardcoded…
Debugger022 896dde9
refactor(bstock): rename native-quote smoke test to native-smoke
Debugger022 1ae2c47
feat(bstock): support non-USDT debt via two-hop swap
Debugger022 17717bc
feat(bstock): index debt market in Liquidated event
Debugger022 c9afc42
feat(bstock): reject zero minOut in liquidator
Debugger022 087ab6c
refactor(bstock): clarify treasury-cut var and hop-2 amountIn constraint
Debugger022 2968bf3
feat(bstock): add per-call swap deadline
Debugger022 cb3ee37
fix(bstock): reset liquidation-gate approval to zero
Debugger022 37bbaea
docs(bstock): clarify inventory floor and native-debt limits
Debugger022 d843b27
feat(bstock): support native BNB (vBNB) debt
Debugger022 b7df959
docs(bstock): add operator runbook for liquidation scripts
Debugger022 6319593
test(bstock): add fork helper to list a real bStock collateral market
Debugger022 0a3f355
test(bstock): harden liquidator suite with reentrancy, deadline, and …
Debugger022 a8c58d0
test(bstock): richer fork sweep — market names, decoded skips, cash-s…
Debugger022 1784444
chore: fix lint
Debugger022 9f452db
test(bstock): render dynamic sweep results as an aligned table
Debugger022 159c85e
test(bstock): restore chain snapshot after suite to prevent signer st…
Debugger022 327a362
chore: consolidate router validation into a single function
Debugger022 08f8c32
docs: clarify comments regarding native BNB debt handling in atomicLi…
Debugger022 28ba594
fix(bstock):: enforce Venus Liquidator gate checks in atomicLiquidate…
Debugger022 3cef17c
feat(bstock): add SEIZE_BUFFER parameter to atomicLiquidate for impro…
Debugger022 812c600
feat(bstock): support native BNB debt in safe fallback batch
Debugger022 43409ff
chore(bstock): deploy BStockLiquidator to bscmainnet
Debugger022 2812b9d
feat: updating deployment files
Debugger022 2115a9b
test(bstock): run fork suite against deployed bscmainnet BStockLiquid…
Debugger022 0f94350
feat(bstock): support a separate router spender for split-settlement …
Debugger022 f5e3d09
feat(bstock): add Liquid Mesh as a hop-1 liquidation source
Debugger022 03bd5da
fix: [L02]
Debugger022 ce0b179
fix: [L03]
Debugger022 355b16b
fix: [L04]
Debugger022 a2d2043
fix: [L05]
Debugger022 4d176db
fix: [L06]
Debugger022 4617af5
fix: [I01]
Debugger022 d57fc0b
fix(bstock): harden setRouterSpender against misconfiguration
Debugger022 e53cd8a
fix(bstock): reconcile indicative LM quotes against firm quotes after…
Debugger022 9b9c7a5
fix(bstock): enforce a minimum TTL on built Liquid Mesh orders
Debugger022 5c9cab2
refactor(bstock): type LM API responses and validate the signing seed
Debugger022 18fce77
docs(bstock): document hop-1 reconcile and setRouterSpender ordering
Debugger022 510c9e8
docs(bstock): add script decision flowchart to runbook
Debugger022 15ac30d
docs(bstock): fix runbook env table and swap mermaid for SVG
Debugger022 aba7007
docs(bstock): clarify renounce and swap-underflow invariants
Debugger022 b36c17e
fix(bstock): consistent LM slippage bps and tolerant SOURCE parsing
Debugger022 ae6b50f
fix(bstock): time out hung hop-1 source API calls
Debugger022 d8d0e99
fix(bstock): bubble up router revert reason in _swap
Debugger022 2a26a80
Merge branch 'feat/VPD-1598' into feat/VPD-1589
Debugger022 929ec41
fix(bstock): restore router spender lookup in _swap
Debugger022 591f6c7
fix(bstock): size the hop-2 leg off the LM floor, not the quote
Debugger022 6a21bca
feat(bstock): support VAI debt in the backstop liquidator
Debugger022 90fed52
fix(bstock): stop safe-fallback misreading a VAI debt as native BNB
Debugger022 3ab7e4f
feat(bstock): build the VAI hop-2 PSM calldata in the script
Debugger022 1baf78f
test(bstock): fork-test the VAI PSM hop against the real PegStability…
Debugger022 111af24
test(bstock): script-driven VAI liquidation fork scenario
Debugger022 4214098
fix(bstock): harden liquidation off-chain seize, minOut, and pre-flig…
Debugger022 6d5c7e9
docs(bstock): document env knobs and correct the runbook and sizing c…
Debugger022 801f180
docs(bstock): correct VAI incentive-divergence comments in liquidatio…
Debugger022 17bc7fd
test(bstock): fork-prove effective-incentive divergence for a non-cor…
Debugger022 0b4a754
docs(bstock): expand liquidation flowchart and correct Native/LM/PSM …
Debugger022 c18c571
docs(bstock): stop the atomic arrow overlapping the DRY_RUN=1 header …
Debugger022 316bbb4
fix(bstock): name the actual seize function in VAI error messages
Debugger022 b1815d0
feat(bstock): add lm-smoke probe, align smoke output, clarify naming …
Debugger022 c1925f0
Merge pull request #694 from VenusProtocol/feat/VPD-1589
Debugger022 1507c56
fix: [L07]
Debugger022 d7b3adb
test(bstock): fork-prove the full mode × hop-1 source × debt scenario…
fred-venus 2ca908e
fix(bstock): pin vBNB oracle under the native sentinel, not WBNB
Debugger022 9d94d4d
test(bstock): harden scenario matrix
fred-venus 8441a7c
test(bstock): remove standalone fork workflow
fred-venus 00ca710
Merge pull request #696 from VenusProtocol/feat/VPD-1598
Debugger022 2536b36
chore(bstock): redeploy BStockLiquidator to bscmainnet
Debugger022 4ba70aa
docs(audits): add HashDit BStockLiquidator audit report
Debugger022 831c8b2
Merge pull request #701 from VenusProtocol/test/bstock-scenario-matrix
fred-venus 351501b
Merge pull request #703 from VenusProtocol/feat/VPD-1598
fred-venus e75d2b7
Merge pull request #702 from VenusProtocol/feat/VPD-1636
fred-venus c688006
feat: updating deployment files
fred-venus File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| { | ||
| "extends": "./tsconfig.json", | ||
| "include": ["./typechain", "./deploy", "./tests", "./script", "./scenario", "saddle.config.js", "docgen-templates", "commitlint.config.js", "./hardhat.config.zksync.ts", "type-extensions.ts"] | ||
| "include": ["./typechain", "./deploy", "./tests", "./script", "./scripts", "./scenario", "saddle.config.js", "docgen-templates", "commitlint.config.js", "./hardhat.config.zksync.ts", "type-extensions.ts"] | ||
| } |
Binary file not shown.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| // SPDX-License-Identifier: BSD-3-Clause | ||
| pragma solidity 0.8.25; | ||
|
|
||
| import { IVBep20 } from "../InterfacesV8.sol"; | ||
|
|
||
| /// @title IBStockLiquidator | ||
| /// @author Venus | ||
| /// @notice External API, events, errors and parameter struct for {BStockLiquidator}. | ||
| /// @dev The flash-loan callback `executeOperation` is intentionally NOT part of this interface — it is | ||
| /// declared by {IFlashLoanReceiver} (owned by the Core flash-loan subsystem) and implemented directly | ||
| /// by {BStockLiquidator}, keeping this interface free of the concrete `VToken` dependency. | ||
| interface IBStockLiquidator { | ||
| /// @notice Parameters for a single liquidation. | ||
| /// @dev The swap can be one or two hops. When `router2 == address(0)` it is a single hop | ||
| /// (bStock -> debt) and `swapCalldata2` / `intermediateToken` are ignored — behavior is | ||
| /// identical to the single-hop version. When `router2` is set it is two hops | ||
| /// (bStock -> `intermediateToken` -> debt): hop 1 sells bStock via `router`, hop 2 converts | ||
| /// the intermediate to the debt asset via `router2`. `minOut` is always the FINAL debt-asset | ||
| /// floor across the whole chain. `deadline` is a unix-timestamp expiry: the call reverts once | ||
| /// `block.timestamp` passes it, so a stale tx cannot settle against an expired quote. | ||
| struct LiquidationParams { | ||
| address borrower; // account to liquidate | ||
| IVBep20 vDebt; // borrowed market to repay (e.g. vUSDT) | ||
| IVBep20 vBStock; // bStock collateral market to seize (e.g. vTSLAB) | ||
| uint256 repayAmount; // debt underlying to repay (its own decimals) | ||
| address router; // hop-1 RFQ router (Native firm-quote target, Liquid Mesh router, …) — must be allowlisted | ||
| bytes swapCalldata; // hop-1 calldata (off-chain-signed RFQ order): bStock -> intermediate (or -> debt if single-hop) | ||
| uint256 minOut; // minimum FINAL debt-asset amount the swap chain must yield, else revert | ||
| address router2; // hop-2 router (AMM/aggregator): intermediate -> debt; address(0) = single-hop | ||
| bytes swapCalldata2; // hop-2 calldata; the swap recipient inside it MUST be this contract | ||
| address intermediateToken; // token hop 1 outputs and hop 2 consumes (e.g. USDT); required when router2 set | ||
| uint256 deadline; // unix timestamp after which the call reverts; guards a stale tx sitting in the mempool | ||
| } | ||
|
|
||
| /// @notice Emitted when an operator is allowlisted or removed. | ||
| event OperatorSet(address indexed operator, bool allowed); | ||
|
|
||
| /// @notice Emitted when a swap router is allowlisted or removed. | ||
| event RouterSet(address indexed router, bool allowed); | ||
|
|
||
| /// @notice Emitted when a router's token-approval target (spender) is set or cleared. | ||
| event RouterSpenderSet(address indexed router, address indexed spender); | ||
|
|
||
| /// @notice Emitted on a successful liquidation. | ||
| /// @param borrower The liquidated account. | ||
| /// @param vBStock The seized bStock collateral market. | ||
| /// @param vDebt The repaid debt market. | ||
| /// @param repayAmount Debt underlying repaid. | ||
| /// @param seizedBStock Raw bStock redeemed and sold. | ||
| /// @param debtOut Debt-asset proceeds of the swap. | ||
| /// @param flash True if funded by a flash loan, false if from inventory. | ||
| event Liquidated( | ||
| address indexed borrower, | ||
| address indexed vBStock, | ||
|
fred-venus marked this conversation as resolved.
|
||
| address indexed vDebt, | ||
| uint256 repayAmount, | ||
| uint256 seizedBStock, | ||
| uint256 debtOut, | ||
| bool flash | ||
| ); | ||
|
|
||
| /// @notice Emitted when the owner withdraws a token. | ||
| event Swept(address indexed token, address indexed to, uint256 amount); | ||
|
|
||
| /// @notice Emitted when the owner withdraws stuck native BNB. | ||
| event SweptNative(address indexed to, uint256 amount); | ||
|
|
||
| /// @notice Emitted when a swap hop pulls less than the amount approved to the router, leaving a | ||
| /// residual of the input token in the contract (e.g. a partially-filled RFQ quote). The | ||
| /// residual is recoverable via `sweep`. | ||
| /// @param token The input token left over (bStock on hop 1, the intermediate on hop 2). | ||
| /// @param amount The residual amount not consumed by the swap. | ||
| event PartialSwapLeftover(address indexed token, uint256 amount); | ||
|
|
||
| /// @notice Thrown when the caller is neither the owner nor an allowlisted operator. | ||
| error NotOperator(); | ||
|
|
||
| /// @notice Thrown when the supplied swap router is not allowlisted. | ||
| error RouterNotAllowed(address router); | ||
|
|
||
| /// @notice Thrown when a router spender being set is not a deployed contract. The spender receives | ||
| /// a live token approval during the swap, so an EOA spender is always a misconfiguration. | ||
| error SpenderNotContract(address spender); | ||
|
|
||
| /// @notice Thrown when `vBStock.redeem` returns a non-zero error code. | ||
| error RedeemFailed(uint256 errCode); | ||
|
|
||
| /// @notice Thrown when the low-level call to the router reverts. | ||
| error SwapFailed(); | ||
|
|
||
| /// @notice Thrown when swap proceeds are below `minOut`. | ||
| error InsufficientOut(uint256 got, uint256 minOut); | ||
|
|
||
| /// @notice Thrown when `minOut` is zero: a liquidation must set a non-zero debt-asset floor, | ||
| /// else it would silently accept any proceeds (including zero). | ||
| error ZeroMinOut(); | ||
|
|
||
| /// @notice Thrown when a two-hop `intermediateToken` is zero, or equals the debt or bStock token. | ||
| error InvalidIntermediate(); | ||
|
|
||
| /// @notice Thrown when `executeOperation` is called by something other than the Comptroller. | ||
| error OnlyComptroller(); | ||
|
|
||
| /// @notice Thrown when the flash-loan initiator is not this contract. | ||
| error BadInitiator(address initiator); | ||
|
|
||
| /// @notice Thrown when the flashed asset does not match `params.vDebt`. | ||
| error WrongFlashAsset(); | ||
|
|
||
| /// @notice Thrown when `flashLiquidate` is called with a VAI debt. VAI is minted/burned by the | ||
| /// VAIController and has no vToken market to flash from — use `liquidate` (INVENTORY mode) | ||
| /// with pre-funded VAI instead. | ||
| error FlashNotSupportedForVai(); | ||
|
|
||
| /// @notice Thrown when the call is submitted after `params.deadline`. | ||
| error DeadlineExpired(uint256 deadline, uint256 nowTs); | ||
|
|
||
| /// @notice Thrown when a native BNB transfer (the `sweepNative` payout) fails. | ||
| error NativeTransferFailed(); | ||
|
|
||
| /// @notice Allow or disallow an address to trigger liquidations. | ||
| /// @param operator Address to allowlist or remove. | ||
| /// @param allowed True to allow, false to remove. | ||
| function setOperator(address operator, bool allowed) external; | ||
|
|
||
| /// @notice Allow or disallow a router as the swap target (e.g. the Native router). | ||
| /// @dev Removing a router also clears its `routerSpender` entry (emitting {RouterSpenderSet} with | ||
| /// `address(0)`), so a stale spender cannot silently reactivate on a later re-allowlist. | ||
| /// @param router Address to allowlist or remove. | ||
| /// @param allowed True to allow, false to remove. | ||
| function setRouter(address router, bool allowed) external; | ||
|
|
||
| /// @notice Set the token-approval target (spender) for a router whose settlement contract that pulls | ||
| /// the input token differs from the call target (e.g. Liquid Mesh). When unset, the approval | ||
| /// defaults to the router itself (Native behaviour). Setting `spender = address(0)` clears it. | ||
| /// @dev Reverts with {RouterNotAllowed} unless `router` is currently allowlisted, and with | ||
| /// {SpenderNotContract} when a non-zero `spender` has no code. The spender is an approval | ||
| /// target only — it is never called; the low-level call always targets the allowlisted router. | ||
| /// @param router The allowlisted swap target (call target). | ||
| /// @param spender The contract that pulls the input token via `transferFrom` during settlement. | ||
| function setRouterSpender(address router, address spender) external; | ||
|
|
||
| /// @notice Withdraw any token (profit, leftover inventory, stuck dust) to `to`. | ||
| /// @param token Token to withdraw. | ||
| /// @param to Recipient. | ||
| /// @param amount Amount to withdraw. | ||
| function sweep(address token, address to, uint256 amount) external; | ||
|
|
||
| /// @notice Withdraw stuck native BNB (a stray transfer, or a gate refund) to `to`. | ||
| /// @param to Recipient. | ||
| /// @param amount Amount of native BNB to withdraw. | ||
| function sweepNative(address to, uint256 amount) external; | ||
|
|
||
| /// @notice Liquidate using the contract's own debt-asset inventory. | ||
| /// @dev The contract must already hold >= `repayAmount` of `vDebt.underlying()`. | ||
| /// Profit (proceeds - repay) stays in the contract; withdraw it with `sweep`. | ||
| /// @param params Liquidation parameters (borrower, markets, repay, hop-1 router + calldata, final | ||
| /// minOut, `deadline`, and the optional hop-2 router/calldata/intermediate for non-USDT debt). | ||
| /// @return debtOut Debt-asset proceeds realized by the swap chain. | ||
| function liquidate(LiquidationParams calldata params) external returns (uint256 debtOut); | ||
|
|
||
| /// @notice Liquidate by flash-borrowing the repay amount from Venus, repaid (+ premium) in the same tx. | ||
| /// @dev Requires this contract to be `authorizedFlashLoan` in the Comptroller and `vDebt` flash-enabled. | ||
| /// Profit (proceeds - repay - premium) stays in the contract; withdraw it with `sweep`. | ||
| /// @param params Liquidation parameters (borrower, markets, repay, hop-1 router + calldata, final | ||
| /// minOut, `deadline`, and the optional hop-2 router/calldata/intermediate for non-USDT debt). | ||
| function flashLiquidate(LiquidationParams calldata params) external; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.