@aegis-engine/core 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import type { AegisEngineBorrowCapacity, AegisEngineBorrowCapacityInput, AegisEngineBorrowQuote, AegisEngineBorrowQuoteInput, AegisEngineAddCollateralQuoteInput, AegisEngineCloseQuoteInput, AegisEngineDepositQuote, AegisEngineDepositQuoteInput, AegisEngineIdleWithdrawQuoteInput, AegisEnginePositionActionQuote, AegisEngineRedeemQuoteInput, AegisEngineRepayQuoteInput } from './types.js';
1
+ import type { AegisEngineBorrowCapacity, AegisEngineBorrowCapacityInput, AegisEngineBorrowQuote, AegisEngineBorrowQuoteInput, AegisEngineAddCollateralQuoteInput, AegisEngineCloseQuoteInput, AegisEngineDepositQuote, AegisEngineDepositQuoteInput, AegisEngineIdleWithdrawQuoteInput, AegisEnginePositionActionQuote, AegisEngineRedeemQuoteInput, AegisEngineRepayQuoteInput, AegisEngineTradeOpenQuote, AegisEngineTradeOpenQuoteInput } from './types.js';
2
2
  export declare function quoteEngineDeposit(input: AegisEngineDepositQuoteInput): Promise<AegisEngineDepositQuote>;
3
3
  export declare function quoteEngineBorrow(input: AegisEngineBorrowQuoteInput): Promise<AegisEngineBorrowQuote>;
4
4
  export declare function quoteEngineAddCollateral(input: AegisEngineAddCollateralQuoteInput): Promise<AegisEnginePositionActionQuote>;
@@ -7,3 +7,12 @@ export declare function quoteEngineRepay(input: AegisEngineRepayQuoteInput): Pro
7
7
  export declare function quoteEngineCloseVault(input: AegisEngineCloseQuoteInput): Promise<AegisEnginePositionActionQuote>;
8
8
  export declare function quoteEngineIdleWithdraw(input: AegisEngineIdleWithdrawQuoteInput): Promise<AegisEnginePositionActionQuote>;
9
9
  export declare function quoteEngineRedeem(input: AegisEngineRedeemQuoteInput): Promise<AegisEnginePositionActionQuote>;
10
+ /**
11
+ * Quotes one tap open on a fresh vault: size the α band against a block-pinned
12
+ * frame, turn the solver's signed `q` into the router's single internal swap,
13
+ * and encode create → deposit → borrow → swap → deposit → lock as one call.
14
+ *
15
+ * Every economic rejection is a typed `infeasibleReason` carrying the bound
16
+ * that caused it. Only untrusted deployment metadata and malformed input throw.
17
+ */
18
+ export declare function quoteEngineTradeOpen(input: AegisEngineTradeOpenQuoteInput): Promise<AegisEngineTradeOpenQuote>;
@@ -1,11 +1,20 @@
1
1
  import type { Address } from 'viem';
2
- import type { AegisEngineBorrowQuoteContext, AegisEngineMarket, AegisEngineMarketReadInput, AegisEngineMarketSnapshot, AegisEnginePositionsHydration, AegisEnginePositionsHydrationInput, AegisEngineVaultActivityEntry } from './types.js';
3
- export declare class AegisEngineMarketNotReadyError extends Error {
2
+ import { UserFacingError } from '../errors.js';
3
+ import type { AegisEngineBorrowQuoteContext, AegisEngineMarket, AegisEngineMarketMark, AegisEngineMarketReadInput, AegisEngineMarketSnapshot, AegisEnginePositionsHydration, AegisEnginePositionsHydrationInput, AegisEngineVaultActivityEntry } from './types.js';
4
+ export declare class AegisEngineMarketNotReadyError extends UserFacingError {
4
5
  constructor(message: string);
5
6
  }
6
7
  /** Test-only reset for the module-owned, weakly client-scoped read caches. */
7
8
  export declare function clearEngineReadCaches(): void;
8
9
  export declare function readEngineMarketSnapshot(input: AegisEngineMarketReadInput): Promise<AegisEngineMarketSnapshot>;
10
+ /**
11
+ * Live pool mid for one market, in token1-per-token0 display units — the same
12
+ * price plane `quoteEngineTradeOpen` sizes against. Reuses the market-snapshot
13
+ * read and its short TTL, so a UI can poll this for each visible market
14
+ * without new RPC surface: within the freshness window repeated calls join the
15
+ * in-flight snapshot instead of fanning out.
16
+ */
17
+ export declare function readEngineMarketMark(input: AegisEngineMarketReadInput): Promise<AegisEngineMarketMark>;
9
18
  export declare function readEngineBorrowQuoteContext(input: AegisEngineMarketReadInput, execution?: {
10
19
  owner: Address;
11
20
  vaultId?: bigint;
@@ -0,0 +1,17 @@
1
+ import { type MethodParameters, type TapOpenPositionOptions } from '@labs-solo/aegis-engine-sdk';
2
+ /**
3
+ * Encode a tap-open without routing internally borrowed swap balances through
4
+ * the user's wallet.
5
+ *
6
+ * SDK 0.30's public builder closes both the Engine and PoolManager deltas via
7
+ * the message sender. That lands only when both pool tokens have durable
8
+ * Permit2 caps, even though the user supplies one deposit token. This adapter
9
+ * keeps the borrowed input and swap output in router custody: TAKE_AE ->
10
+ * router-funded V4 SETTLE -> router TAKE -> router-funded SETTLE_AE. The only
11
+ * user-funded transfer is the declared deposit.
12
+ *
13
+ * Keep this implementation at the private-SDK boundary. Remove it after the
14
+ * equivalent builder ships in a newer SDK release and the fork matrix proves
15
+ * byte-for-byte behavior at that dependency version.
16
+ */
17
+ export declare function buildWalletMinimalTapOpenPosition(options: TapOpenPositionOptions): MethodParameters;
@@ -0,0 +1,24 @@
1
+ import type { V4Route } from '@labs-solo/aegis-engine-sdk';
2
+ import type { Address, PublicClient } from 'viem';
3
+ import type { AegisEngineBorrowQuoteContext, AegisEngineToken } from '../types.js';
4
+ import type { AegisEngineTapSwapLeg } from './swapLeg.js';
5
+ export type AegisEngineTapRoute = {
6
+ /** One path, one hop — the pool the vault already borrows against. */
7
+ route: V4Route;
8
+ amountOutQuoted: bigint;
9
+ /** What `addSwapActionsToPlanner` will encode as `amountOutMinimum`. */
10
+ amountOutMinimum: bigint;
11
+ /** Block the quote was simulated at. */
12
+ blockNumber: bigint;
13
+ };
14
+ export type AegisEngineTapRouteInput = {
15
+ publicClient: PublicClient;
16
+ /** Registry-trusted Uniswap V4 Quoter. */
17
+ quoter: Address;
18
+ context: AegisEngineBorrowQuoteContext;
19
+ token0: AegisEngineToken;
20
+ token1: AegisEngineToken;
21
+ leg: AegisEngineTapSwapLeg;
22
+ slippageBps: number;
23
+ signal?: AbortSignal;
24
+ };
@@ -0,0 +1,136 @@
1
+ import type { AegisEngineTradeDirection } from '../types.js';
2
+ import { type AegisEngineTapRateBasis, type AegisEngineTapState } from './systemState.js';
3
+ import { type SolverMajors } from './units.js';
4
+ /**
5
+ * Legacy root preference retained for source compatibility. Spec-0168 makes
6
+ * selection deterministic: both values now resolve through the debt-minimizing
7
+ * frontier and ties always choose the lower-γ candidate.
8
+ *
9
+ * @deprecated The value is ignored.
10
+ */
11
+ export type AegisEngineTapRootPolicy = 'min-carry' | 'max-leverage';
12
+ /** Which side of the pair the collateral is denominated in. */
13
+ export type AegisEngineTapDepositAsset = 'token0' | 'token1';
14
+ export type AegisEngineTapSizingInput = {
15
+ state: AegisEngineTapState;
16
+ direction: AegisEngineTradeDirection;
17
+ depositAsset: AegisEngineTapDepositAsset;
18
+ /** Deposit in solver majors. */
19
+ depositAmount: SolverMajors;
20
+ /** Horizon the target LTV is derived from, in seconds. */
21
+ tlSeconds: number;
22
+ /** Relative price move to the target: P_T = P_pool · (1 + Δ_lev). Its sign is
23
+ * forced to match `direction`; zero has no target and is rejected. */
24
+ deltaLev: number;
25
+ /** Absolute ceiling on the opening LTV, independent of the horizon. */
26
+ tauBar: number;
27
+ /** When present, invert the band to this average leverage instead of taking
28
+ * the leverage-maximising candidate. */
29
+ leverageTarget?: number;
30
+ /** @deprecated Ignored; selection always uses the debt-minimizing frontier. */
31
+ rootPolicy?: AegisEngineTapRootPolicy;
32
+ };
33
+ export type AegisEngineTapCandidate = {
34
+ /** Exposure ratio the sweep evaluated. */
35
+ alpha: number;
36
+ /** Average leverage over the move to the target price; always positive. */
37
+ leverage: number;
38
+ /** Instantaneous leverage at entry. */
39
+ localLeverage: number;
40
+ /** Leverage as price runs away from entry. */
41
+ asymptoticLeverage: number;
42
+ /** Opening LTV. Identical across the band — δ is sized to hit τ. */
43
+ ltv: number;
44
+ /** Borrow principal δ (L majors). */
45
+ delta: SolverMajors;
46
+ /** Real debt γ = δ·M (L majors). The only quantity that separates the two
47
+ * roots at one leverage. */
48
+ gamma: SolverMajors;
49
+ /** Post-swap token0 balance (token0 majors). */
50
+ x: SolverMajors;
51
+ /** Post-swap token1 balance (token1 majors). */
52
+ y: SolverMajors;
53
+ /** Signed internal swap: x = x_b + q, y = y_b − P·q. Positive buys token0. */
54
+ q: SolverMajors;
55
+ /** Entry equity (token1 majors). Constant across the band and equal to the
56
+ * deposit — borrowing is value-neutral at the pool price. */
57
+ equity: SolverMajors;
58
+ /** Equity at the target price (token1 majors). */
59
+ equityAtTarget: SolverMajors;
60
+ /** Simple interest over `tlSeconds` at the sized rate (token1 majors). */
61
+ interestCost: SolverMajors;
62
+ /** Minimum of E(P) over ALL prices: E_min = ȳ − γ²/x̄ (token1 majors).
63
+ * An equity floor, NOT a liquidation level — equity never reaches zero. */
64
+ equityMin: SolverMajors;
65
+ /** E_min / E_0. */
66
+ equityMinRatio: number;
67
+ cappedByDelta: boolean;
68
+ };
69
+ export type AegisEngineTapSizingDiagnostics = {
70
+ /** Opening LTV the band was sized to. */
71
+ tau: number;
72
+ /** Which of the three inputs set τ. */
73
+ tauBinding: 'theta-margin' | 'tau-bar' | 'horizon';
74
+ /** Market OPEN cap θ_L. */
75
+ thetaL: number;
76
+ /** Liquidation threshold. The countdown's target — see
77
+ * {@link tapDaysToLiquidation}. */
78
+ thetaLiq: number;
79
+ /** Annual rate τ and the carry were priced at. */
80
+ rEffAnnual: number;
81
+ /** Where that rate came from. */
82
+ rateBasis: AegisEngineTapRateBasis;
83
+ entryPrice: number;
84
+ targetPrice: number;
85
+ /** δ ceiling from the utilisation cap (L majors). */
86
+ deltaCap: SolverMajors;
87
+ /** Deposit above which the cap starts binding; null when uncapped. */
88
+ maxEfficientDeposit: SolverMajors | null;
89
+ /** True when the cap moved the winner off the unconstrained optimum. */
90
+ isCapConstrained: boolean;
91
+ candidatesTotal: number;
92
+ candidatesSurviving: number;
93
+ };
94
+ export type AegisEngineTapInfeasibleReason =
95
+ /** Deposit, horizon, τ̄, or leverage target outside its domain. */
96
+ {
97
+ kind: 'invalid-input';
98
+ }
99
+ /** Δ_lev = 0. The solver rejects a target equal to entry. */
100
+ | {
101
+ kind: 'zero-price-move';
102
+ }
103
+ /** Δ_lev non-finite, or ≤ −100% on a short. */
104
+ | {
105
+ kind: 'price-move-out-of-range';
106
+ } | {
107
+ kind: 'invalid-market-state';
108
+ } | {
109
+ kind: 'no-borrow-capacity';
110
+ } | {
111
+ kind: 'deposit-above-max';
112
+ maxEfficientDeposit: SolverMajors;
113
+ } | {
114
+ kind: 'no-feasible-band';
115
+ }
116
+ /** @deprecated Valid leverage requests are clamped to `lMax`. */
117
+ | {
118
+ kind: 'leverage-above-max';
119
+ lMax: number;
120
+ }
121
+ /** @deprecated Valid leverage requests are clamped to `lMin`. */
122
+ | {
123
+ kind: 'leverage-below-min';
124
+ lMin: number;
125
+ };
126
+ export type AegisEngineTapSizingResult = {
127
+ /** Lowest average leverage on the openable debt-minimizing frontier. */
128
+ lMin: number | null;
129
+ /** Highest average leverage on that frontier in the requested direction. */
130
+ lMax: number | null;
131
+ chosen: AegisEngineTapCandidate | null;
132
+ candidates: readonly AegisEngineTapCandidate[];
133
+ /** Null only when the inputs never reached the solver. */
134
+ diagnostics: AegisEngineTapSizingDiagnostics | null;
135
+ infeasibleReason?: AegisEngineTapInfeasibleReason;
136
+ };
@@ -0,0 +1,32 @@
1
+ import type { AegisEngineTradeDirection } from '../types.js';
2
+ import type { AegisEngineTapCandidate } from './sizing.js';
3
+ import { type SolverMajors } from './units.js';
4
+ /** Floor-converts an amount in solver majors to token base units. */
5
+ export declare function tokenBaseUnits(value: SolverMajors, decimals: number): bigint;
6
+ export type AegisEngineTapSwapLeg = {
7
+ /** False when `q` is dust — the borrow already delivers the target mix. */
8
+ needed: boolean;
9
+ inputIsToken0: boolean;
10
+ /** Floor-rounded, and never above the idle the vault holds after the borrow. */
11
+ amountIn: bigint;
12
+ /** True when vault idle, not the solver, set `amountIn`. */
13
+ clampedByIdle: boolean;
14
+ };
15
+ export type AegisEngineTapSwapLegResult = {
16
+ ok: true;
17
+ leg: AegisEngineTapSwapLeg;
18
+ } | {
19
+ ok: false;
20
+ reason: 'swap-direction-mismatch' | 'insufficient-idle';
21
+ };
22
+ export type AegisEngineTapSwapLegInput = {
23
+ candidate: AegisEngineTapCandidate;
24
+ direction: AegisEngineTradeDirection;
25
+ /** Pool mid price, token1 per token0. The solver settles `q` at this price. */
26
+ entryPrice: number;
27
+ decimals0: number;
28
+ decimals1: number;
29
+ /** Vault idle after the collateral deposit and the borrow, in base units. */
30
+ idle0: bigint;
31
+ idle1: bigint;
32
+ };
@@ -0,0 +1,44 @@
1
+ import type { Address } from 'viem';
2
+ import type { AegisEngineVersion } from '../types.js';
3
+ /** Which rate the horizon, the carry, and the countdown were priced at. */
4
+ export type AegisEngineTapRateBasis = 'projected-post-borrow' | 'current-apr';
5
+ export type AegisEngineTapRate = {
6
+ aprPct: number;
7
+ basis: AegisEngineTapRateBasis;
8
+ };
9
+ /**
10
+ * The α-sweep's market state plus the two things the sweep does not model: the
11
+ * liquidator's threshold, and the inputs that reprice the market after our own
12
+ * borrow.
13
+ */
14
+ export type AegisEngineTapState = {
15
+ /** Pool price, token1 per token0. */
16
+ Ppool: number;
17
+ /** Idle liquidity S, in solver majors. */
18
+ SIdle: number;
19
+ /** Global real debt B_M, in solver majors. */
20
+ BM: number;
21
+ /** Borrow index M. */
22
+ M: number;
23
+ /** Utilisation cap Ū. */
24
+ Ucap: number;
25
+ /** The OPEN cap. Sizing may not cross it. */
26
+ thetaL: number;
27
+ /** The liquidator's threshold. The countdown runs to THIS, not to θ_L. */
28
+ thetaLiq: number;
29
+ /** Pre-borrow APR. The basis only when the oracle projection is refused. */
30
+ aprPct: number;
31
+ /** RESEARCH-0024 deletes β. Never expose it as a setting. */
32
+ betaTime: number;
33
+ /** What `estimatePostBorrowRate` needs to reprice this market. */
34
+ projection: {
35
+ equityLWad: bigint;
36
+ borrowedLWad: bigint;
37
+ fullUtilRate: bigint;
38
+ rateOracleAddress: Address;
39
+ chainId: number;
40
+ version: AegisEngineVersion;
41
+ /** κ, to carry γ from solver majors back into engine L-WAD. */
42
+ kappa: number;
43
+ };
44
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Tap sizing crosses three unit systems that are indistinguishable at the type
3
+ * level until one of them is off by κ or by WAD:
4
+ *
5
+ * - {@link EngineL} — WAD-scaled L-units exactly as the engine reports them
6
+ * (`equityLWad`, `borrowedLWad`).
7
+ * - {@link SolverMajors} — decimal-adjusted floats; the space the SDK's α-sweep
8
+ * works in (`δ`, `γ`, `x`, `y`, equities).
9
+ * - {@link RlUnits} — debt principal in the units `modifyDebt` accepts.
10
+ *
11
+ * κ = 10^((decimals0 + decimals1) / 2) is the only bridge between engine L and
12
+ * solver majors. It CANCELS in LTV — numerator γ·κ over denominator √(x̄·ȳ)·κ —
13
+ * which is exactly why a κ mistake stays invisible in the number a user reads.
14
+ * It does NOT cancel in the δ-cap comparison or in the principal handed to the
15
+ * engine: passing raw engine L to `deltaMaxByUtil` overstates borrow capacity by
16
+ * κ (10^18 on an 18/18 pair) and silently disables the utilisation cap.
17
+ */
18
+ declare const unitBrand: unique symbol;
19
+ type Unit<T, Name extends string> = T & {
20
+ readonly [unitBrand]: Name;
21
+ };
22
+ /** WAD-scaled L-units, as read from the engine. */
23
+ export type EngineL = Unit<bigint, 'engine-l-wad'>;
24
+ /** Decimal-adjusted floats — token and L amounts in the solver's own space. */
25
+ export type SolverMajors = Unit<number, 'solver-majors'>;
26
+ /** Debt principal in rL units — what `modifyDebt` takes. */
27
+ export type RlUnits = Unit<bigint, 'rl'>;
28
+ export declare function engineL(value: bigint): EngineL;
29
+ export declare function solverMajors(value: number): SolverMajors;
30
+ /** κ = 10^((d0+d1)/2). Non-integral for an odd decimal sum, hence a float. */
31
+ export declare function kappaForDecimals(decimals0: number, decimals1: number): number;
32
+ export declare function solverMajorsFromEngineL(value: EngineL, kappa: number): SolverMajors;
33
+ /**
34
+ * Rounds down: the engine is never asked for more principal than was sized.
35
+ * Past 2⁵³ — where every principal on an 18/18 pair lives — the product is
36
+ * already an integral float and `Math.floor` is a no-op, so the last digits are
37
+ * float noise that can sit ABOVE the sized δ. The shift drops one relative ulp,
38
+ * which is zero below 2⁵² and puts the result under the true product above it.
39
+ */
40
+ export declare function rlFromSolverMajors(value: SolverMajors, kappa: number): RlUnits;
41
+ export {};