@aegis-engine/core 0.7.0 → 0.8.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.
Files changed (74) hide show
  1. package/README.md +215 -7
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  3. package/dist/account.d.ts +11 -0
  4. package/dist/account.js +129 -0
  5. package/dist/actions/allowance.d.ts +94 -0
  6. package/dist/actions/directPoolSwap.d.ts +8 -1
  7. package/dist/actions/kyberSwap.d.ts +1 -0
  8. package/dist/actions/types.d.ts +2 -0
  9. package/dist/actions/wallet.d.ts +1 -0
  10. package/dist/aegis-core.js +9654 -205
  11. package/dist/backendAdapters.d.ts +3 -1
  12. package/dist/config/chains.d.ts +1 -0
  13. package/dist/config/constants.d.ts +4 -0
  14. package/dist/config/tokens.d.ts +2 -1
  15. package/dist/config/types.d.ts +8 -0
  16. package/dist/contract/backendClient.d.ts +3 -1
  17. package/dist/contract/generated/aegis-swap.d.ts +6337 -1377
  18. package/dist/contract/generated/market-data.d.ts +8286 -0
  19. package/dist/contract/index.d.ts +1 -0
  20. package/dist/contract/responseBudget.d.ts +9 -0
  21. package/dist/contract/schemas.d.ts +13 -3
  22. package/dist/engine/account/accounting.d.ts +24 -0
  23. package/dist/engine/account/accountingSchemas.d.ts +2056 -0
  24. package/dist/engine/account/activity.d.ts +42 -0
  25. package/dist/engine/account/activitySchemas.d.ts +327 -0
  26. package/dist/engine/account/amountSchemas.d.ts +9 -0
  27. package/dist/engine/account/catalogSchemas.d.ts +108 -0
  28. package/dist/engine/account/client.d.ts +14 -0
  29. package/dist/engine/account/history.d.ts +40 -0
  30. package/dist/engine/account/historySchemas.d.ts +251 -0
  31. package/dist/engine/account/management.d.ts +13 -0
  32. package/dist/engine/account/portfolioSchemas.d.ts +712 -0
  33. package/dist/engine/account/positionPerformance.d.ts +18 -0
  34. package/dist/engine/account/positionPerformanceSchemas.d.ts +101 -0
  35. package/dist/engine/account/positionPnl.d.ts +18 -0
  36. package/dist/engine/account/positionPnlSchemas.d.ts +149 -0
  37. package/dist/engine/account/transactionHistory.d.ts +50 -0
  38. package/dist/engine/account/transactionSchemas.d.ts +101 -0
  39. package/dist/engine/account/transactions.d.ts +26 -0
  40. package/dist/engine/account/transport.d.ts +31 -0
  41. package/dist/engine/account/types.d.ts +39 -0
  42. package/dist/engine/actions.d.ts +8 -3
  43. package/dist/engine/adaptiveFee.d.ts +14 -0
  44. package/dist/engine/balancedLending.d.ts +82 -0
  45. package/dist/engine/dataSource.d.ts +2 -0
  46. package/dist/engine/index.d.ts +19 -0
  47. package/dist/engine/marketAdapter.d.ts +3 -0
  48. package/dist/engine/marketSeries.d.ts +61 -0
  49. package/dist/engine/marketSeriesSchemas.d.ts +312 -0
  50. package/dist/engine/marketTrust.d.ts +26 -0
  51. package/dist/engine/openingEntry.d.ts +41 -0
  52. package/dist/engine/rateHistorySchemas.d.ts +88 -0
  53. package/dist/engine/reads.d.ts +1 -1
  54. package/dist/engine/registry.d.ts +1 -1
  55. package/dist/engine/restSchemas.d.ts +59 -1
  56. package/dist/engine/tradeExecutionSession.d.ts +155 -0
  57. package/dist/engine/types.d.ts +128 -14
  58. package/dist/engine/v4Quote.d.ts +5 -0
  59. package/dist/index.d.ts +11 -7
  60. package/dist/internal/guardedWalletTransaction.d.ts +31 -0
  61. package/dist/permit.d.ts +80 -7
  62. package/dist/quote/aggregatedSwapQuote.d.ts +5 -1
  63. package/dist/quote/kyberCalldata.d.ts +5 -1
  64. package/dist/{sdkRuntime-BE3ZMb5o.js → sdkRuntime-3aRt_g55.js} +3385 -2958
  65. package/dist/services/kyberSwap.d.ts +12 -0
  66. package/dist/swap/authorizePermit.d.ts +11 -9
  67. package/dist/swap/executeSwapTransaction.d.ts +5 -1
  68. package/dist/swap/receiptWait.d.ts +9 -0
  69. package/dist/swap/sendSwapTransaction.d.ts +7 -0
  70. package/dist/swap/trustedMarket.d.ts +25 -0
  71. package/dist/transactionHistory-1Zl2KCcV.js +5915 -0
  72. package/dist/wallet.d.ts +4 -0
  73. package/package.json +12 -5
  74. package/dist/index-DofKgro2.js +0 -11201
package/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Aegis Core
2
2
 
3
+ Direct paired lending is exposed by `quoteEngineBalancedDeposit` and
4
+ `executeEngineBalancedDeposit`, with a discriminated `AegisEngineLendIntent`.
5
+ The quote preserves both token limits, protected shares, funding, native reserve,
6
+ and frame evidence. Execution reuses the Engine approval and receipt flow.
7
+ See [the integration guide](../../docs/balanced-lending.md) for the required SDK
8
+ release dependency, reviewed-bound behavior and verification limits.
9
+
3
10
  React-free Swap and Engine operations for Aegis integrations.
4
11
 
5
12
  `@aegis-engine/core` is the operations layer behind the Aegis swap experience.
@@ -17,6 +24,25 @@ npm install @aegis-engine/core viem
17
24
  RPC setup. The protocol implementation used by Engine quotes is bundled into
18
25
  the published Core package; consumers do not need GitHub Packages credentials.
19
26
 
27
+ For account data without the execution layer, import from
28
+ `@aegis-engine/core/account`. This entry includes portfolio/activity reads,
29
+ `fetchEnginePositionHistory`, `fetchEngineHistoryPositions` (including closed
30
+ positions), and `createEngineTransactionHistory` for scoped metadata and
31
+ receipt-only recovery. It imports no React, Widget CSS or execution SDK chunk.
32
+ `fetchEnginePositionAccounting` adds immutable raw accounting pages, proven
33
+ ownership when available, and separate financial-completeness flags. Continue
34
+ with `nextCursor`; do not treat raw event availability as executed prices or
35
+ wallet PnL. The widget hooks entry exports `useEnginePositionAccounting` for
36
+ explicit reads and refreshes without background polling.
37
+ History retains missing observations and unknown valuations; page totals must
38
+ not be added together. The endpoints require a backend that serves the pinned
39
+ account/history contract.
40
+
41
+ Installed-package checks use the configured Node runtime, strict TypeScript 5.8 NodeNext and
42
+ Bundler, and TypeScript 5.6 Bundler. Current viem types require TypeScript 5.8+
43
+ for NodeNext. See the repository's `docs/package-data-contracts.md` for the
44
+ exact compatibility matrix, storage and coverage semantics, and release gates.
45
+
20
46
  ## What It Supports
21
47
 
22
48
  - Direct Aegis pool quotes and execution against host-supplied Uniswap v4 pool
@@ -89,6 +115,11 @@ reconstruct Long/Short identity; position rows alone are ordinary borrow-vault
89
115
  facts and are not enough to classify a trade. Engine market history remains a
90
116
  REST capability.
91
117
 
118
+ `readEngineVaultActivity` is a separate best-effort helper that queries the
119
+ public Engine subgraph. A browser caller sends the chain and vault identifier
120
+ to that indexer. Do not call it for a fully offline integration; provide the
121
+ static `vaultActivity` fixture instead.
122
+
92
123
  The REST service supplies facts and provenance. Core owns live RPC reads,
93
124
  collateral/debt math, quote freshness, recipe construction, simulation,
94
125
  approval, and send. `positions.freshness` is indexed provenance:
@@ -178,6 +209,12 @@ live leverage, exact opening LTV after the swap minimum, interest carry, risk
178
209
  thresholds, gross return at the configured target, actionable solver limits,
179
210
  and atomic router calldata when all execution gates pass.
180
211
 
212
+ Every Lend or Trade quote with an internal swap requires
213
+ `maxPriceImpactBps`. Core derives the impact from that same block-pinned quote
214
+ and returns a typed, non-executable `price-impact-limit` or
215
+ `price-impact-unavailable` result when it cannot satisfy the host policy.
216
+ This is an SDK execution gate. It is not a Router-level pool-price invariant.
217
+
181
218
  Successful and leverage-bound quotes expose `limits.minLeverage` and
182
219
  `limits.maxLeverage`. Treat these as live, request-specific bounds rather than
183
220
  a protocol-wide constant.
@@ -203,16 +240,16 @@ const quote = await quoteEngineTradeOpen({
203
240
  leverage: 1.5,
204
241
  horizonSeconds: 30 * 24 * 60 * 60,
205
242
  priceMove: 0.2,
206
- slippageBps: 100
243
+ slippageBps: 100,
244
+ maxPriceImpactBps: 500
207
245
  })
208
246
  ```
209
247
 
210
248
  Treat `feasible` and `executable` separately. A feasible quote can still need
211
- the trusted router's vault-operator grant or Permit2 authorization. After an
212
- authorization transaction, request the submit quote with
213
- `forceExecutionEvidenceRefresh: true`; then pass its fresh `tx` and `expiresAt`
214
- to `sendEngineTransaction`. The prebuilt `AegisLeverageWidget` performs this
215
- sequence for frontend integrations.
249
+ the trusted router's vault-operator grant or Permit2 authorization. The
250
+ low-level quote, authorization, and send functions remain available as
251
+ primitives. For a reviewed Long/Short flow, prefer the execution session below
252
+ so every integration uses the same re-planning and receipt-recovery rules.
216
253
 
217
254
  Use `readEngineAuthorizationPlan` to present the connected account's current
218
255
  wallet sequence before submission:
@@ -232,7 +269,9 @@ const plan = await readEngineAuthorizationPlan({
232
269
  ```
233
270
 
234
271
  `missingPermissionCount` excludes the final open and any zero-first reset.
235
- `walletPromptCount` includes every required sequential transaction.
272
+ `walletPromptCount` includes every required sequential wallet action. In
273
+ Permit2 signature mode, the Permit2 router step can be a typed-data signature
274
+ or a fallback spending-cap transaction.
236
275
  `walletChainSwitchRequired` reports the network switch separately and is null
237
276
  until the wallet chain is known. The plan is a read-only presentation snapshot, not authorization
238
277
  evidence. Submission must still re-read permissions and obtain a fresh
@@ -240,6 +279,55 @@ executable quote. Exact ERC-20 and Permit2 limits are consumed by the successful
240
279
  opening transfer; maximum limits and the VaultRegistry operator grant remain
241
280
  active until revoked.
242
281
 
282
+ ### Reviewed trade execution
283
+
284
+ `createEngineTradeOpenExecutionSession` is the React-free execution boundary
285
+ for partner UIs. Give it the wallet, the exact intent the user reviewed, and
286
+ the matching plan and quote. Core then re-reads permissions before every wallet
287
+ request, re-quotes from a fresh block-pinned frame after permissions settle,
288
+ and stops for review if authority or execution facts become less favorable.
289
+
290
+ ```ts
291
+ import { createEngineTradeOpenExecutionSession } from '@aegis-engine/core'
292
+
293
+ const session = createEngineTradeOpenExecutionSession({
294
+ wallet,
295
+ publicClient,
296
+ activeChain,
297
+ intent: {
298
+ owner: wallet.account,
299
+ market,
300
+ direction: 'long',
301
+ token: market.token0,
302
+ amount: 1_000_000n,
303
+ leverage: 1.5,
304
+ horizonSeconds: 30 * 24 * 60 * 60,
305
+ priceMove: 0.2,
306
+ slippageBps: 100,
307
+ maxPriceImpactBps: 500,
308
+ approvalMode: 'exact'
309
+ },
310
+ reviewed: { plan, quote },
311
+ onChange: renderExecution
312
+ })
313
+
314
+ await session.dispatch({ kind: 'continue' })
315
+ ```
316
+
317
+ Read `session.getSnapshot().next` before each user action:
318
+
319
+ - `continue`: continue the reviewed flow.
320
+ - `accept-review`: show `snapshot.review`, then dispatch the exact `revision`
321
+ after the user accepts the updated plan or quote.
322
+ - `check-receipt`: check the retained transaction hash without broadcasting.
323
+ - `cancel`: stop preparation before a transaction hash exists.
324
+ - `none`: no command is currently safe or necessary.
325
+
326
+ A wallet rejection stops before chain confirmation. A receipt timeout retains
327
+ the submitted hash and permits only `check-receipt`; it never enables a blind
328
+ retry. If a prerequisite confirms late, the session returns
329
+ `resume-required`, so the next wallet request still needs an explicit Continue.
330
+
243
331
  ## Historical token prices
244
332
 
245
333
  Historical prices are intentionally separate from Engine market and
@@ -583,6 +671,126 @@ pnpm build
583
671
  pnpm pack:check
584
672
  ```
585
673
 
674
+ ## Engine account portfolio and activity
675
+
676
+ `fetchEngineAccountPortfolio({ source, account, chainIds, signal })` reads one complete, bounded account snapshot from the versioned portfolio API. The returned positions, totals, prices and per-chain frames belong to the same snapshot. A failed or expired page rejects the read instead of mixing snapshots. Supported chain IDs are 1, 130, 8453 and 4663; pass the distinct host-selected set.
677
+
678
+ Metrics keep `usd: null`, a `knownUsd` subtotal and reasons when coverage is incomplete. Gross assets include supplied value; adding supply again would double count it. Debt and net equity remain separate. NFT principal, fees, unknown prices and unavailable chains retain their coverage reasons. `performance` explicitly reports unavailable cash-flow and cost-basis evidence.
679
+
680
+ `fetchEngineAccountActivity` reads one continuation page, and `groupEngineAccountActivity` joins events by chain and transaction while preserving vault-balance changes separately from lending settlement. `formatEngineAccountTokenAmount` formats raw bigint strings using verified decimals, without a Number round-trip or an assumed 18-decimal fallback. Indexed events are not receipt finality.
681
+
682
+ `fetchEngineTransactionStatus` consumes the backend receipt/indexer/portfolio acknowledgement. A `ready` result must include a checked receipt, the complete event acknowledgement, and an unexpired portfolio at or beyond its block. This is checked-at-read evidence, not a finalized transaction or permission to submit it again.
683
+
684
+ `resolveEngineAccountPositionTarget` maps a portfolio identity to the existing position manager only with matching account, chain, pool, Engine, registry and recent successful live hydration. The target keeps the legacy live position ID; the aggregate API ID is never substituted into an unrelated action context.
685
+
686
+ Safe transaction-history helpers expose versioned, wallet/chain-scoped display metadata and hashes. They reject extra executable fields and retain pending identities when completed history is pruned. They do not persist quotes, signatures, permits or transaction calldata.
687
+
688
+ `onTransactionObservation` on Engine and swap executors reports the submitted hash, replacement relationship and receipt outcome without executable data. `executionChanged` distinguishes a price-only speed-up from a replacement that changed the call; receipt recovery retains that evidence through timeouts. Approval helpers report and return the hash that actually mines. Transaction-history merges retain replacement ancestry across out-of-order observations and keep authorization records distinct from position actions.
689
+
690
+ `deriveEngineTradePositionStrategy` identifies a Tap opening from indexed Engine
691
+ activity, but leaves `entryPrice: null` and `entryPriceBasis: 'unavailable'`.
692
+ Its optional `referencePrice` is the debt-action token ratio, which excludes the
693
+ actual swap's price impact and fees. It must not become entry price or cost basis.
694
+ The widget accepts entry-based display only with an explicit
695
+ `entryPriceBasis: 'receipt-reconciled'`. Legacy host records without that basis
696
+ remain unverified. Receipt ingestion is a separate consumer integration; this
697
+ change does not claim it is already available through the accounting endpoint.
698
+
699
+ ### Market series
700
+
701
+ `fetchEngineMarketCandles`, `fetchEngineMarketReferenceHistory`, and
702
+ `fetchEngineRateHistory` read public market data with a shared, bounded REST request.
703
+ Validated responses are cached for 30 seconds with at most 16 entries, keyed by
704
+ endpoint, request headers, timeout, market, series and window. A missing endpoint
705
+ backs off for 60 seconds; 429/503 responses back off for at least 30 seconds and
706
+ honor a longer `Retry-After`. `AegisEngineMarketDataReadError.retryAfterSeconds`
707
+ exposes the retry delay. Reads never start automatic polling or switch sources.
708
+
709
+ Each consumer receives its own snapshot and can abort its wait independently;
710
+ the shared transport retains its response-size limit and deadline. Use
711
+ `clearEngineMarketSeriesCache()` for an explicit host reset. Cached history is
712
+ display evidence, never a fresh quote or an execution prerequisite.
713
+
714
+ ```ts
715
+ import {
716
+ fetchEngineMarketCandles,
717
+ fetchEngineMarketReferenceHistory,
718
+ fetchEngineRateHistory,
719
+ splitEngineMarketCandleSegments
720
+ } from '@aegis-engine/core'
721
+
722
+ const input = { source: { kind: 'rest' as const, baseUrl }, marketId, signal }
723
+ const candles = await fetchEngineMarketCandles({
724
+ ...input,
725
+ window: '1d',
726
+ expectedAssets: { baseAsset: market.token0, quoteAsset: market.token1 }
727
+ })
728
+ const segments = splitEngineMarketCandleSegments(candles)
729
+ // Plot each segment on the same requestedFrom/requestedTo time axis.
730
+ const reference = await fetchEngineMarketReferenceHistory({ ...input, window: '7d' })
731
+ const rates = await fetchEngineRateHistory({ ...input, window: '30d' })
732
+ ```
733
+
734
+ Pool history provides OHLC and distinguishes exact five-minute swaps from
735
+ upstream hourly/daily pool aggregates. Aggregate `txCount` is not a swap count.
736
+ `expectedAssets` checks selected token addresses and decimals, including cache
737
+ hits. `splitEngineMarketCandleSegments` retains valid candles on both sides of
738
+ explicit gaps. It does not fill quiet buckets, synthesize one-second rows, or
739
+ turn a current pool-state reference into historical OHLC.
740
+ The explicitly requested reference is a line of token USD close ratios, with
741
+ bucket-only synchronization and unknown historical venue independence. It is
742
+ neither pair OHLC nor independent fair value. Neither series is execution price,
743
+ cost basis, or a transaction quote. Reference history has no one-day window.
744
+
745
+ Rate history exposes simple lending APR estimates and borrow rates. Coverage and
746
+ canonical provenance are separate: a complete legacy series can be `ready` while
747
+ its observations remain `legacy-unpinned`. Missing buckets and missing rate
748
+ values remain explicit. Observation checks do not claim finality or realized PnL.
749
+
750
+ The market-data OpenAPI snapshot has its own exact backend revision because its
751
+ PR is independent of the position-accounting stack. Both snapshots are checked
752
+ by `openapi:parity` and the live release gate. Generated types and runtime guards
753
+ are local source contracts; endpoint deployment and new writer observations
754
+ still require separate qualification.
755
+
756
+ ### Completed tap trade token PnL
757
+
758
+ `fetchEnginePositionPnl` is available through `@aegis-engine/core/account`.
759
+ Pass the `snapshotId` from `fetchEnginePositionAccounting` for the same account,
760
+ chain, pool and vault. It makes one bounded API request; it does not refresh the
761
+ accounting snapshot, read prices or poll.
762
+
763
+ ```ts
764
+ import { fetchEnginePositionPnl } from '@aegis-engine/core/account'
765
+
766
+ const pnl = await fetchEnginePositionPnl({
767
+ source: { kind: 'rest', baseUrl: backendUrl },
768
+ account, chainId, poolId, vaultId,
769
+ snapshotId: accounting.snapshotId,
770
+ signal
771
+ })
772
+ if (pnl.status === 'token-pnl') {
773
+ // Each currency keeps its own raw units. Do not sum these token amounts.
774
+ renderTokenPnl(pnl.key.currency0, pnl.totals.net.amount0Raw)
775
+ renderTokenPnl(pnl.key.currency1, pnl.totals.net.amount1Raw)
776
+ }
777
+ ```
778
+
779
+ The backend supports one-owner, NFT-free ERC20 tap trades from opening through a
780
+ supported full vault close. Other histories return an explicit unavailable
781
+ reason. Paid, received and net amounts are validated independently. Trading and
782
+ borrowing charges are embedded in those flows; execution gas is a separate
783
+ native-wei amount. Historical USD PnL, approval costs, L2/data fees and total
784
+ economic PnL remain unavailable. Label the result as token PnL; a token gain and
785
+ a loss in another currency are not a single profit percentage.
786
+
787
+ Responses retain capture-time provenance and expiry, not a finality guarantee.
788
+ An expired snapshot yields 410 and requires an explicit accounting refresh.
789
+ The API must publish/pin the settlement SDK and deploy the additive PnL endpoint
790
+ before this read is available. The matching maintained fixture in
791
+ `scripts/fixtures/package-consumers/position-pnl-v1.json` was produced by the
792
+ SDK receipt reconciler and API adapter, then accepted unchanged by this reader.
793
+
586
794
  ## Borrow collateral sizing
587
795
 
588
796
  `quoteEngineBorrowCapacity` reports `collateralFloor` as a settled result:
@@ -2,7 +2,7 @@
2
2
 
3
3
  The lazy Engine implementation includes code from these MIT-licensed works:
4
4
 
5
- - `@labs-solo/aegis-engine-sdk` 0.33.0 — Copyright (c) 2026 Solo Labs
5
+ - `@labs-solo/aegis-engine-sdk` 0.40.0 — Copyright (c) 2026 Solo Labs
6
6
  - `@uniswap/sdk-core` 6.1.1 and 7.18.0 — Copyright (c) 2021 Uniswap Labs
7
7
  - `@uniswap/v3-sdk` 3.27.0 — Copyright (c) 2021 Uniswap Labs
8
8
  - `tiny-invariant` 1.3.3 — Copyright (c) 2019 Alexander Reardon
@@ -0,0 +1,11 @@
1
+ /** Account reads and transaction metadata without wallet execution or React. */
2
+ export * from './engine/account/types.js';
3
+ export * from './engine/account/client.js';
4
+ export * from './engine/account/history.js';
5
+ export * from './engine/account/accounting.js';
6
+ export * from './engine/account/positionPnl.js';
7
+ export * from './engine/account/positionPerformance.js';
8
+ export * from './engine/account/activity.js';
9
+ export * from './engine/account/management.js';
10
+ export * from './engine/account/transactions.js';
11
+ export * from './engine/account/transactionHistory.js';
@@ -0,0 +1,129 @@
1
+ import { w as u, o as b, n as A, s as I, l as P, E as g, A as h, r as f, a as x, i as c, b as E, c as S, d as C, e as _, P as T, f as D } from "./transactionHistory-1Zl2KCcV.js";
2
+ import { g as M, h as j, j as J, k as O, m as U, p as G, q as Z, t as Q, u as V, v as W, x as X, y as Y, z as ee, B as ae, C as oe, D as se, F as ne, G as te, H as re } from "./transactionHistory-1Zl2KCcV.js";
3
+ import { keccak256 as k, encodeAbiParameters as y } from "viem";
4
+ const H = b({ version: P(1), snapshotId: I().uuid(), page: A().int().min(1).max(95) }).strict();
5
+ function v(e) {
6
+ if (!/^[A-Za-z0-9_-]{1,256}$/.test(e)) throw new Error("invalid-cursor");
7
+ return H.parse(JSON.parse(atob(e.replace(/-/g, "+").replace(/_/g, "/"))));
8
+ }
9
+ function L(e) {
10
+ return u({ ...e, chainIds: [e.chainId] }, async (r) => {
11
+ let o;
12
+ try {
13
+ if (!/^0x[0-9a-fA-F]{64}$/.test(e.poolId) || !["lend_shares", "borrow_vault"].includes(e.kind) || (e.kind === "borrow_vault" ? !g.safeParse(e.vaultId).success : e.vaultId !== void 0)) throw new Error("invalid-query");
14
+ e.cursor !== void 0 && (o = v(e.cursor));
15
+ } catch {
16
+ throw new h("invalid-query", 400);
17
+ }
18
+ const a = await f(r, "positions/accounting", {
19
+ chainId: String(e.chainId),
20
+ poolId: e.poolId.toLowerCase(),
21
+ kind: e.kind,
22
+ ...e.kind === "borrow_vault" ? { vaultId: e.vaultId } : {},
23
+ ...e.cursor ? { cursor: e.cursor } : {}
24
+ }, x, { omitChainIds: !0, responseLimit: 256 * 1024 });
25
+ if (Date.parse(a.expiresAt) <= Date.now()) throw new h("snapshot-expired", 410);
26
+ const n = a.position, l = n.key;
27
+ if ((n.account !== r.query.account || n.chainId !== e.chainId || n.poolId !== e.poolId.toLowerCase() || n.kind !== e.kind || n.vaultId !== (e.vaultId ?? null) || n.scope !== (e.kind === "lend_shares" ? "account-lending" : "vault-lifetime") || a.page.snapshotId !== a.snapshotId || a.page.page !== ((o == null ? void 0 : o.page) ?? 0) || o && o.snapshotId !== a.snapshotId || a.page.page >= a.pageCount || a.recordCount > 0 && a.page.records.length === 0 || a.page.records.length > a.recordCount || a.pageCount === 1 && a.page.records.length !== a.recordCount || Date.parse(a.expiresAt) - Date.parse(a.createdAt) !== 6e5 || l.currency0 >= l.currency1 || k(y(
28
+ [{ type: "address" }, { type: "address" }, { type: "uint24" }, { type: "int24" }, { type: "address" }],
29
+ [l.currency0, l.currency1, l.fee, l.tickSpacing, l.hooks]
30
+ )) !== n.poolId) && c(), a.page.page + 1 < a.pageCount != (a.nextCursor !== null) && c(), a.nextCursor !== null)
31
+ try {
32
+ const t = v(a.nextCursor);
33
+ (t.snapshotId !== a.snapshotId || t.page !== a.page.page + 1) && c();
34
+ } catch {
35
+ c();
36
+ }
37
+ const m = /* @__PURE__ */ new Map();
38
+ let i;
39
+ for (const t of a.page.records) {
40
+ const s = t.event, p = m.get(s.transactionHash);
41
+ if ((s.blockNumber > a.frame.blockNumber || s.blockTimestamp > a.frame.blockTimestamp || i && (s.blockNumber < i.blockNumber || s.blockTimestamp < i.blockTimestamp || s.blockNumber === i.blockNumber && (s.logIndex <= i.logIndex || s.blockTimestamp !== i.blockTimestamp || s.transactionIndex < i.transactionIndex || s.transactionIndex === i.transactionIndex != (s.transactionHash === i.transactionHash))) || p && (p.blockNumber !== s.blockNumber || p.blockTimestamp !== s.blockTimestamp || p.transactionIndex !== s.transactionIndex)) && c(), t.type === "ownership")
42
+ (e.kind !== "borrow_vault" || t.event.vaultId !== e.vaultId || t.event.registry !== n.registry || s.id !== `vault-transfer:${n.chainId}:${n.registry}:${s.transactionHash}:${s.logIndex}` || s.blockNumber === a.frame.blockNumber && t.event.blockHash !== a.frame.blockHash) && c();
43
+ else {
44
+ const d = t.event, w = ["liquidity_modified", "share_transfer", "protocol_fee_minted"].includes(d.kind);
45
+ (e.kind === "lend_shares" !== w || d.kind === "liquidity_modified" && d.details.account !== n.account || d.kind === "protocol_fee_minted" && d.details.recipient !== n.account || d.kind === "share_transfer" && d.details.from !== n.account && d.details.to !== n.account) && c(), (t.event.id !== `engine-event:${n.chainId}:${n.engine}:${s.transactionHash}:${s.logIndex}` || t.event.sourceId !== `${s.transactionHash}-${s.logIndex}` || e.kind === "lend_shares" && t.ownershipAtEvent.status !== "not-applicable" || e.kind === "borrow_vault" && (a.ownership.status !== "complete" ? t.ownershipAtEvent.status !== "unavailable" : !["known", "inactive"].includes(t.ownershipAtEvent.status))) && c();
46
+ }
47
+ m.set(s.transactionHash, s), i = s;
48
+ }
49
+ return a;
50
+ });
51
+ }
52
+ const R = _({ ttlMs: 0, maxEntries: 64 });
53
+ async function F(e) {
54
+ var n;
55
+ (n = e.signal) == null || n.throwIfAborted();
56
+ const r = { ...e.source, headers: { ...e.source.headers } }, o = JSON.stringify([
57
+ E(r.baseUrl),
58
+ S(r.headers),
59
+ r.timeoutMs,
60
+ e.account,
61
+ e.chainId,
62
+ e.poolId,
63
+ e.vaultId,
64
+ e.snapshotId
65
+ ]), a = R.read(o, () => $({ ...e, source: r, signal: void 0 }));
66
+ return structuredClone(await C(a, e.signal, "Position PnL read aborted."));
67
+ }
68
+ function $(e) {
69
+ return u({ ...e, chainIds: [e.chainId] }, async (r) => {
70
+ if (!/^0x[0-9a-fA-F]{64}$/.test(e.poolId) || !g.safeParse(e.vaultId).success || !I().uuid().safeParse(e.snapshotId).success) throw new h("invalid-query", 400);
71
+ const o = await f(r, "positions/pnl", {
72
+ chainId: String(e.chainId),
73
+ poolId: e.poolId.toLowerCase(),
74
+ kind: "borrow_vault",
75
+ vaultId: e.vaultId,
76
+ snapshotId: e.snapshotId
77
+ }, T, { omitChainIds: !0, responseLimit: 32 * 1024 });
78
+ if (Date.parse(o.expiresAt) <= Date.now()) throw new h("snapshot-expired", 410);
79
+ if ((o.account !== r.query.account || o.chainId !== e.chainId || o.poolId !== e.poolId.toLowerCase() || o.vaultId !== e.vaultId || o.snapshotId !== e.snapshotId || Date.parse(o.capturedAt) > Date.now() + 6e4 || Date.parse(o.expiresAt) - Date.parse(o.capturedAt) > 6e5) && c(), o.status === "token-pnl") {
80
+ const a = o.key;
81
+ k(y(
82
+ [{ type: "address" }, { type: "address" }, { type: "uint24" }, { type: "int24" }, { type: "address" }],
83
+ [a.currency0, a.currency1, a.fee, a.tickSpacing, a.hooks]
84
+ )) !== o.poolId && c();
85
+ }
86
+ return o;
87
+ });
88
+ }
89
+ function z(e) {
90
+ return u({ ...e, chainIds: [e.chainId] }, async (r) => {
91
+ if (!/^0x[0-9a-fA-F]{64}$/.test(e.poolId) || !g.safeParse(e.vaultId).success || !I().uuid().safeParse(e.snapshotId).success || e.portfolioSnapshotId !== void 0 && !I().uuid().safeParse(e.portfolioSnapshotId).success)
92
+ throw new h("invalid-query", 400);
93
+ const o = await f(r, "positions/performance", {
94
+ chainId: String(e.chainId),
95
+ poolId: e.poolId.toLowerCase(),
96
+ kind: "borrow_vault",
97
+ vaultId: e.vaultId,
98
+ snapshotId: e.snapshotId,
99
+ ...e.portfolioSnapshotId ? { portfolioSnapshotId: e.portfolioSnapshotId } : {}
100
+ }, D, { omitChainIds: !0, responseLimit: 32 * 1024 });
101
+ if (Date.parse(o.expiresAt) <= Date.now()) throw new h("snapshot-expired", 410);
102
+ return (o.account !== r.query.account || o.chainId !== e.chainId || o.poolId !== e.poolId.toLowerCase() || o.vaultId !== e.vaultId || o.snapshotId !== e.snapshotId || o.portfolioSnapshotId !== (e.portfolioSnapshotId ?? null) || Date.parse(o.capturedAt) > Date.now() + 6e4 || Date.parse(o.expiresAt) - Date.parse(o.capturedAt) > 6e5) && c(), o;
103
+ });
104
+ }
105
+ export {
106
+ h as AegisEngineAccountReadError,
107
+ M as createEngineTransactionHistory,
108
+ j as engineAccountPositionKey,
109
+ J as engineAccountTransactionKey,
110
+ O as engineHistoryCatalogResponseSchema,
111
+ U as enginePortfolioPriceFor,
112
+ G as enginePositionHistoryResponseSchema,
113
+ Z as engineTransactionStorageKey,
114
+ Q as fetchEngineAccountActivity,
115
+ V as fetchEngineAccountPortfolio,
116
+ W as fetchEngineHistoryPositions,
117
+ L as fetchEnginePositionAccounting,
118
+ X as fetchEnginePositionHistory,
119
+ z as fetchEnginePositionPerformance,
120
+ F as fetchEnginePositionPnl,
121
+ Y as fetchEngineTransactionStatus,
122
+ ee as formatEngineAccountTokenAmount,
123
+ ae as groupEngineAccountActivity,
124
+ oe as groupEnginePortfolioPositions,
125
+ se as mergeEngineTransactionRecord,
126
+ ne as parseEngineTransactionRecords,
127
+ te as resolveEngineAccountPositionTarget,
128
+ re as serializeEngineTransactionRecords
129
+ };
@@ -1,3 +1,14 @@
1
+ import type { Hex } from 'viem';
2
+ import type { AegisSwapApprovalMode } from '../swap/types.js';
3
+ import type { AegisSwapToken } from '../config/index.js';
4
+ import type { AegisSwapActionCallbacks, AegisSwapApprovalRequest } from './types.js';
5
+ /**
6
+ * Whether replacing this token's non-zero allowance needs an approve(0)
7
+ * transaction first. The explicit token fact is the generic extension point;
8
+ * Ethereum USDT is recognized by address so a host cannot accidentally lose
9
+ * the well-known compatibility rule when it constructs its own token object.
10
+ */
11
+ export declare function requiresErc20ApprovalReset(token: Pick<AegisSwapToken, 'chainId' | 'address' | 'requiresApprovalReset'>): boolean;
1
12
  /**
2
13
  * Polls an ERC-20 allowance read until it covers `minimum`, then asserts it did.
3
14
  * Shared by the direct-pool and KyberSwap approval flows after they submit an
@@ -5,3 +16,86 @@
5
16
  * the wallet approved a smaller amount, so the swap must not proceed.
6
17
  */
7
18
  export declare function confirmAllowanceReached(read: () => Promise<bigint>, minimum: bigint): Promise<bigint>;
19
+ /**
20
+ * Sizes the ERC-20 grant a swap will request. Exported because a widget
21
+ * predicting the prompt before any executor exists calls the same function
22
+ * `ensureErc20Approval` writes from, so the predicted figure and the signed one
23
+ * cannot drift apart.
24
+ */
25
+ export declare function erc20ApprovalRequest(amount: bigint, approvalMode: AegisSwapApprovalMode, decimals: number): AegisSwapApprovalRequest;
26
+ export type Erc20AllowanceGrantStep = 'reset' | 'grant';
27
+ export type Erc20AllowanceGrantResolution = {
28
+ requiredAllowance: bigint;
29
+ satisfied: boolean;
30
+ approvalRequired: boolean;
31
+ resetRequired: boolean;
32
+ planned: number;
33
+ /** Whether a review plan should render this grant at all. */
34
+ visible: boolean;
35
+ };
36
+ /**
37
+ * Resolves one ERC-20 allowance decision for both review planning and writes.
38
+ * Exact zero is a glance: it reports an existing grant but never invents a
39
+ * zero-value approval. Max mode always asks for effectively unlimited
40
+ * authority, even when a smaller standing allowance covers today's spend.
41
+ */
42
+ export declare function resolveErc20AllowanceGrant(args: {
43
+ currentAllowance: bigint;
44
+ amount: bigint;
45
+ approvalMode: AegisSwapApprovalMode;
46
+ requiresReset?: boolean;
47
+ replaceAllowance?: boolean;
48
+ }): Erc20AllowanceGrantResolution;
49
+ type Erc20AllowanceWriteCallbacks = {
50
+ onWalletRequest?: () => void;
51
+ onHash?: (hash: Hex) => void;
52
+ };
53
+ /**
54
+ * Executes the decision above. Protocol-specific writers provide the spender;
55
+ * Engine can wrap each step with its lifecycle events and checkpoint without
56
+ * duplicating allowance sizing, reset ordering, or post-receipt proof.
57
+ */
58
+ export declare function executeErc20AllowanceGrant(args: {
59
+ read: () => Promise<bigint>;
60
+ write: (step: Erc20AllowanceGrantStep, amount: bigint, callbacks?: Erc20AllowanceWriteCallbacks) => Promise<Hex>;
61
+ amount: bigint;
62
+ decimals: number;
63
+ approvalMode: AegisSwapApprovalMode;
64
+ requiresReset?: boolean;
65
+ replaceAllowance?: boolean;
66
+ knownAllowance?: bigint;
67
+ executeStep?: (step: Erc20AllowanceGrantStep, run: (callbacks?: Erc20AllowanceWriteCallbacks) => Promise<Hex>) => Promise<Hex>;
68
+ afterStep?: (step: Erc20AllowanceGrantStep, hash: Hex) => Promise<void>;
69
+ confirm?: typeof confirmAllowanceReached;
70
+ onStatus?: AegisSwapActionCallbacks['onStatus'];
71
+ onApprovalProgress?: AegisSwapActionCallbacks['onApprovalProgress'];
72
+ }): Promise<{
73
+ approvalHashes: Hex[];
74
+ allowance: bigint;
75
+ }>;
76
+ /**
77
+ * Raises an ERC-20 allowance to what a swap needs: prompt plan, USDT-style
78
+ * zero-reset, the sized approval, and confirmation. The direct-pool and
79
+ * KyberSwap executors differ only in `write` — which spender they approve, and
80
+ * with which writer.
81
+ */
82
+ export declare function ensureErc20Approval(args: {
83
+ read: () => Promise<bigint>;
84
+ /** Submits the approval for exactly `amount` and resolves once mined. */
85
+ write: (amount: bigint, callbacks?: Erc20AllowanceWriteCallbacks) => Promise<Hex>;
86
+ amount: bigint;
87
+ /** Decimals of the approved token, carried into the reported request. */
88
+ decimals: number;
89
+ approvalMode: AegisSwapApprovalMode;
90
+ /** Authoritative token compatibility fact; never infer this from allowance. */
91
+ requiresReset?: boolean;
92
+ replaceAllowance?: boolean;
93
+ /** Allowance the caller already read for this (token, owner, spender) tuple. */
94
+ knownAllowance?: bigint;
95
+ onStatus?: AegisSwapActionCallbacks['onStatus'];
96
+ onApprovalProgress?: AegisSwapActionCallbacks['onApprovalProgress'];
97
+ }): Promise<{
98
+ approvalHashes: Hex[];
99
+ allowance: bigint;
100
+ }>;
101
+ export {};
@@ -27,10 +27,17 @@ export declare function approveDirectPoolSwapInput(args: {
27
27
  wallet: WalletSession;
28
28
  publicClient: PublicClient;
29
29
  activeChain: AegisSwapChainConfig;
30
+ market: AegisSwapMarket;
30
31
  token: AegisSwapToken;
31
- permit2: AegisSwapMarket['permit2'];
32
32
  amount: bigint;
33
33
  approvalMode?: AegisSwapApprovalMode;
34
+ /**
35
+ * ERC-20 -> Permit2 allowance the caller already read for this token and
36
+ * owner. executeDirectPoolSwap starts that read alongside its re-quote;
37
+ * passing it here saves a round trip right before the wallet prompt.
38
+ */
39
+ knownAllowance?: bigint;
40
+ signal?: AbortSignal;
34
41
  onStatus?: AegisSwapActionCallbacks['onStatus'];
35
42
  onApprovalProgress?: AegisSwapActionCallbacks['onApprovalProgress'];
36
43
  }): Promise<DirectPoolSwapApprovalResult>;
@@ -22,6 +22,7 @@ export declare function approveKyberSwapInput(args: {
22
22
  spender: Address;
23
23
  amount: bigint;
24
24
  approvalMode?: AegisSwapApprovalMode;
25
+ signal?: AbortSignal;
25
26
  onStatus?: AegisSwapActionCallbacks['onStatus'];
26
27
  onApprovalProgress?: AegisSwapActionCallbacks['onApprovalProgress'];
27
28
  }): Promise<KyberSwapApprovalResult>;
@@ -1,3 +1,4 @@
1
+ import type { AegisTransactionObservation } from '../swap/receiptWait.js';
1
2
  import type { Hex } from 'viem';
2
3
  import type { DirectSwapQuote } from '../quote.js';
3
4
  import type { AegisSwapReceiptSummary, SubmitStatus } from '../transactionProgress.js';
@@ -50,6 +51,7 @@ export type AegisSwapAuthorizationProgress = {
50
51
  completed: number;
51
52
  };
52
53
  export type AegisSwapActionCallbacks<TSwapDetails = AegisSwapSubmitDetails> = {
54
+ onTransactionObservation?: (event: AegisTransactionObservation) => void;
53
55
  onStatus?: (status: SubmitStatus) => void;
54
56
  onTxHash?: (hash: Hex | null) => void;
55
57
  onSubmitted?: (hash: Hex, swap?: TSwapDetails) => void;
@@ -6,6 +6,7 @@ export declare function waitForProviderChain(provider: Eip1193Provider, targetCh
6
6
  export declare function ensureWalletChain(args: {
7
7
  provider: Eip1193Provider;
8
8
  chain: AegisSwapChainConfig;
9
+ signal?: AbortSignal;
9
10
  onChainId?: (chainId: number | null) => void;
10
11
  }): Promise<void>;
11
12
  export declare function resolveWalletSession(args?: {