Blend’s on-chain protocol consists of 9 contract systems handling Safe deployment, vault operations, cross-chain bridging, and security enforcement.Documentation Index
Fetch the complete documentation index at: https://docs.blend.money/llms.txt
Use this file to discover all available pages before exploring further.
Contract map
Contract systems
BlendSafeFactory - Safe deployment and setup
BlendSafeFactory - Safe deployment and setup
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
- 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
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
- 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
- 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
- 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
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
_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
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