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.


afterSupply

function 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

function 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

Called 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

Called 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

Called 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

Validates 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

Returns 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

Parameter
Type
Description
Required

_owner

address

Initial owner of the hook

Yes

Reverts: ZeroAddress() if _owner is the zero address.

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

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

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:

  1. Verify isSenderAllowed[id][trancheIndex][sender] is true. Reverts with SenderNotAllowed(sender) otherwise.

  2. Verify isOnBehalfAllowed[id][trancheIndex][onBehalf] is true. Reverts with OnBehalfNotAllowed(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

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

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

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

  1. Load the factor for the market and tranche. If zero, return immediately (unconfigured).

  2. Fetch market parameters, tranche state, and borrower position from Lotus.

  3. Convert the borrower's borrow shares to assets: borrowed = borrowShares.toAssetsUp(trancheBorrowAssets, trancheBorrowShares).

  4. Compute the protocol maximum borrow: protocolMaxBorrow = collateral * oraclePrice / ORACLE_PRICE_SCALE * LLTV / WAD.

  5. Apply the factor: strictMaxBorrow = protocolMaxBorrow * factor / WAD.

  6. If borrowed > strictMaxBorrow, revert with HealthFactorTooLow(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

  • Learn → Hooks for conceptual explanation

  • Build → Hooks for implementation guide

  • Reference → Admin for setMarketHook documentation

Last updated