Contract map
Contract systems
BlendSafeFactory - Safe deployment and setup
BlendSafeFactory - Safe deployment and setup
Deploys and sets up Gnosis Safe proxies with Blend’s module and guard architecture.Key functions:
deploySafe is restricted to the module’s executor (StrategyManager(module).executor()). It validates non-empty owners, valid threshold, and that module/guard are set.enableModuleAndSetGuardFromFactory reads module and guard addresses from factory storage at runtime. This is what enables cross-chain address determinism. Module and guard can differ per chain while Safe addresses stay identical.Setup installs three components:- RolesReceiver as module (strategy execution)
- RolesGuard as transaction guard (pause + access control)
- Safe4337Module as module and fallback handler (account abstraction)
StrategyManager - Rebalance orchestration and rate limiting
StrategyManager - Rebalance orchestration and rate limiting
Core orchestration layer. Manages vault configs, executes rebalances, and enforces rate limiting.Key structs:Key functions:Security invariants:
- Rate limited per (safe, vault) pair via
keccak256(abi.encodePacked(safe, vault)) MIN_SECONDS_BETWEEN_OPERATIONSenforced (1-300 seconds)- Timestamp set before execution; full transaction reverts on failure
- Separate reentrancy guards:
isRebalanceInitiatedandisVaultActionInitiated - Config validation rejects duplicate marketIds, leverage below 1e18, and duplicate action controllers
Roles system - Guards, broadcasting, and receiving
Roles system - Guards, broadcasting, and receiving
Three contracts that enforce transaction validation and propagate config across chains.RolesGuard - Transaction guard on every Safe:When paused: Same-chain calls route directly to
checkTransaction allows Safe owners to execute directly. checkModuleTransaction blocks ALL module transactions with no owner bypass.RolesBroadcaster - Sends role updates cross-chain via LayerZero:sameChainReceiver.processSameChainCall().RolesReceiver - Receives and applies role updates. Extends StrategyManager:- Immutable trust anchors:
TRUSTED_BROADCASTER(bytes32) andTRUSTED_CHAIN_ID(uint32) set at construction setPeer()always reverts (peer locked at deployment)_lzSend()always reverts (receive-only)- Processes
updateVaultConfigandsetExecutormessages - Double-checks source chain ID AND broadcaster address for defense-in-depth
MorphoVaultController - Morpho rebalancing with flashloans
MorphoVaultController - Morpho rebalancing with flashloans
Orchestrates Morpho vault rebalancing through Bundler3 flashloans.Execution flow:
- Wrap native ETH if vault token is WETH
- Deposit existing vault tokens into vault
- Process all decrease operations (repay debt, withdraw collateral)
- Process all increase operations (supply collateral, borrow)
- Clean up GeneralAdapter (deposit remaining tokens back)
-
MorphoLeverageLib - Manages leveraged positions via flashloans.
_increaseLeverageAllocationflashloans loan tokens, swaps to collateral, supplies to Morpho, borrows back._decreaseLeverageAllocationruns the reverse. - MorphoSeedingLib - Handles non-leveraged collateral supply. No borrowing involved.
- MorphoVaultLib - Utility functions for borrow/supply math, deposit/withdraw with slippage checks, and price data decoding.
- Temporarily authorizes and then cleans up GeneralAdapter in Morpho
- Slippage protection via
assets/sharesratio checks againstassetPerShare - Processes decreases before increases (frees capital first)
Withdrawal controllers - User and vault withdrawals
Withdrawal controllers - User and vault withdrawals
Two controllers handle different withdrawal scenarios.UserWithdrawController - Full 9-step withdrawal lifecycle:The 9 steps:
- Validate amount, module, vault, single-owner requirement
- Liquidity reset via VaultController.executeRebalance
- Snapshot balance, resolve max withdrawal
- Force deallocate from adapters (zero-penalty only)
- Vault withdrawal with slippage protection
- Determine actual withdrawn amount
- Deduct withdrawal fee (max 5%)
- Transfer to owner OR bridge cross-chain
- Redeposit remaining assets into vault
bridgeOffsets (recipientOffset, inputAmountOffset, outputAmountOffset, destDecimals) to inject values into pre-built bridge calldata.VaultWithdrawController - Simple atomic vault redemption:- No fees, no bridging, no liquidity reset
- Validates amount is within balance
- Calls
MorphoVaultLib._withdrawAssetsdirectly - Assets stay in the Safe
Swap adapters - DEX execution with slippage protection
Swap adapters - DEX execution with slippage protection
Three adapters handle token swaps within Bundler3 multicalls.SwapAdapter - Base contract:Three layers of slippage protection:
- Governance max (
maxSlippageBps) - hard ceiling - Per-swap (
slippageBps <= maxSlippageBps) - caller-specified - Oracle-verified minimum output via
PriceLib
checkSwapInvariants ensures the adapter holds zero tokens before and after every swap.WhitelistedSwapAdapter - Adds temporal access control. Swaps only execute during active isRebalanceInitiated() or isVaultActionInitiated() windows. At least one of ALLOW_ON_REBALANCE / ALLOW_ON_VAULT_ACTION must be true.BalanceReplacementAdapter - Reads token balances and injects them into calldata at specified offsets using bitwise OR. Handles temporary approvals and balance draining.Cross-chain adapters - Across and CCTP bridging
Cross-chain adapters - Across and CCTP bridging
Two bridge adapters and a batching controller for cross-chain transfers.AcrossXChainAdapter - Bridges via Across V3 SpokePool:Supports any token. Validates slippage via
PriceLib.normalize and applySlippage. Validates all address and amount parameters match. Refunds dust to sender.CCTPXChainAdapter - Bridges USDC via Circle CCTP V2:USDC-only. Queries burnLimitsPerMessage from the minter. If the amount exceeds the limit, it splits into multiple depositForBurn calls automatically.Uses maxFee=0, minFinalityThreshold=2000 (Standard finality).XChainVaultAction - Orchestrates batched cross-chain vault actions:- Requests MUST be sorted ascending by
destinationChainId(enables O(N) duplicate detection) - Single vault withdrawal, then executes each bridge request
- Verifies zero adapter balance after each transfer
- Sweeps remaining balance back to vault
Vault controllers - Base controllers and perpetual trading
Vault controllers - Base controllers and perpetual trading
Layered controller system for vault operations and perpetual trading.DelegateController - Base security.
_onlyDelegateCall modifier compares address(this) against immutable SELF. Ensures code only runs via delegatecall from a Safe.VaultController - Extends DelegateController. Provides _validateRebalanceData modifier that checks rebalanceData length matches markets, all marketIds match, and vault is configured.VaultActionController - Extends DelegateController. Provides the executeAction(vault, strategyData, extraData) entry point that delegates to abstract _execute.BasePerpVaultController - Abstract base for perpetual trading with a 6-step rebalance flow:_preTransaction()(protocol-specific setup)- Consolidate Safe collateral into vault
- Close all positions (decreases first)
- Consolidate freed capital
- Open new positions (increases with amount > 0)
- Deposit remaining and emit event
_validateSlippage and _validatePriceDeviation.OstiumVaultController - Concrete implementation for Ostium perpetual trading. Uses IOstiumRegistry for dynamic contract resolution. MarketId encoding packs pairIndex (16 bits) plus an isLong flag.VaultToVaultAction - Moves funds between vaults with optional swap. Validates both source and destination vaults are registered. Uses SwapAdapter with oracle slippage protection when asset types differ.Supporting libraries - Oracles, calldata, and market wrappers
Supporting libraries - Oracles, calldata, and market wrappers
Utility contracts used across the protocol.PriceLib - Oracle and decimal utilities:CallBuilder - Constructs Bundler3
Call structs. All functions are internal pure for deterministic calldata encoding. Covers: swapToCollateral, swapToLoanToken, wrapNative, erc20Transfer, erc4626Deposit/Withdraw/Redeem, morphoSupplyCollateral, morphoBorrow, morphoRepay, morphoWithdrawCollateral, morphoFlashLoan.MarketWrapper - ERC-4626 vault wrapping any ERC-20 with authorization gating:_depositrequiresroleReceiver.isRebalanceInitiated()to be true- Dual-layer inflation attack protection: virtual shares via decimal offset plus burn deposit to address(1)
createBurnDeposit()locks 0.001 tokens to prevent empty vault attacks
Architecture overview
See how these contracts fit into the full system.
Security deep dive
Understand the 4 security layers protecting every transaction.
Deployments
Find deployed contract addresses on each chain.
Audits
Review independent security audit reports.