feat(market-factory): support bStock markets and wire the liquidation suite - #231
Open
razww wants to merge 1 commit into
Open
feat(market-factory): support bStock markets and wire the liquidation suite#231razww wants to merge 1 commit into
razww wants to merge 1 commit into
Conversation
… suite Add a stockCollateral flag to createMarket / batchCreateMarkets that registers the collateral in StockOracleSwitch via setStock. The factory never touches the switch's global market-hours flag, so a new bStock is registered but stays gated by ops. An already-registered stock is skipped, since setStock reverts on a no-op and creating a market must not reopen a deliberately closed stock. Whitelist market tokens uniformly across all three liquidation contracts (Liquidator, BrokerLiquidator, LiquidationVault) for common, fixed-term and smart-collateral markets, and register smart providers on BrokerLiquidator too. A smart-collateral LP is the one exception: it is excluded from the vault whitelist and reflow-blacklisted on both liquidators instead, because the vault cannot sell it. This matches the live BSC posture, which was previously only half-reproduced by the factory. liquidationVault and stockOracleSwitch are storage variables with admin setters, following the rateCalculator / brokerLiquidator pattern, so the constructor immutables and the existing deploy scripts are unchanged and ETH can leave both unset. Deploying this requires granting MarketFactory the MANAGER role on LiquidationVault and StockOracleSwitch, then calling the two setters. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pull Request ReviewThis Solidity PR extends the upgradeable MarketFactory to register tokenized-stock collateral with StockOracleSwitch and adds admin-configurable StockOracleSwitch and LiquidationVault integrations. It also centralizes token and smart-provider configuration across Liquidator, BrokerLiquidator, and LiquidationVault, updates relevant interfaces, and adds tests for stock registration, uniform whitelisting, LP exclusions, idempotency, and setter access control. Sensitive ContentNo sensitive content detected. Security IssuesNo serious security issues detected. Generated by Hashdit Bot. This tool can absolutely NOT replace manual audits. |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Two additions to
MarketFactory, plus a consistency fix the second one surfaced.1. bStock market support. New
stockCollateralflag oncreateMarket/stockCollateralsarray onbatchCreateMarkets. When set, the factory registers the collateral inStockOracleSwitchviasetStock, so a tokenized-stock market is gated by market hours from the moment it exists rather than depending on a follow-up ops step.The factory deliberately does not touch
globalEnabled— the daily market-hours switch stays MANAGER-owned. An already-registered stock is skipped, becausesetStockrevertsAlreadySeton a no-op and creating a second market on the same collateral must not reopen a stock ops deliberately closed.2. LiquidationVault token whitelist, wired everywhere the
Liquidatorwhitelist was already set.3. Uniform whitelisting across all three liquidation contracts. Auditing (2) showed the factory only ever configured a subset per path. Now collapsed into one
_whitelistToken(token, includeVault)helper applied to every path:One deliberate exception, carried by the
includeVaultflag: a smart-collateral LP is never vault-whitelisted. The vault cannot sell it, so it is reflow-blacklisted on both liquidators instead; whitelisting it would also have opened the BOTcollect*path for it. MANAGER rescue viacollectERC20still works, since that bypassestokenWhitelist.Why this shape
liquidationVaultandstockOracleSwitchare storage variables with admin setters, following the existingrateCalculator/brokerLiquidatorpattern rather than new constructor args. The constructor immutables are unchanged, sodeploy_marketFactory_impl.solworks as-is and ETH can leave both unset (vault whitelisting silently skips; the stock flag reverts loudly).Verified against live BSC state
The chosen posture is not invented — it is what ops already maintains by hand, which the factory previously only half-reproduced:
StableSwapLPCollateraltokens: reflow-blacklisted on both liquidators, vault-whitelisted on none.BNB_ADDRESSwhitelisted on all three, and the slisBNB/BNB provider'stoken(1)isBNB_ADDRESS— so native legs need no special case; the generic leg path coverscollectETH/sellBNB.vault.liquidators: Liquidator ✅, BrokerLiquidator ✅, PublicLiquidator ❌ — correct, PublicLiquidator has nofundSourceand never reflows.Out of scope (flagged, not changed)
publicLiquidator.setMarketWhitelistis still never called by the factory. It isonlyRole(BOT)and the factory does not hold BOT on PublicLiquidator on mainnet. Enabling public liquidation is also a per-market policy call, not something to imply fromliquidatorMarketWhitelist— wiring it needs a role grant plus a new flag.pairWhiteliston all four contracts: DEX pools/routers are not derivable fromMarketParams.Deployment prerequisites
MarketFactory already holds
MANAGERon Liquidator and BrokerLiquidator, so the new calls work. Still required before the upgraded factory can create anything:MANAGERto MarketFactory on LiquidationVault (0xEe3aa1AF4Ee231f2e1277A48fc4A2f29A3D7C028) and StockOracleSwitch (0xb4678C3E8B49d2b95Da48458f98805da193A8498) — both currentlyfalseon BSC.setLiquidationVault/setStockOracleSwitch.Note
switch.globalEnabledis currentlytrueon BSC, so a newly registered bStock goes live immediately rather than waiting for a market-hours open.createMarketandbatchCreateMarketseach take one additional argument. Any off-chain caller or script must be updated.Test
forge test --mc MarketFactoryTest— 12 passed, including 5 new tests:testCreateStockMarket— registers + enables the stock, leavesglobalEnabledalone, stock only tradable after MANAGER opens the markettestCreateStockMarketAlreadyRegistered— idempotent, and does not reopen a closed stocktestCreateStockMarketRevertsWhenSwitchNotSettestCreateMarketWhitelistsLiquidationVaultTokens/testCreateMarketVaultWhitelistIdempotent/testCreateMarketSkipsVaultWhenUnsettestSettersOnlyAdmintestCreateSmartProviderMarketnow asserts the full LP posture (not vault-whitelisted, reflow-blacklisted on both liquidators, provider registered on all three, legs whitelisted everywhere).Full non-fork suite: 966 passed, 0 failed.
forge buildandnpm run checkclean.🤖 Generated with Claude Code