logo
Smart Contracts ReferencePermissions

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

  1. Collateral Preservation: The pod's collateral balance must not decrease below a threshold.

  2. Debt Ceiling: The pod's debt must not increase above a threshold.

  3. Health Floor: The loan-to-value (LTV) ratio must stay within safe bounds.

  4. 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

  1. Off-chain: A Merkle tree is constructed where each leaf is keccak256(abi.encode(decoderOutput, target, selector, value)).

  2. On-chain: Only the root is stored via merkleRoots[solver] = root.

  3. Verification: When a solver executes an action, they provide a Merkle proof in their transaction payload. The PositionGuard verifies the proof against the stored root, checking the explicit function selector the solver is attempting to invoke (e.g. AaveV3UniversalAdapter.supplyAndBorrow).

Was this page helpful?

Last updated Apr 6, 2026

Built with Documentation.AI