Execution & Permissions
How PositionGuard and MerkleRegistry restrict Solver execution.
Safe Execution via PositionGuard
When a solver calls executeSolverAction on a borrower's isolated LoanPod (for instance, to move debt from Aave to Morpho to capture a better variable rate spread), the transaction must pass through PositionGuard.
PositionGuard enforces transaction-level safety invariants. It actively checks that critical limits hold before and after the action.
Invariants Checked
-
Collateral Preservation: The pod's collateral balance must not decrease below a threshold.
-
Debt Ceiling: The pod's debt must not increase above a threshold.
-
Health Floor: The loan-to-value (LTV) ratio must stay within safe bounds.
-
Absolute Floor (Anti-Grinding): Prevents positions from being drained through many small, cumulative adverse actions by malicious actors.
Authorization via IRIS_MerkleRegistry
Authorization via the Merkle registry is a future-proof extensibility feature. In its current form, solver actions are simple enough that PositionGuard alone is sufficient to validate execution. However, as solver logic grows more complex — spanning multiple protocols, contract calls, or conditional action paths — the system will leverage IRIS_MerkleRegistry to explicitly scope and verify what each solver is permitted to do, without bloating on-chain storage.
Even if an action maintains all financial invariants, solvers cannot call arbitrary third-party contracts using user collateral.
The IRIS_MerkleRegistry is a gas-efficient permission system defining which actions each solver is structurally allowed to execute.
Instead of storing a full array map of allowed (target, selector, value) tuples on-chain, each solver has a single Merkle root stored on-chain. The leaves of the Merkle tree encode specific permissions.
Execution Flow
-
Off-chain: A Merkle tree is constructed where each leaf is
keccak256(abi.encode(decoderOutput, target, selector, value)). -
On-chain: Only the root is stored via
merkleRoots[solver] = root. -
Verification: When a solver executes an action, they provide a Merkle proof in their transaction payload. The
PositionGuardverifies the proof against the stored root, checking the explicit function selector the solver is attempting to invoke (e.g.AaveV3UniversalAdapter.supplyAndBorrow).