Skip to content

EBrake

EBrake (Emergency Brake) is a Venus periphery contract that acts as an emergency action router for the protocol. It exposes a curated set of Comptroller emergency functions, and from v1.3.0 three Liquidity Hub pause forwarders, behind Access Control Manager (ACM) permissions, allowing the multisig, automated monitoring contracts, and trusted third-party services to rapidly tighten protocol parameters during an incident — without waiting for a governance VIP.

Version scope: This API reference follows venus-periphery v1.3.0. EBrake is deployed behind upgradeable proxies. Its effective behavior depends on the current implementation, immutable Comptroller/type pair, ACM grants, and the Comptroller version on each network; verify those values from the deployment registry and explorer before incident use.

During a security incident, every block of delay can increase potential losses. EBrake provides a fast path for selected protective actions without waiting for a governance proposal: pausing market actions, reducing collateral factors, lowering supply/borrow caps, and pausing a Liquidity Hub, one of its YieldGroups, or a resource. The contract restricts these mutators to tightening configured parameters, but a mistaken or compromised caller can still block user actions, reduce borrowing capacity, or prolong an incident. The contract does not guarantee that downstream economic loss is impossible.

Recovery from any EBrake action always goes through a governance VIP, which also calls the snapshot reset functions to prepare EBrake for future incidents.

EBrake is designed to be called from three types of principals:

CallerAccess MethodDescription
Venus MultisigDirect ACM whitelistFull access to all EBrake functions. Used during manual incident response.
On-chain monitorsDirect ACM whitelistContracts like DeviationSentinel that contain their own detection logic and call EBrake on trigger.
Third-party monitorsSafe Module on multisigExternal services (e.g. Hypernative) get a dedicated Safe Module that scopes which functions they can call.

This architecture keeps detection logic isolated from execution. EBrake only handles execution — it holds no detection logic of its own.

EBrake can only tighten restrictions, never loosen them. This means it intentionally cannot:

  • Unpause — recovery is always via governance VIP
  • Pause REPAY or SEIZE — users must always be able to repay to avoid liquidation, and liquidations must always work to prevent bad debt
  • Pause the protocol — setProtocolPaused blocks repay and liquidation, which violates the safety invariant
  • Lower liquidation threshold — this would instantly make healthy positions liquidatable
  • Increase caps — caps can only be decreased to reduce exposure
  • Enable forced liquidation — this would make any borrower liquidatable regardless of their collateral ratio
  • Target individual users — prevents griefing specific addresses
  • Change the oracle or liquidation incentive — would cause mass mispricing or alter liquidation economics for all users

Actions available to a compromised authorized caller include:

  • Pausing minting, borrowing, redeeming, or transfers, which can delay entry and exit operations
  • Zeroing supply/borrow caps, which blocks additional exposure and can affect later account actions
  • Decreasing collateral factor, which does not directly change liquidation eligibility while liquidation threshold is preserved, but can restrict later borrows or redemptions
  • Pausing flash loans, which can block integrations that depend on that facility
  • Pausing a whole Liquidity Hub (pauseHub), which blocks every lender deposit and withdrawal on that Hub until it is unpaused
  • Pausing one of a Hub’s YieldGroups or a single resource, which closes only that route: the Hub’s outer queues skip a paused YieldGroup and its inner queues skip a paused resource, so deposits and withdrawals continue through healthy sibling routes while they have the capacity and liquidity. A paused resource is still counted in the Hub’s NAV, and shares still trade against that NAV, which is why the NAV sentinel pauses the whole Hub rather than the resource

Recovery requires a governance VIP that restores the affected parameters and clears the corresponding snapshots. Operational and economic consequences depend on the affected markets and recovery time.

Whenever EBrake tightens a parameter for the first time, it snapshots the original value using a first-write-wins strategy. These snapshots are stored in marketStates and serve as a reference for governance to restore to when issuing a recovery VIP. After restoring values on-chain, governance calls the corresponding reset function (resetCFSnapshot, resetBorrowCapSnapshot, resetSupplyCapSnapshot) to clear the snapshot and prepare EBrake for future incidents.

EBrake supports two Comptroller families. The currently published registry lists deployments on only a subset of Venus networks, and behavior differs by the configured Comptroller:

FeatureBSC — Diamond Comptroller (IS_ISOLATED_POOL=false)Non-BSC — IL Comptroller (IS_ISOLATED_POOL=true)
decreaseCF(market, newCF)Iterates all pools (corePoolId to lastPoolId), silently skips pools already at or below newCFApplies to the single market; reverts if newCF > currentCF
decreaseCF(market, poolId, newCF)Supported — targets a single pool (core or e-mode)Reverts with NotSupportedOnIsolatedPool
pauseFlashLoan()Supported — flash loans only exist on DiamondNot ACM-granted
disablePoolBorrow(poolId, market)Supported — per-pool granular borrow disableNot ACM-granted
revokeFlashLoanAccess(account)Supported — removes account from flash loan whitelistNot ACM-granted
pauseHub, pauseHubYieldGroup, pauseHubResourceSupported, where the deployed implementation has themNot ACM-granted
E-mode pool supportYes — via poolId > 0No — no pool concept

All other functions (pauseActions, pauseSupply, pauseBorrow, pauseRedeem, pauseTransfer, setMarketBorrowCaps, setMarketSupplyCaps) are ABI-compatible across both comptroller types and work identically on all chains.

  • AccessControlledV8 — privileged state-changing functions are gated through the Venus Access Control Manager; initialization and public views are not ACM actions
VariableTypeDescription
COMPTROLLERICorePoolComptrollerThe Venus Comptroller this EBrake instance operates on. On BSC this is a Diamond proxy; on other chains it is an IL comptroller.
IS_ISOLATED_POOLboolSet at deployment. true for IL comptroller (isolated-pools); false for Diamond (BSC).
VariableTypeDescription
marketStatesmapping(address => MarketState)Pre-incident snapshots keyed by vToken market address, captured on the first tightening.
struct MarketState {
uint256 borrowCap;
uint256 supplyCap;
bool borrowCapSnapshotted;
bool supplyCapSnapshotted;
mapping(uint96 => uint256) poolCFs;
mapping(uint96 => uint256) poolLTs;
}

Holds the pre-incident state captured by EBrake before any tightening action. Nested mapping fields (poolCFs, poolLTs) must be read via getMarketCFSnapshot(). Cap fields are accessible via the auto-generated marketStates() getter.

FieldDescription
borrowCapBorrow cap value before EBrake decreased it.
supplyCapSupply cap value before EBrake decreased it.
borrowCapSnapshottedTrue if a borrow cap snapshot has been recorded.
supplyCapSnapshottedTrue if a supply cap snapshot has been recorded.
poolCFsMapping of poolId to the collateral factor before EBrake decreased it.
poolLTsMapping of poolId to the liquidation threshold at snapshot time.

Initializes the proxy with its Access Control Manager. The implementation constructor fixes COMPTROLLER and IS_ISOLATED_POOL and disables direct initialization of the implementation.

function initialize(address accessControlManager_) external initializer

This is a one-time proxy initialization function; it is not an ACM-gated incident action.


Pause multiple actions on multiple markets in a single call.

function pauseActions(address[] calldata markets, IComptroller.Action[] calldata actions) external
NameTypeDescription
marketsaddress[]The vToken market addresses to pause actions on.
actionsIComptroller.Action[]The actions to pause.

Calls setActionsPaused(markets, actions, true) on the comptroller for the provided markets and actions. Only MINT, REDEEM, BORROW, and TRANSFER are allowed. Passing REPAY, SEIZE, LIQUIDATE, ENTER_MARKET, or EXIT_MARKET reverts.

  • ACM permission required: pauseActions(address[],uint8[])
  • EmptyArray if markets or actions is empty
  • ForbiddenAction if any action is not one of the four permitted actions
  • ActionsPaused emitted on success

Pause supply (mint) on a single market. Blocks new deposits; existing suppliers can still redeem.

function pauseSupply(address market) external
NameTypeDescription
marketaddressThe vToken market address.
  • ACM permission required: pauseSupply(address)
  • ActionPaused emitted with action = MINT

Pause redeem on a single market. Blocks withdrawals. Use when draining must be stopped immediately.

function pauseRedeem(address market) external
NameTypeDescription
marketaddressThe vToken market address.
  • ACM permission required: pauseRedeem(address)
  • ActionPaused emitted with action = REDEEM

Pause borrowing on a single market. Blocks new borrows; existing borrowers can still repay.

function pauseBorrow(address market) external
NameTypeDescription
marketaddressThe vToken market address.
  • ACM permission required: pauseBorrow(address)
  • ActionPaused emitted with action = BORROW

Pause vToken transfers on a single market. Blocks vToken movement, preventing an attacker from moving stolen collateral.

function pauseTransfer(address market) external
NameTypeDescription
marketaddressThe vToken market address.
  • ACM permission required: pauseTransfer(address)
  • ActionPaused emitted with action = TRANSFER

Pause flash loans across the core pool.

function pauseFlashLoan() external

Calls setFlashLoanPaused(true) on the Diamond comptroller. Idempotent: silently returns without emitting an event when flash loans are already paused, so FlashLoanPaused is always a true state-change signal.

  • ACM permission required: pauseFlashLoan()
  • BSC (Diamond) only — not ACM-granted on IL chains
  • FlashLoanPaused emitted on state change (not emitted if already paused)

Disable borrowing for a market in a specific pool, leaving all other pools unaffected.

function disablePoolBorrow(uint96 poolId, address market) external
NameTypeDescription
poolIduint96The pool identifier (0 = core pool, >0 = e-mode pools).
marketaddressThe vToken market address.

Calls setIsBorrowAllowed(poolId, market, false) on the Diamond comptroller. The false argument is hardcoded — EBrake can only disable, never re-enable. This flag is independent of pauseBorrow(market), which flips the global _actionPaused[market][BORROW] flag across every pool. Both flags must allow borrowing for borrows to proceed in a given pool/market; recovery therefore requires governance to clear both if both were set.

  • ACM permission required: disablePoolBorrow(uint96,address)
  • BSC (Diamond) only — not ACM-granted on IL chains
  • PoolBorrowDisabled emitted on success

Remove a single account from the flash loan whitelist.

function revokeFlashLoanAccess(address account) external
NameTypeDescription
accountaddressThe account whose flash loan access is revoked.

Calls setWhiteListFlashLoanAccount(account, false) on the Diamond comptroller. The surgical alternative to pauseFlashLoan() — use when a single whitelisted integrator is compromised and a full flash loan pause would harm innocent users. The false is hardcoded; re-granting access requires governance.

  • ACM permission required: revokeFlashLoanAccess(address)
  • BSC (Diamond) only — not ACM-granted on IL chains
  • ZeroAddress if account is the zero address
  • FlashLoanAccessRevoked emitted on success

Pause an entire Liquidity Hub.

Not in the BNB Chain mainnet implementation yet. This function and the two below shipped in v1.3.0. The BNB Chain testnet implementation already has them. The live mainnet implementation 0x2D36677EcA318c9536011D53aa752F042dd01DE8 predates them and carries none of their selectors, so no Hub can be paused through EBrake until the proxy is upgraded.

function pauseHub(address hub) external
NameTypeDescription
hubaddressThe Hub to pause.

Calls pauseHub() on the Hub, which blocks deposits, withdrawals and reallocate across every Source it owns; emergencyReallocate and sweep still work. Idempotent: returns without emitting when hubPaused() is already true. Reverts ZeroAddress on a zero address.

  • ACM permission required: pauseHub(address)
  • EBrake must additionally hold the Hub’s own pauseHub() role, granted per Hub address
  • HubPaused emitted on state change (not emitted if already paused)

Pause one Source on the Hub that owns it, leaving the rest of the Hub running.

function pauseHubYieldGroup(address yieldGroup) external
NameTypeDescription
yieldGroupaddressThe Source to pause.

Reads the owning Hub from yieldGroup.hub(), so the caller does not pass it. Calls pauseYieldGroup(yieldGroup) on that Hub. Idempotent: returns without emitting when the Hub’s yieldGroupConfig(yieldGroup).paused is already true. Reverts ZeroAddress on a zero address.

  • ACM permission required: pauseHubYieldGroup(address)
  • EBrake must additionally hold the Hub’s own pauseYieldGroup(address) role
  • HubYieldGroupPaused emitted on state change (not emitted if already paused)

Pause one resource inside a Source, the narrowest of the three.

function pauseHubResource(address yieldGroup, address resource) external
NameTypeDescription
yieldGroupaddressThe Source holding the resource.
resourceaddressThe resource to pause.

Reads the resource’s paused flag from yieldGroup.resourceConfig(resource) and returns without emitting when it is already set. Otherwise calls pauseResource(resource) on the Source. Reverts ZeroAddress if either address is zero.

Note the Hub’s totalAssets() still counts a paused resource, so pausing a resource stops new flow through it without removing its value from the share price.

  • ACM permission required: pauseHubResource(address,address)
  • EBrake must additionally hold the Source’s own pauseResource(address) role
  • HubResourcePaused emitted on state change (not emitted if already paused)

Decrease collateral factor to newCF for a market across all relevant pools. Liquidation threshold is left unchanged.

function decreaseCF(address market, uint256 newCF) external
NameTypeDescription
marketaddressThe vToken market address whose CF should be decreased.
newCFuint256The new collateral factor value.
  • Diamond (BSC): Iterates all pools from corePoolId to lastPoolId. Applies newCF only to pools where currentCF > newCF; silently skips pools already at or below newCF and unlisted pools. Does not revert due to CF comparison — use the per-pool overload for strict enforcement on a specific pool.
  • IL (non-BSC): Applies to the single market entry. Reverts with CFExceedsCurrent if newCF > currentCF. No-ops (returns without event) if newCF == currentCF.

Decreasing CF blocks or limits new borrows against the asset. It does not make existing positions liquidatable — that would require lowering LT, which EBrake cannot do.

  • ACM permission required: decreaseCF(address,uint256)
  • MarketNotListed if the market is not listed in the core pool (Diamond) or the comptroller (IL)
  • CFExceedsCurrent if newCF > currentCF (IL only; Diamond silently skips)
  • SetCollateralFactorFailed if the comptroller returns a non-zero error code (Diamond only)
  • CollateralFactorDecreased emitted per pool where CF was actually changed

Decrease collateral factor to newCF for a market in a specific pool.

function decreaseCF(address market, uint96 poolId, uint256 newCF) external
NameTypeDescription
marketaddressThe vToken market address whose CF should be decreased.
poolIduint96The pool ID (0 for core pool, >0 for e-mode pools).
newCFuint256The new collateral factor value. Must be ≤ current CF in the pool.

Targets a single pool. No-ops (returns without event) if newCF == currentCF. Unlike the batch overload, this reverts with CFExceedsCurrent if newCF > currentCF, making it suitable for multisig use where strict enforcement per pool is required.

  • ACM permission required: decreaseCF(address,uint96,uint256)
  • BSC (Diamond) only — reverts with NotSupportedOnIsolatedPool on IL chains
  • NotSupportedOnIsolatedPool if called on an IL comptroller deployment
  • MarketNotListed if the market is not listed in the given pool
  • CFExceedsCurrent if newCF > currentCF
  • SetCollateralFactorFailed if the comptroller returns a non-zero error code
  • CollateralFactorDecreased emitted on success

Decrease borrow caps on one or more markets. Setting a cap to 0 blocks additional borrowing; it does not change debt already recorded, although the account remains subject to normal interest and liquidation rules.

function setMarketBorrowCaps(address[] calldata markets, uint256[] calldata newBorrowCaps) external
NameTypeDescription
marketsaddress[]The vToken market addresses to adjust borrow caps on.
newBorrowCapsuint256[]The new borrow cap values. Each must be ≤ current cap (equality is a no-op; greater reverts).

Iterates the markets array. Elements equal to the current cap are silently skipped (no snapshot pollution). Elements strictly lower than the current cap trigger a cap decrease and record a first-write-wins snapshot. Only calls the comptroller if at least one element actually decreased.

  • ACM permission required: setMarketBorrowCaps(address[],uint256[])
  • EmptyArray if markets is empty
  • ArrayLengthMismatch if markets and newBorrowCaps have different lengths
  • CapExceedsCurrent if any new cap is strictly greater than the current cap
  • BorrowCapsDecreased emitted when at least one cap was actually decreased

Decrease supply caps on one or more markets. Setting a cap to 0 blocks additional deposits; it does not change an existing supplied balance, although a separate redeem pause can still block withdrawals.

function setMarketSupplyCaps(address[] calldata markets, uint256[] calldata newSupplyCaps) external
NameTypeDescription
marketsaddress[]The vToken market addresses to adjust supply caps on.
newSupplyCapsuint256[]The new supply cap values. Each must be ≤ current cap (equality is a no-op; greater reverts).

Identical to setMarketBorrowCaps but operates on supply caps.

  • ACM permission required: setMarketSupplyCaps(address[],uint256[])
  • EmptyArray if markets is empty
  • ArrayLengthMismatch if markets and newSupplyCaps have different lengths
  • CapExceedsCurrent if any new cap is strictly greater than the current cap
  • SupplyCapsDecreased emitted when at least one cap was actually decreased

Reset the stored CF/LT snapshot for a market. Called by governance as part of a recovery VIP after restoring collateral factors.

function resetCFSnapshot(address market) external
NameTypeDescription
marketaddressThe vToken market address whose CF snapshot to clear.

Clears poolCFs and poolLTs for all relevant pools (all pools on Diamond; pool 0 on IL). Does not touch cap snapshots. After this call, the next decreaseCF call will capture a fresh pre-incident value.

  • ACM permission required: resetCFSnapshot(address)
  • CFSnapshotReset emitted on success

Reset the stored borrow cap snapshot for a market. Called by governance after restoring the borrow cap.

function resetBorrowCapSnapshot(address market) external
NameTypeDescription
marketaddressThe vToken market address whose borrow cap snapshot to clear.

Clears borrowCap and sets borrowCapSnapshotted = false. Does not touch supply cap or CF snapshots.

  • ACM permission required: resetBorrowCapSnapshot(address)
  • BorrowCapSnapshotReset emitted on success

Reset the stored supply cap snapshot for a market. Called by governance after restoring the supply cap.

function resetSupplyCapSnapshot(address market) external
NameTypeDescription
marketaddressThe vToken market address whose supply cap snapshot to clear.

Clears supplyCap and sets supplyCapSnapshotted = false. Does not touch borrow cap or CF snapshots.

  • ACM permission required: resetSupplyCapSnapshot(address)
  • SupplyCapSnapshotReset emitted on success

Read the stored collateral factor and liquidation threshold snapshot for a market in a specific pool.

function getMarketCFSnapshot(address market, uint96 poolId) external view returns (uint256 cf, uint256 lt)
NameTypeDescription
marketaddressThe vToken market address.
poolIduint96The pool ID (0 for IL chains or the core pool on Diamond).
NameTypeDescription
cfuint256The collateral factor stored before EBrake decreased it. 0 if no snapshot exists.
ltuint256The liquidation threshold at the time of the snapshot. 0 if no snapshot exists.

EventParametersDescription
ActionsPausedcaller, markets[], actions[]Emitted when actions are batch-paused on markets.
ActionPausedcaller, market, actionEmitted when a single action is paused on a market.
FlashLoanPausedcallerEmitted when flash loans are paused (BSC only).
PoolBorrowDisabledcaller, poolId, marketEmitted when pool-level borrow is disabled (BSC only).
FlashLoanAccessRevokedcaller, accountEmitted when an account’s flash loan access is revoked (BSC only).
HubPausedcaller, hubEmitted when a Liquidity Hub is paused.
HubYieldGroupPausedcaller, hub, yieldGroupEmitted when one Hub Source is paused.
HubResourcePausedcaller, yieldGroup, resourceEmitted when one resource inside a Source is paused.
CollateralFactorDecreasedcaller, market, poolId, newCFEmitted per pool where CF was actually decreased.
BorrowCapsDecreasedcaller, markets[], newBorrowCaps[]Emitted when at least one borrow cap was decreased.
SupplyCapsDecreasedcaller, markets[], newSupplyCaps[]Emitted when at least one supply cap was decreased.
CFSnapshotResetmarketEmitted when a market’s CF/LT snapshot is cleared.
BorrowCapSnapshotResetmarketEmitted when a market’s borrow cap snapshot is cleared.
SupplyCapSnapshotResetmarketEmitted when a market’s supply cap snapshot is cleared.
ErrorParametersDescription
ForbiddenActionactionA forbidden action (REPAY, SEIZE, etc.) was passed to batch pause.
ZeroAddress—A zero address was passed where a valid address is required.
MarketNotListedpoolId, marketThe market is not listed in the given pool.
SetCollateralFactorFailederrorCodesetCollateralFactor returned a non-zero error code (Diamond only).
EmptyArray—An empty array was passed where at least one element is required.
ArrayLengthMismatchexpected, actualArray lengths do not match.
CapExceedsCurrentmarket, currentCap, requestedCapAttempted to set a cap higher than the current value.
NotSupportedOnIsolatedPool—A Diamond-only function was called on an IL comptroller deployment.
CFExceedsCurrentmarket, poolId, currentCF, requestedCFAttempted to set a collateral factor higher than the current value.

Privileged EBrake mutators require an explicit Venus ACM grant for their exact signature. Public view functions such as getMarketCFSnapshot are ungated, and initialize is protected by one-time initialization rather than ACM. The set of mutator grants differs between BSC and non-BSC chains: Diamond-only functions (pauseFlashLoan, disablePoolBorrow, revokeFlashLoanAccess, decreaseCF(address,uint96,uint256)) are not intended for IL chains. The three Hub forwarders need two grants, not one: the caller’s grant on EBrake, and EBrake’s own grant on the target, which is pauseHub() or pauseYieldGroup(address) on the Hub and pauseResource(address) on the Source. Liquidity Hubs exist only on BNB Chain.

EBrake uses first-write-wins snapshots to capture the pre-incident state:

  • CF/LT snapshots: _snapshotCF only writes if poolCFs[poolId] == 0 and currentCF > 0. If the CF was already 0 before EBrake acted, nothing is recorded.
  • Cap snapshots: written only on the first actual decrease (equality skipped to avoid polluting the snapshot with a no-op call).
  • Each snapshot type (CF, borrow cap, supply cap) is independent and has its own reset function. Resetting one does not affect the others.

Collateral Factor vs Liquidation Threshold

Section titled “Collateral Factor vs Liquidation Threshold”

EBrake decreases CF but always preserves LT when calling setCollateralFactor. This is intentional:

  • Decreasing CF does not directly lower LT or make an account liquidatable by itself, but it can reduce available liquidity and restrict later borrow or redeem operations for existing accounts.
  • Decreasing LT would instantly make previously healthy positions liquidatable, harming innocent users.

Recovery VIPs may restore both CF and LT to their original values, which is why both are included in the snapshot.

On BSC there are two independent borrow flags:

  1. Global pause (pauseBorrow → _actionPaused[market][BORROW]): applies across every pool for the market.
  2. Per-pool disable (disablePoolBorrow → isBorrowAllowed[poolId][market]): applies only to the targeted pool, leaving other pools unaffected.

Both flags must allow borrowing for borrows to actually proceed. A recovery VIP must clear both flags if both were set by EBrake.

EBrake is deployed behind a TransparentUpgradeableProxy. The implementation constructor fixes COMPTROLLER and IS_ISOLATED_POOL, so every proxy-to-implementation mapping must use an implementation built for that network and Comptroller family. On the documented BSC deployment IS_ISOLATED_POOL = false; the documented IL Comptroller deployments use true.

ContractAddress
EBrake (Proxy)0x35eBaBB99c7Fb7ba0C90bCc26e5d55Cdf89C23Ec
EBrake (Implementation)0x2D36677EcA318c9536011D53aa752F042dd01DE8
ContractAddress
EBrake (Proxy)0x957c09e3Ac3d9e689244DC74307c94111FBa8B42
EBrake (Implementation)0xAC54A4D148690b7FDA22B1D29c4439aCBF668fb2

Published EBrake and DeviationSentinel audit reports are indexed in the venus-periphery v1.3.0 release, including the HashDit report on the Hub pause forwarders and HubNavDeviationSentinel. A report’s scope and reviewed commit should be checked against the current proxy implementation.