Hooks
API reference for the Lotus hooks system covering ILotusHooks interface, permission flags, AllowlistHook, and BorrowHealthGuardHook parameters.
The hooks system consists of the ILotusHooks interface (which hook contracts implement), the Hooks.sol library (which the core protocol uses to manage and invoke hooks), and two production implementations: AllowlistHook and BorrowHealthGuardHook.
ILotusHooks Interface
All hooks are invoked via staticcall. Each method must return its own function selector (bytes4) on success. Any revert causes the parent operation to revert.
Hooks are invoked via staticcall and cannot modify state. A hook that reverts on every call will lock users out of all hooked operations on that market.
afterSupply
afterSupplyfunction afterSupply(SupplyParams calldata params) external view returns (bytes4);Called after supply state changes, before token transfer.
SupplyParams
| Field | Type | Description | |||***| | id | Id | Market identifier | | trancheIndex | uint256 | Tranche being supplied to | | sender | address | Address that initiated the supply call | | onBehalf | address | Address credited with supply shares | | assets | uint256 | Amount of loan tokens supplied | | shares | uint256 | Amount of supply shares minted |
afterBorrow
afterBorrowfunction afterBorrow(BorrowParams calldata params) external view returns (bytes4);Called after borrow state changes and health checks, before token transfer.
BorrowParams
| Field | Type | Description | |||***| | id | Id | Market identifier | | trancheIndex | uint256 | Tranche being borrowed from | | sender | address | Address that initiated the borrow call | | onBehalf | address | Address whose position is debited | | receiver | address | Address receiving the borrowed tokens | | assets | uint256 | Amount of loan tokens borrowed | | shares | uint256 | Amount of borrow shares created |
afterSupplyCollateral
afterSupplyCollateralCalled after collateral supply state changes, before token transfer.
SupplyCollateralParams
| Field | Type | Description | |||***| | id | Id | Market identifier | | trancheIndex | uint256 | Tranche receiving collateral | | sender | address | Address that initiated the collateral supply | | onBehalf | address | Address credited with the collateral | | assets | uint256 | Amount of collateral tokens deposited |
afterWithdraw
afterWithdrawCalled after withdrawal state changes, before token transfer.
WithdrawParams
| Field | Type | Description | |||***| | id | Id | Market identifier | | trancheIndex | uint256 | Tranche being withdrawn from | | sender | address | Address that initiated the withdrawal | | onBehalf | address | Address whose supply shares are burned | | receiver | address | Address receiving the withdrawn tokens | | assets | uint256 | Amount of loan tokens withdrawn | | shares | uint256 | Amount of supply shares burned | | shouldAccrueInterest | bool | Whether interest was accrued before withdrawal |
afterWithdrawCollateral
afterWithdrawCollateralCalled after collateral withdrawal state changes, before token transfer.
WithdrawCollateralParams
| Field | Type | Description | |||***| | id | Id | Market identifier | | trancheIndex | uint256 | Tranche from which collateral is withdrawn | | sender | address | Address that initiated the collateral withdrawal | | onBehalf | address | Address whose collateral is being withdrawn | | receiver | address | Address receiving the collateral tokens | | assets | uint256 | Amount of collateral tokens withdrawn |
Hooks Library
The Hooks.sol library provides permission flags, configuration validation, and the internal call mechanism used by Lotus core.
Permission Flags
| Flag | Value | Triggers On | |||***| | AFTER_SUPPLY_FLAG | 1 << 0 (1) | supply() | | AFTER_BORROW_FLAG | 1 << 1 (2) | borrow() | | AFTER_SUPPLY_COLLATERAL_FLAG | 1 << 2 (4) | supplyCollateral() | | AFTER_WITHDRAW_FLAG | 1 << 3 (8) | withdraw() | | AFTER_WITHDRAW_COLLATERAL_FLAG | 1 << 4 (16) | withdrawCollateral() |
Combine flags with bitwise OR. For example, a hook that fires on both supply and borrow uses AFTER_SUPPLY_FLAG | AFTER_BORROW_FLAG (3).
HookConfig
Stored per-market. The hook address is the deployed hook contract; permissions is the bitmask of active flags.
validateHookConfig
validateHookConfigValidates a hook configuration. If hook is the zero address, returns an empty config (hooks disabled). If hook is non-zero but contains no code, reverts with InvalidHook(hook).
hasPermission
hasPermissionReturns true if the given flag is set in the permissions bitmask.
Errors
| Error | When | ||| | HookCallFailed(address hook, bytes4 selector) | The hook's staticcall reverted | | InvalidHookResponse(address hook, bytes4 expected, bytes4 received) | The hook returned an unexpected selector | | InvalidHook(address hook) | The hook address has no deployed code |
AllowlistHook
Restricts market operations to whitelisted addresses. Checks both the transaction sender and the on-behalf address on all five hook points.
Storage
constructor
constructor| Parameter | Type | Description | Required | ||||| | _owner | address | Initial owner of the hook | Yes |
Reverts: ZeroAddress() if _owner is the zero address.
setOwner
setOwner| Parameter | Type | Description | Required | ||||| | newOwner | address | New owner address | Yes |
Reverts: NotOwner() if caller is not the current owner. ZeroAddress() if newOwner is the zero address.
setSenderAllowed
setSenderAllowed| Parameter | Type | Description | Required | ||||| | id | Id | Market identifier | Yes | | trancheIndex | uint256 | Tranche index | Yes | | who | address | Address to allow or disallow as sender | Yes | | allowed | bool | Whether the address is allowed | Yes |
Reverts: NotOwner() if caller is not the current owner.
setOnBehalfAllowed
setOnBehalfAllowed| Parameter | Type | Description | Required | ||||| | id | Id | Market identifier | Yes | | trancheIndex | uint256 | Tranche index | Yes | | who | address | Address to allow or disallow as on-behalf target | Yes | | allowed | bool | Whether the address is allowed | Yes |
Reverts: NotOwner() if caller is not the current owner.
Hook Behavior
All five hook methods (afterSupply, afterBorrow, afterSupplyCollateral, afterWithdraw, afterWithdrawCollateral) perform the same check:
Verify
isSenderAllowed[id][trancheIndex][sender]istrue. Reverts withSenderNotAllowed(sender)otherwise.Verify
isOnBehalfAllowed[id][trancheIndex][onBehalf]istrue. Reverts withOnBehalfNotAllowed(onBehalf)otherwise.
Errors
| Error | When | ||| | SenderNotAllowed(address sender) | Sender is not on the allowlist for this market/tranche | | OnBehalfNotAllowed(address onBehalf) | On-behalf address is not on the allowlist for this market/tranche | | NotOwner() | Caller is not the hook owner | | ZeroAddress() | Zero address provided where non-zero is required |
BorrowHealthGuardHook
Enforces a stricter health requirement on borrowers by applying a multiplier (factor) to the protocol's LLTV. Only hooks into afterBorrow; all other hook points use the default pass-through from BaseLotusHook.
Storage
The factor is in WAD format (1e18 = 100%). A factor of 0.9e18 means the borrower can only borrow up to 90% of the protocol maximum.
constructor
constructor| Parameter | Type | Description | Required | ||||| | _owner | address | Initial owner of the hook | Yes | | _lotus | ILotus | Address of the Lotus core contract | Yes |
Reverts: ZeroAddress() if either parameter is the zero address.
setOwner
setOwner| Parameter | Type | Description | Required | ||||| | newOwner | address | New owner address | Yes |
Reverts: NotOwner() if caller is not the current owner. ZeroAddress() if newOwner is the zero address.
setFactor
setFactor| Parameter | Type | Description | Required | ||||| | id | Id | Market identifier | Yes | | trancheIndex | uint256 | Tranche index | Yes | | newFactor | uint256 | Health factor multiplier in WAD (must be ≤ 1e18) | Yes |
Reverts: NotOwner() if caller is not the current owner. InvalidFactor(newFactor) if newFactor > 1e18.
A factor of 0 means the guard is not configured for that tranche (no check performed). Setting a factor effectively tightens the borrowing limit: strictMaxBorrow = protocolMaxBorrow * factor / WAD.
afterBorrow Behavior
afterBorrow BehaviorLoad the factor for the market and tranche. If zero, return immediately (unconfigured).
Fetch market parameters, tranche state, and borrower position from Lotus.
Convert the borrower's borrow shares to assets:
borrowed = borrowShares.toAssetsUp(trancheBorrowAssets, trancheBorrowShares).Compute the protocol maximum borrow:
protocolMaxBorrow = collateral * oraclePrice / ORACLE_PRICE_SCALE * LLTV / WAD.Apply the factor:
strictMaxBorrow = protocolMaxBorrow * factor / WAD.If
borrowed > strictMaxBorrow, revert withHealthFactorTooLow(borrowed, strictMaxBorrow).
Errors
| Error | When | ||| | HealthFactorTooLow(uint256 borrowed, uint256 maxAllowed) | Borrow exceeds the guard-adjusted maximum | | InvalidFactor(uint256 factor) | Factor exceeds 1e18 | | NotOwner() | Caller is not the hook owner | | ZeroAddress() | Zero address provided in constructor |
See Also
Last updated

