Guard system
How to write calls that pass the Guard System, and how to handle rejections
For the risk-model framing — what the Guard System prevents and why — see Security: guard system. This page is the integrator's side: how to write calls that don't revert, how to enumerate what's supported, and how to surface failures back to users.
Call flow
Every vault interaction flows through PoolLogic.execTransaction(address to, bytes data):
The vault looks up the contract guard registered for
tovia the factory.The guard's
txGuard(poolManagerLogic, to, data)is called. It decodes the calldata, enforces protocol-specific rules, and returns atxTypeplusisPublicflag.If the contract guard returns
txType == 0(no match or rejection), or isn't registered, the vault falls back to the asset guard forto. If no asset guard is registered either, it defaults to the governance-configuredERC20Guardas a last resort. A revert withdh23means every layer returnedtxType == 0.On approval, the external call executes.
Some guards implement
afterTxGuardto track post-call state (for example, recording open perp positions).
The manager/trader permission check happens at the vault layer before the guard runs. The guard itself doesn't distinguish manager from trader — see trader delegation for how that's enforced.
Two guard categories
Contract guards — registered against a destination contract address (a swap router, a lending pool, a position manager). They govern what calls can be made to that contract. Examples: OneInchV6Guard, AaveLendingPoolGuardV3, UniswapV3NonfungiblePositionGuard, GmxExchangeRouterContractGuard.
Asset guards — registered against an asset type (a token, an LP NFT, a perp position). They govern how the vault holds and unwinds that asset — balance calculation, USD pricing, withdrawal behavior. Examples: ERC20Guard, UniswapV3AssetGuard, AaveLendingPoolAssetGuard, HyperliquidPositionGuard.
A single vault operation may touch both. A Uniswap V3 mint needs the position manager contract guard to approve the call and an asset guard registered for the resulting LP NFT so the vault can price and withdraw it.
Enumerating support
Is this protocol callable from a vault?
Is this asset supported?
Is this asset enabled on a specific vault?
A guard being registered globally is necessary but not sufficient — the manager also has to have enabled that asset on their vault.
Common revert codes
Vault reverts use dh-prefixed strings. The full list of codes with descriptions is maintained in the contracts repo:
Guard registry
The exact set of guards differs per chain (see deployment matrix). The full per-chain lists of contract guards, asset guards, and deprecated guards are maintained in the config/ directory of the contracts repo — each chain folder contains:
dHEDGE Governance Contract Guards.csv— registered contract guardsdHEDGE Governance Asset Guards.csv— registered asset guardsdHEDGE Assets list.json— supported assets
You can also query getContractGuard() and getAssetGuard() on the factory at runtime.
See also
Security: guard system — the risk framing
Contract addresses — where to find the factory
SDK — typed helpers for guard queries
Deployment matrix — per-chain guard availability
Last updated

