# Integrating AEGIS Engine

This page is for builders: developers writing routers, vault strategies, keepers, aggregators, front-ends, or any other code that calls AEGIS Engine programmatically.

The target audience is someone who has read What is AEGIS Engine? and How Borrowing Works and now wants to write code.

### The mental model for integrators

AEGIS Engine is a two-layer stack:

* Core: AegisEngine (singleton) + supporting managers (OracleManager, LimitOrderManager, VaultRegistry, DynamicFeeManager, PoolPolicyManager).
* Periphery: AegisRouterV1.

In v1, almost all integrations should go through AegisRouterV1. The core is designed to be composed by the router, not called directly from EOAs or arbitrary contracts. Direct engine calls are possible but require you to re-implement the session and PM.unlock orchestration yourself.

Inside the router, the unit of work is an ExecutionBatch: an ordered list of action opcodes with a requiresV4Unlock flag. The router can execute multiple batches in sequence, and can split work between Phase-0 (PM locked) and Phase-1 (PM unlocked).

### Key patterns

#### 1. Phase-0 and Phase-1

The Uniswap v4 PositionManager restricts ERC-721 transfers of its NFTs to when the PoolManager is locked. Engine's NFT attach and detach therefore have to run in Phase-0 — outside the PM.unlock frame.

Conversely, anything that touches the PoolManager (deposit, withdraw, borrow, repay, peel, micro-liq) has to run in Phase-1 — inside PM.unlock.

The router exposes execute2Phase(pre, actions, deadline) where pre is the Phase-0 batch and actions is the Phase-1 batch. Inside the router they are processed in order, with a single PM.unlock transition between them.

If you mix up the phases, the call reverts with ManagerLocked or with the NFT transfer failing. Check requiresV4Unlock on your batch carefully.

#### 2. Sentinel batching

Often you'll want to pass value between actions without settling through ERC-20. The router supports this via the to = address(0) sentinel on withdrawIdle:

\[Phase-1]

WITHDRAW\_IDLE(vaultA, token0, amount, to=address(0))  // AE retains positive delta

DEPOSIT\_IDLE(vaultB, token0, amount, ...)              // consumes the delta

The PoolManager enforces delta-zero at frame end, but within the frame AE can hold a positive delta across actions. This is how cross-vault rebalances, borrow-and-redeploy, and atomic repay-from-another-position all work.

Similarly, TransientNftTracker lets the router address the "last attached" / "last minted" NFT via sentinels (USE\_LAST\_NFT) so that composed calls don't need to know IDs statically.

#### 3. Session discipline

Every vault mutation requires the vault to be unlocked in the current AE session by a caller authorized per VaultRegistry. Explicit pattern:

UNLOCK\_VAULT(vaultId)

&#x20; // all mutations on vaultId

LOCK\_VAULT(vaultId)  // enforces caps

A session can have multiple vaults unlocked simultaneously (typically rare, but supported for cross-vault flows). All unlocked vaults must be re-locked before the session ends or the transaction reverts with ERR\_VAULTS\_NOT\_LOCKED.

lockVault is where the LTV and utilization caps are enforced. If you skip LOCK\_VAULT, the engine session epilogue calls it implicitly, but you should include it explicitly to make the call flow legible.

#### 4. First-touch accrual

The first PM-touching action on a given pool in a session triggers a feeSync(); accrue(); pass. Subsequent same-pool actions in the same session reuse the cached accrue result via EIP-1153 transient storage. This means a batch of three deposits into three different vaults of the same pool only pays accrue gas once.

You don't have to do anything to opt into this — it happens automatically. But if you're gas-profiling, it explains why "first action in batch" is more expensive than later same-pool actions.

#### 5. Pre-fund, don't operator-pull (v1)

AegisRouterV1 uses a pre-fund model: the router calls PoolManager.sync → transferFrom(user → PM) → settleFor(AE). AE then consumes the resulting positive delta on its ERC-6909 balance.

This means:

* Users approve the router (or Permit2), not the engine.
* The engine never needs any approval from the user.
* Operator-pull (where AE pulls from the router's PM ERC-6909 via PM.burn) is reserved for future router versions (operatorPull = true flag). Pass false in v1.

If you build a custom router, stick with the pre-fund pattern unless you deeply understand the operator-approval surface.

### The action set

A condensed list of the most useful router actions. See [Router and Actions Reference](http://../07-reference/router-and-actions-reference.md) for opcodes and exact calldata encoding.

Vault lifecycle (AE actions):

* AE\_CREATE\_VAULT(poolKey) — mints a vault NFT, returns vaultId.
* AE\_UNLOCK\_VAULT(vaultId) / AE\_LOCK\_VAULT(vaultId) — session begin/end per vault.
* AE\_MODIFY\_IDLE(vaultId, currency, deltaInt) — deposit (+) or withdraw (−) idle.
* AE\_MODIFY\_DEBT(vaultId, dL\_signed) — borrow (+) or repay (−). Sentinel: dL=0 on repay repays full rL.
* AE\_ATTACH\_NFT(vaultId, nftRef) / AE\_DETACH\_NFT(vaultId, nftRef, to) — custody.
* AE\_PEEL\_OR\_MICRO\_LIQUIDATE(vaultId, params) — keeper lane.
* AE\_MODIFY\_LIQUIDITY(vaultId, sharesDelta) — LP deposit/redeem on sL (minting or burning shares).
* AE\_FLUSH\_POSITIVE\_DELTA(currency, to) — governance-only; drains a stuck positive delta.

Limit order actions (LO actions): LO\_PLACE\_ORDER, LO\_CANCEL\_ORDER, LO\_WITHDRAW\_ORDER, LO\_MODIFY\_LIQUIDITIES.

Uniswap v4 actions (CL actions): mint, increase/decrease liquidity, collect, burn — these are standard v4 PositionManager operations encoded inline.

Settlement helpers (from BaseActionsRouter): SETTLE, TAKE, SETTLE\_ERC6909, TAKE\_ERC6909 — move value between AE, PM, and the user.

### Reading state

Off-chain integrations should use:

* AegisStateView — a read-only wrapper exposing per-vault and per-market state (rL, idleBalance, cMin, borrowIndexWad, equityLWad, totalRlBorrowed, sL\_totalSupply, etc.).
* AegisStateLibrary — library functions that compute slots for extsload lookups. Useful for building custom indexers or fast on-chain reads.
* aegis-engine-subgraph — the reference subgraph implementation indexing markets, vaults, and events.

For dynamic fee state, read DynamicFeeManager.getLatestFeeQuote(poolId) and getFeeState(poolId). For oracle observations, OracleManager.observe(poolKey, secondsAgos) or consult(poolKey, secondsAgo).

### SDK

aegis-engine-sdk provides TypeScript bindings, common action builders, and helpers for encoding ExecutionBatch arrays. It is the easiest way to call the router from a front-end or from Node-based automation.

import { AegisClient } from '@labs-solo/aegis-engine-sdk'

const client = new AegisClient({ rpcUrl, chainId })

const batch = client.batch()

&#x20; .createVault(poolKey)

&#x20; .depositIdle(vaultId, token0, amount0)

&#x20; .depositIdle(vaultId, token1, amount1)

&#x20; .borrowL(vaultId, dL)

&#x20; .withdrawIdle(vaultId, token0, amount0Out, userAddress)

&#x20; .lockVault(vaultId)

&#x20; .build()

await client.execute(batch, { deadline })

TODO: Confirm SDK public API before v1.0 — the above is representative but the method names are not yet locked.

### Keeper patterns

For keepers, the essential loop is:

1. Index all markets with at least some totalRlBorrowed > 0.
2. For each market, index all vaults with rL > 0.
3. For each vault, compute current C\_min using the pool's current √P and the vault's idle + attached NFT positions.
4. If rL > C\_min × MAX\_LTV\_PIPS / PIPS, submit stabilize(vaultId) as a keeper transaction.
5. Handle zero-fill gracefully (the operation returns cleanly rather than reverting).

TODO: Link to an example keeper implementation once one is published in a public repo.

### Gas profile

Approximate gas figures (cold, mainnet-style gas prices) for the main actions, TODO: confirm against deployed gas report before mainnet launch:

* Create vault: \~150k
* Deposit idle: \~90k (first touch per pool per session, adds \~40k accrue)
* Borrow: \~250k (first touch adds accrue)
* Repay: \~220k
* Stabilize (peel): \~180k
* Stabilize (micro-liq): \~200k

Batching helps significantly: a create-deposit-borrow-withdraw sequence is typically \~50-80k cheaper than the individual calls because accrue runs only once and the PM.unlock cost is amortized.

### What to be careful about

A short checklist from integrators who have done this before:

* Don't forget LOCK\_VAULT. Failure to relock at session end causes the entire transaction to revert. The session epilogue will catch this, but making it explicit is clearer.
* Approvals go to the router, not the engine. Users who approved AegisEngine directly find their transactions fail.
* Phase-0 is for attach/detach only. Putting a DEPOSIT\_IDLE in the Phase-0 batch reverts with ManagerLocked.
* Vault NFT transfers are session-gated. Don't try to transfer a vault mid-mutation; \_update on VaultRegistry reverts if the vault is unlocked.
* Borrow against current pool state. The token amounts you receive on BORROW\_L depend on the pool's √P at the moment of the burn. If you're swapping-and-redepositing atomically, this is fine; if you're building a UX that pre-quotes amounts, refresh your quote close to submission.
* Dynamic fees apply to swaps. If you swap in an AEGIS-enabled pool as part of your flow, the fee paid reflects DFM's current quote — not a static tier. This matters for strategy PnL modeling.

### Reference deployments

Deployed contract addresses for the current supported networks are listed in Deployed Contracts.

If you are integrating ahead of mainnet, the testnet deployment uses the same addresses across Ethereum Sepolia, Base Sepolia, Optimism Sepolia, and Unichain Sepolia (by deterministic CREATE2). Refer to the AegisDependencies.sol contract and the script/Create2Deploy.s.sol script in the aegis-engine repo for the 4-phase deterministic deployment flow.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.aegis.markets/integrating-aegis-engine.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
