@temporalabs/treasury 0.1.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 (55) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +10 -0
  3. package/README.md +153 -0
  4. package/THIRD_PARTY_NOTICES.md +366 -0
  5. package/dist/abi/erc4626.d.ts +243 -0
  6. package/dist/abi/erc4626.js +146 -0
  7. package/dist/abi/erc4626.js.map +1 -0
  8. package/dist/build.d.ts +88 -0
  9. package/dist/build.js +124 -0
  10. package/dist/build.js.map +1 -0
  11. package/dist/client.d.ts +429 -0
  12. package/dist/client.js +248 -0
  13. package/dist/client.js.map +1 -0
  14. package/dist/config/earn.d.ts +47 -0
  15. package/dist/config/earn.js +46 -0
  16. package/dist/config/earn.js.map +1 -0
  17. package/dist/disclosures.d.ts +14 -0
  18. package/dist/disclosures.js +28 -0
  19. package/dist/disclosures.js.map +1 -0
  20. package/dist/index.d.ts +14 -0
  21. package/dist/index.js +10 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/links.d.ts +21 -0
  24. package/dist/links.js +32 -0
  25. package/dist/links.js.map +1 -0
  26. package/dist/mcp/server.d.ts +33 -0
  27. package/dist/mcp/server.js +346 -0
  28. package/dist/mcp/server.js.map +1 -0
  29. package/dist/mcp-server.mjs +56281 -0
  30. package/dist/position.d.ts +142 -0
  31. package/dist/position.js +354 -0
  32. package/dist/position.js.map +1 -0
  33. package/dist/preflight.d.ts +62 -0
  34. package/dist/preflight.js +165 -0
  35. package/dist/preflight.js.map +1 -0
  36. package/dist/quote.d.ts +55 -0
  37. package/dist/quote.js +83 -0
  38. package/dist/quote.js.map +1 -0
  39. package/dist/redact.d.ts +44 -0
  40. package/dist/redact.js +92 -0
  41. package/dist/redact.js.map +1 -0
  42. package/dist/registry-schema.d.ts +127 -0
  43. package/dist/registry-schema.js +124 -0
  44. package/dist/registry-schema.js.map +1 -0
  45. package/dist/registry.d.ts +26 -0
  46. package/dist/registry.js +62 -0
  47. package/dist/registry.js.map +1 -0
  48. package/dist/units.d.ts +8 -0
  49. package/dist/units.js +24 -0
  50. package/dist/units.js.map +1 -0
  51. package/dist/version.d.ts +1 -0
  52. package/dist/version.js +14 -0
  53. package/dist/version.js.map +1 -0
  54. package/package.json +58 -0
  55. package/registry/vaults.json +68 -0
@@ -0,0 +1,142 @@
1
+ import { type Address } from "viem";
2
+ import { type VaultEntry } from "./registry-schema.js";
3
+ import type { ReadClient } from "./client.js";
4
+ /** The value `entryBasisUsdc` / `accruedYieldUsdc` carry when the event scan failed outright: not a number. */
5
+ export declare const UNKNOWN_AFTER_SCAN_FAILURE = "unknown \u2014 event scan failed; see scan.note";
6
+ /**
7
+ * What `entryBasisUsdc` / `accruedYieldUsdc` carry when the scan read events but did NOT cover this
8
+ * position's history: shares in βˆ’ shares out does not reconcile to the balance, so the deposits that
9
+ * produced these shares are outside the window. Reporting the partial sums there renders a position
10
+ * whose deposit was missed as 100% yield (measured in review: 10.011996 USDC of
11
+ * "accrued yield" on a 10 USDC position). A bound nobody can see the bounds of is not a number.
12
+ */
13
+ export declare const UNKNOWN_INCOMPLETE_SCAN = "unknown \u2014 the scan did not cover this position's history; see scan.note";
14
+ export interface Position {
15
+ vault: string;
16
+ principal: Address;
17
+ /** Shares held, exact, in share units β€” pass this string back to earn_prepare_withdraw({ all }) unchanged. */
18
+ sharesExact: string;
19
+ shares: string;
20
+ /** What the shares redeem for now (convertToAssets). πŸ”΄ This is what the position is WORTH, not what
21
+ * can be taken out β€” see `exit`. */
22
+ usdcValue: string;
23
+ /**
24
+ * What a withdrawal would actually pay RIGHT NOW, measured by simulating it rather than by reading
25
+ * the vault's own view. `maxWithdraw()` answers what a holder is ENTITLED to, not what the vault can
26
+ * pay: measured on a live Fusion vault at block 51327076, it reported the full 14.999970
27
+ * USDC position while 1.498874 already reverted β€” the exit was capped at the vault's 1.498873 USDC
28
+ * idle balance, to the unit.
29
+ */
30
+ exit: {
31
+ /** The largest amount this simulation found payable now, or `"unknown"` when neither attempt resolved. */
32
+ exitableNow: string;
33
+ /** What that number is: the whole position, the vault's liquid balance, or neither. */
34
+ measuredAs: "full position" | "vault's liquid balance" | "nothing to withdraw" | "refused, size unknown" | "not measured";
35
+ /** The vault's own balance of the asset β€” what it can pay without unwinding, on a chassis that pays from it. */
36
+ instantLiquidity: string;
37
+ /** `maxWithdraw()`, reported because callers see it elsewhere β€” never as the verdict. */
38
+ maxWithdrawSays: string;
39
+ note: string;
40
+ };
41
+ /** Ξ£ deposited βˆ’ Ξ£ withdrawn for this owner, from the vault's Deposit/Withdraw events over the scanned window β€” or `UNKNOWN_AFTER_SCAN_FAILURE` when no events could be read at all. */
42
+ entryBasisUsdc: string;
43
+ /** usdcValue βˆ’ entryBasis. Negative means withdrawals exceeded deposits inside the window, or the window missed deposits β€” or `UNKNOWN_AFTER_SCAN_FAILURE`. */
44
+ accruedYieldUsdc: string;
45
+ sharePriceInAssets: string;
46
+ /**
47
+ * `source` names which RPC served the event scan, never its URL: `"logs rpc"` (the configured one)
48
+ * or `"fallback"` (the endpoint `TREASURY_LOGS_FALLBACK` names, Base's public one by default, used
49
+ * when the configured one could not cover the range). πŸ”΄ `complete` is only a RECONCILIATION and is
50
+ * vacuously true for an empty window β€” `wholeHistory` is the coverage claim, and the note is written
51
+ * from it.
52
+ */
53
+ scan: {
54
+ fromBlock: string;
55
+ toBlock: string;
56
+ deposits: number;
57
+ withdrawals: number;
58
+ /**
59
+ * The Deposit transactions this scan actually saw, oldest first β€” `txHash` is what an explorer
60
+ * link needs. Derived from the logs the scan already fetched to compute `entryBasisUsdc`; no
61
+ * extra request is made for them. Bounded by `MAX_SCAN_TXS`: when `deposits` exceeds the array's
62
+ * length, the list is the most recent that many and the COUNT is the total.
63
+ * πŸ”΄ These are the events inside the SCANNED WINDOW. They are the whole history only when
64
+ * `wholeHistory` is true β€” the same caveat that makes `entryBasisUsdc` unknown otherwise.
65
+ */
66
+ depositTxs: ScanTx[];
67
+ /** The Withdraw transactions this scan saw, on the same terms as `depositTxs`. */
68
+ withdrawTxs: ScanTx[];
69
+ complete: boolean;
70
+ capped: boolean;
71
+ providerWindow?: string;
72
+ source: "logs rpc" | "fallback";
73
+ /** `fromBlock` is at or before the vault's deployment block AND the scan reconciles: only then is this the WHOLE history. */
74
+ wholeHistory: boolean;
75
+ note: string;
76
+ };
77
+ measuredAtBlock: number;
78
+ }
79
+ export interface PositionArgs {
80
+ vault: VaultEntry;
81
+ principal: Address;
82
+ client: ReadClient;
83
+ /**
84
+ * How far back to try to scan for events. Default: from the vault's `deployedAtBlock` (the whole
85
+ * history), or 2,000,000 blocks (~46 days on Base at 2s) for a row that does not record it. The
86
+ * EFFECTIVE window is bounded by `maxLogRequests Γ— the provider's per-request cap`: 100 Γ— 10 = 1,000
87
+ * blocks on Alchemy's free tier, 100 Γ— 2,000 = 200,000 (~4.6 days) on Base's public RPC. A vault
88
+ * older than that needs a provider with a wide eth_getLogs range for a complete history.
89
+ * The result's `scan` block says what was actually covered; `complete` is the reconciliation test.
90
+ */
91
+ lookbackBlocks?: bigint;
92
+ /**
93
+ * Cap on eth_getLogs requests per scan. RPC providers cap the block range per request (measured:
94
+ * Alchemy free tier 10 blocks, Base public RPC 2,000), so a long lookback is walked in chunks and
95
+ * may not reach `lookbackBlocks` β€” the result says how far it got. Default 100 (per event).
96
+ */
97
+ maxLogRequests?: number;
98
+ /**
99
+ * A second read client for the event scan, used only when `client` cannot cover the range: its
100
+ * eth_getLogs error is one no window can be sized from (measured 2026-09-14: publicnode refuses any
101
+ * range older than ~2,000 blocks with "Archive requests require a personal token"), or its window
102
+ * would need more than `maxLogRequests` requests (Alchemy free tier: 10 blocks). The server passes
103
+ * Base's public endpoint, whose 2,000-block window serves history. Omitted β‡’ no fallback.
104
+ */
105
+ fallbackClient?: ReadClient;
106
+ /**
107
+ * Wall-clock budget for the event walk, milliseconds (default 30,000). A provider-sized walk over a
108
+ * long range is unbounded in time β€” measured at 40 s on the public endpoint, longer under 429s β€” and
109
+ * a tool that never returns is worse than one that returns a bounded answer. On expiry the walk stops
110
+ * where it is and the result is `capped`, with the budget named in the note.
111
+ */
112
+ budgetMs?: number;
113
+ /** Wall-clock budget for the two exit simulations, milliseconds (default 12,000). Separate from the scan's. */
114
+ exitBudgetMs?: number;
115
+ /** Clock, for tests. Defaults to `Date.now`. */
116
+ now?: () => number;
117
+ }
118
+ /**
119
+ * Parses the provider's stated maximum range out of its error, e.g. "limited to a 2,000 range" /
120
+ * "up to a 10 block range". `undefined` means the failure is NOT a window refusal β€” a caller must
121
+ * rethrow rather than narrow, or a dead provider and an empty result become the same answer.
122
+ * Exported for `tests/access.ts`, which walks a different contract's logs and needs the same
123
+ * distinction; NOT re-exported from index.ts.
124
+ */
125
+ export declare function rangeLimitFromError(e: unknown): bigint | undefined;
126
+ /** One Deposit or Withdraw, as an operator needs it to reach a block explorer. */
127
+ export interface ScanTx {
128
+ /** `null` only for a log the provider returned without one β€” never for a log from a mined range. */
129
+ txHash: `0x${string}` | null;
130
+ blockNumber: string | null;
131
+ /** The event's `assets`, formatted in the vault's asset units, e.g. `"10 USDC"`. */
132
+ amountUsdc: string;
133
+ }
134
+ /**
135
+ * How many transactions each of `scan.depositTxs` / `scan.withdrawTxs` carries at most. The COUNTS
136
+ * (`scan.deposits` / `scan.withdrawals`) stay the totals, so a truncated list is always detectable
137
+ * by comparing the two. A cap exists because this list is the only part of the response that grows
138
+ * with an account's history: an allocator depositing hourly reaches four figures in a year, and a
139
+ * tool response that large is a different failure from the one this field was added to fix.
140
+ */
141
+ export declare const MAX_SCAN_TXS = 100;
142
+ export declare function getPosition(args: PositionArgs): Promise<Position>;
@@ -0,0 +1,354 @@
1
+ import { BaseError, ContractFunctionRevertedError, ExecutionRevertedError, parseAbiItem } from "viem";
2
+ import { erc4626Abi } from "./abi/erc4626.js";
3
+ import { describeError } from "./redact.js";
4
+ import { formatAmount } from "./units.js";
5
+ /** ERC-4626's own events β€” the only durable record of what an account put in and took out. */
6
+ const depositEvent = parseAbiItem("event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares)");
7
+ const withdrawEvent = parseAbiItem("event Withdraw(address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares)");
8
+ /** The value `entryBasisUsdc` / `accruedYieldUsdc` carry when the event scan failed outright: not a number. */
9
+ export const UNKNOWN_AFTER_SCAN_FAILURE = "unknown β€” event scan failed; see scan.note";
10
+ /**
11
+ * What `entryBasisUsdc` / `accruedYieldUsdc` carry when the scan read events but did NOT cover this
12
+ * position's history: shares in βˆ’ shares out does not reconcile to the balance, so the deposits that
13
+ * produced these shares are outside the window. Reporting the partial sums there renders a position
14
+ * whose deposit was missed as 100% yield (measured in review: 10.011996 USDC of
15
+ * "accrued yield" on a 10 USDC position). A bound nobody can see the bounds of is not a number.
16
+ */
17
+ export const UNKNOWN_INCOMPLETE_SCAN = "unknown β€” the scan did not cover this position's history; see scan.note";
18
+ /**
19
+ * Parses the provider's stated maximum range out of its error, e.g. "limited to a 2,000 range" /
20
+ * "up to a 10 block range". `undefined` means the failure is NOT a window refusal β€” a caller must
21
+ * rethrow rather than narrow, or a dead provider and an empty result become the same answer.
22
+ * Exported for `tests/access.ts`, which walks a different contract's logs and needs the same
23
+ * distinction; NOT re-exported from index.ts.
24
+ */
25
+ export function rangeLimitFromError(e) {
26
+ const m = String(e).replace(/,/g, "").match(/(?:limited to a|up to a)\s+(\d+)\s*(?:block)?\s*range/i);
27
+ return m ? BigInt(m[1]) : undefined;
28
+ }
29
+ async function scanLogs(client, address, event, owner, from, to, maxRequests, refuseIfCapped, deadline, now) {
30
+ const argsFilter = { owner };
31
+ try {
32
+ const logs = await client.getLogs({ address, event, args: argsFilter, fromBlock: from, toBlock: to });
33
+ return { logs, coveredFrom: from, requests: 1, capped: false };
34
+ }
35
+ catch (e) {
36
+ const window = rangeLimitFromError(e);
37
+ if (!window)
38
+ throw e;
39
+ // Decide BEFORE walking whether the walk can finish. A walk that would stop short spends
40
+ // `maxRequests` calls to produce a bound; when a fallback exists, hand it the range instead.
41
+ const needed = (to - from + window) / window;
42
+ if (refuseIfCapped && needed > BigInt(maxRequests))
43
+ throw new WindowTooNarrow(window, needed);
44
+ // Walk backwards from `to` in provider-sized windows until the lookback is covered or the cap is hit.
45
+ const out = [];
46
+ let hi = to;
47
+ let requests = 0;
48
+ while (hi >= from && requests < maxRequests && now() < deadline) {
49
+ const lo = hi - window + 1n > from ? hi - window + 1n : from;
50
+ const chunk = await client.getLogs({ address, event, args: argsFilter, fromBlock: lo, toBlock: hi });
51
+ out.push(...chunk);
52
+ requests += 1;
53
+ hi = lo - 1n;
54
+ }
55
+ return { logs: out, coveredFrom: hi + 1n, requests, capped: hi >= from, window };
56
+ }
57
+ }
58
+ /** The provider's window would need more requests than allowed to cover the range. */
59
+ class WindowTooNarrow extends Error {
60
+ window;
61
+ needed;
62
+ constructor(window, needed) {
63
+ super(`the provider's ${window}-block eth_getLogs window needs ${needed} requests for this range`);
64
+ this.window = window;
65
+ this.needed = needed;
66
+ }
67
+ }
68
+ /**
69
+ * How many transactions each of `scan.depositTxs` / `scan.withdrawTxs` carries at most. The COUNTS
70
+ * (`scan.deposits` / `scan.withdrawals`) stay the totals, so a truncated list is always detectable
71
+ * by comparing the two. A cap exists because this list is the only part of the response that grows
72
+ * with an account's history: an allocator depositing hourly reaches four figures in a year, and a
73
+ * tool response that large is a different failure from the one this field was added to fix.
74
+ */
75
+ export const MAX_SCAN_TXS = 100;
76
+ /**
77
+ * πŸ”΄ SORT, DO NOT TRUST THE ORDER THE WALK PRODUCED β€” it is path-dependent. The single-request path
78
+ * returns the provider's own ascending order, while the chunked fallback walks BACKWARDS from
79
+ * `toBlock` and pushes each chunk, so its array is descending by chunk and ascending inside one.
80
+ * Both paths feed this function, and the sums above are order-independent so nothing else in this
81
+ * file ever noticed. A list of transactions handed to a human is the first consumer that does.
82
+ */
83
+ function txsOf(logs, decimals, symbol) {
84
+ const key = (l) => [l.blockNumber ?? -1n, l.logIndex ?? -1];
85
+ const sorted = [...logs].sort((a, b) => {
86
+ const [ab, ai] = key(a);
87
+ const [bb, bi] = key(b);
88
+ return ab === bb ? ai - bi : ab < bb ? -1 : 1;
89
+ });
90
+ return sorted.slice(-MAX_SCAN_TXS).map((l) => ({
91
+ txHash: l.transactionHash,
92
+ blockNumber: l.blockNumber === null ? null : l.blockNumber.toString(),
93
+ amountUsdc: `${formatAmount(l.args.assets ?? 0n, decimals)} ${symbol}`,
94
+ }));
95
+ }
96
+ /**
97
+ * Did the CHAIN refuse this, or did the RPC fail to ask it? Every failure used to read as "cannot pay",
98
+ * so one HTTP 502 on the first simulation reported a fully-exitable position as unexitable AND blamed
99
+ * the vault for it (measured through a proxy that failed exactly one call: one attempt made, the vault
100
+ * never asked, `exitableNow: "unknown"`, note "the refusal is the vault's").
101
+ * viem's own error chain separates them: a real revert carries a ContractFunctionRevertedError or an
102
+ * ExecutionRevertedError; a transport failure does not.
103
+ */
104
+ function isRevert(e) {
105
+ return e instanceof BaseError && e.walk((x) => x instanceof ContractFunctionRevertedError || x instanceof ExecutionRevertedError) !== null;
106
+ }
107
+ /**
108
+ * At most two simulated withdrawals β€” the whole position, then the vault's own liquid balance β€” and the
109
+ * answer is whichever the chain accepts. Simulation rather than arithmetic because the ceiling is
110
+ * chassis-specific: a Fusion vault with no instant-withdrawal fuses pays only from its own balance,
111
+ * while a Morpho V2 vault holds almost none and still pays, out of the markets beneath it. Reading
112
+ * either `maxWithdraw()` or the liquid balance alone gets one of those two wrong.
113
+ *
114
+ * Nothing here is reported as the vault's answer unless the vault answered.
115
+ */
116
+ async function measureExit(a) {
117
+ const { vault, principal, client, shares, value } = a;
118
+ const fmt = (x) => `${formatAmount(x, vault.asset.decimals)} ${vault.asset.symbol}`;
119
+ // An empty account needs no reads at all β€” `earn_balance` is the most-called tool.
120
+ if (shares === 0n) {
121
+ return { exitableNow: fmt(0n), measuredAs: "nothing to withdraw", instantLiquidity: "not read", maxWithdrawSays: "not read", note: "the account holds no shares." };
122
+ }
123
+ const read = async (fn) => {
124
+ try {
125
+ return { value: await fn(), failed: undefined };
126
+ }
127
+ catch (e) {
128
+ return { failed: isRevert(e) ? "revert" : "rpc" };
129
+ }
130
+ };
131
+ const [liquidRead, maxRead] = await Promise.all([
132
+ read(() => client.readContract({ address: vault.asset.address, abi: erc4626Abi, functionName: "balanceOf", args: [vault.address] })),
133
+ read(() => client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "maxWithdraw", args: [principal] })),
134
+ ]);
135
+ const liquid = liquidRead.value;
136
+ const liquidText = liquid === undefined ? (liquidRead.failed === "revert" ? "reverted" : "unavailable β€” the RPC call failed") : fmt(liquid);
137
+ const maxText = maxRead.value === undefined ? (maxRead.failed === "revert" ? "reverted" : "unavailable β€” the RPC call failed") : fmt(maxRead.value);
138
+ // Only worth saying when the vault actually answered with a number bigger than what can be paid.
139
+ const advisory = maxRead.value !== undefined && maxRead.value > 0n ? ` maxWithdraw() says ${maxText}; that is an entitlement, not an amount the vault can pay.` : "";
140
+ // Shares worth nothing at this share price: a known zero, not a refusal.
141
+ if (value === 0n) {
142
+ return {
143
+ exitableNow: fmt(0n),
144
+ measuredAs: "nothing to withdraw",
145
+ instantLiquidity: liquidText,
146
+ maxWithdrawSays: maxText,
147
+ note: `the account holds ${formatAmount(shares, vault.shareDecimals)} ${vault.symbol}, which converts to nothing at this share price. No withdrawal was simulated.`,
148
+ };
149
+ }
150
+ const attempt = async (assets) => {
151
+ if (assets === 0n)
152
+ return "refused";
153
+ if (a.now() >= a.deadline)
154
+ return "unresolved";
155
+ try {
156
+ await client.simulateContract({ address: vault.address, abi: erc4626Abi, functionName: "withdraw", args: [assets, principal, principal], account: principal });
157
+ return "paid";
158
+ }
159
+ catch (e) {
160
+ return isRevert(e) ? "refused" : "unresolved";
161
+ }
162
+ };
163
+ const unresolved = (what) => ({
164
+ exitableNow: "unknown",
165
+ measuredAs: "not measured",
166
+ instantLiquidity: liquidText,
167
+ maxWithdrawSays: maxText,
168
+ note: `${what} β€” this is a failure to ASK the vault, not an answer from it: no conclusion should be drawn about what can be withdrawn.${advisory}`,
169
+ });
170
+ const full = await attempt(value);
171
+ if (full === "paid") {
172
+ return { exitableNow: fmt(value), measuredAs: "full position", instantLiquidity: liquidText, maxWithdrawSays: maxText, note: `a withdrawal of the whole position simulates OK at this block.${advisory}` };
173
+ }
174
+ if (full === "unresolved")
175
+ return unresolved("the simulation of a full-position withdrawal did not complete");
176
+ // The vault refused the full amount. Probe the liquid bound whenever there is one β€” including when it
177
+ // is at or above the position, where the refusal has some other cause and the probe is still the
178
+ // cheapest thing that can tell us so.
179
+ if (liquid === undefined)
180
+ return unresolved("the vault refused a full-position withdrawal and the vault's liquid balance could not be read");
181
+ // When `liquid >= value` the bound IS the position, so this re-asks the same question. Keep it
182
+ // anyway: the two calls are separate requests against "latest", so a second can genuinely
183
+ // succeed where the first reverted β€” a cooldown clearing, a rate limiter resetting, a new block. What
184
+ // must NOT happen is describing it as something it was not: the note says what was
185
+ // asked, and a success is believed whatever bound produced it.
186
+ const boundedByLiquid = liquid < value;
187
+ const askedFor = boundedByLiquid ? liquid : value;
188
+ const bounded = await attempt(askedFor);
189
+ if (bounded === "paid" && boundedByLiquid) {
190
+ return {
191
+ exitableNow: fmt(liquid),
192
+ measuredAs: "vault's liquid balance",
193
+ instantLiquidity: liquidText,
194
+ maxWithdrawSays: maxText,
195
+ note: `the whole position does NOT come out at this block: this chassis pays withdrawals from the vault's own balance, and the rest is deployed. ${fmt(liquid)} of ${fmt(value)} is payable now; the remainder needs the fund to unwind first.${advisory}`,
196
+ };
197
+ }
198
+ // πŸ”΄ A success is a success whatever bound produced it. The old gate reused the ATTEMPT condition as
199
+ // the TRUST condition, so a second probe that paid was silently discarded and the result then claimed
200
+ // both were refused β€” false, and reproduced live (liquid 5, value 1, first revert, second paid,
201
+ // reported as "refused, size unknown").
202
+ if (bounded === "paid") {
203
+ return { exitableNow: fmt(value), measuredAs: "full position", instantLiquidity: liquidText, maxWithdrawSays: maxText, note: `a withdrawal of the whole position simulates OK at this block β€” the first attempt was refused and an identical retry succeeded, which two separate calls against the chain's latest state can legitimately do.${advisory}` };
204
+ }
205
+ if (bounded === "unresolved")
206
+ return unresolved("the vault refused a full-position withdrawal and the second simulation did not complete");
207
+ return {
208
+ exitableNow: "unknown",
209
+ measuredAs: "refused, size unknown",
210
+ instantLiquidity: liquidText,
211
+ maxWithdrawSays: maxText,
212
+ // Say what was ASKED. When the liquid balance is at or above the position, the second attempt was
213
+ // the same amount as the first, and describing it as "bounded by the liquid balance" names a
214
+ // withdrawal nobody simulated.
215
+ note: `the vault REFUSED ${boundedByLiquid ? `a full-position withdrawal and one bounded by its liquid balance (${liquidText})` : `a full-position withdrawal, twice β€” its liquid balance (${liquidText}) is at or above the position, so there was no smaller bound to try`} at this block. Both refusals came from the vault, so this is its answer β€” but it is not a shortfall this client could size.${advisory}`,
216
+ };
217
+ }
218
+ export async function getPosition(args) {
219
+ const { vault, principal, client } = args;
220
+ const lookback = args.lookbackBlocks ?? 2000000n;
221
+ const oneShare = 10n ** BigInt(vault.shareDecimals);
222
+ const [block, shares, oneShareInAssets] = await Promise.all([
223
+ client.getBlockNumber(),
224
+ client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "balanceOf", args: [principal] }),
225
+ client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "convertToAssets", args: [oneShare] }),
226
+ ]);
227
+ const value = shares === 0n
228
+ ? 0n
229
+ : await client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "convertToAssets", args: [shares] });
230
+ const now = args.now ?? Date.now;
231
+ // πŸ”΄ The exit's clock, and the scan's, must not overlap. An earlier revision gave the exit its own 12 s but left
232
+ // the scan's deadline computed HERE, before the exit ran β€” so the exit still spent the scan's wall
233
+ // clock and the comment claiming otherwise was false (four zero-config runs: exit "not measured" and the
234
+ // scan cut short at 42,000 of 108,533 blocks, four for four). The scan's deadline is taken AFTER the
235
+ // exit returns, below.
236
+ const exitDeadline = now() + (args.exitBudgetMs ?? 12_000);
237
+ const exit = await measureExit({ vault, principal, client, shares, value, deadline: exitDeadline, now });
238
+ const deadline = now() + (args.budgetMs ?? 30_000);
239
+ // The scan starts at the vault's deployment block when the registry records it: a position has no
240
+ // history before its vault existed, so that range is the whole history. An explicit lookback still
241
+ // narrows it (never widens it past deployment).
242
+ const deployed = vault.deployedAtBlock === undefined ? undefined : BigInt(vault.deployedAtBlock);
243
+ const byLookback = block > lookback ? block - lookback : 0n;
244
+ const wanted = deployed === undefined ? byLookback : args.lookbackBlocks === undefined ? deployed : byLookback > deployed ? byLookback : deployed;
245
+ const maxReq = args.maxLogRequests ?? 100;
246
+ const fallback = args.fallbackClient;
247
+ // One scan = deposits then withdrawals, SEQUENTIALLY: two concurrent walks double the request rate
248
+ // against a provider that is already the thing rate-limiting us.
249
+ const scanBoth = async (c, refuseIfCapped) => {
250
+ const d = await scanLogs(c, vault.address, depositEvent, principal, wanted, block, maxReq, refuseIfCapped, deadline, now);
251
+ const w = await scanLogs(c, vault.address, withdrawEvent, principal, wanted, block, maxReq, refuseIfCapped, deadline, now);
252
+ return [d, w];
253
+ };
254
+ // Primary first. It hands over to the fallback on exactly two conditions, both decided by the
255
+ // provider's own answer: an eth_getLogs error no window can be sized from, or a window too narrow to
256
+ // finish inside `maxReq`. Anything else a primary returns is its answer.
257
+ // A provider whose eth_getLogs error wording matches neither phrasing `rangeLimitFromError` knows
258
+ // makes scanLogs re-throw. That must degrade the way a capped scan does β€” an empty, incomplete
259
+ // window with the reason in the note β€” not fail the whole position read.
260
+ let scanFailure;
261
+ let source = "logs rpc";
262
+ let handover;
263
+ const empty = { logs: [], coveredFrom: block, capped: true, window: undefined };
264
+ let result;
265
+ try {
266
+ result = await scanBoth(client, fallback !== undefined);
267
+ }
268
+ catch (primaryError) {
269
+ if (!fallback) {
270
+ scanFailure = describeError(primaryError);
271
+ result = [empty, empty];
272
+ }
273
+ else {
274
+ handover = primaryError instanceof WindowTooNarrow ? primaryError.message : `eth_getLogs failed: ${describeError(primaryError, 120)}`;
275
+ try {
276
+ result = await scanBoth(fallback, false);
277
+ // πŸ”΄ Set ONLY once the fallback has RESOLVED. Setting it at handover made a both-failed scan
278
+ // report a source for data nothing served.
279
+ source = "fallback";
280
+ }
281
+ catch (fallbackError) {
282
+ scanFailure = `logs rpc: ${handover}; fallback: ${describeError(fallbackError)}`;
283
+ result = [empty, empty];
284
+ }
285
+ }
286
+ }
287
+ const [d, w] = result;
288
+ const deps = d.logs;
289
+ const wds = w.logs;
290
+ const fromBlock = d.coveredFrom > w.coveredFrom ? d.coveredFrom : w.coveredFrom;
291
+ const capped = d.capped || w.capped;
292
+ const timedOut = capped && now() >= deadline;
293
+ const providerWindow = d.window ?? w.window;
294
+ const depositedAssets = deps.reduce((n, l) => n + (l.args.assets ?? 0n), 0n);
295
+ const withdrawnAssets = wds.reduce((n, l) => n + (l.args.assets ?? 0n), 0n);
296
+ const depositedShares = deps.reduce((n, l) => n + (l.args.shares ?? 0n), 0n);
297
+ const withdrawnShares = wds.reduce((n, l) => n + (l.args.shares ?? 0n), 0n);
298
+ const basis = depositedAssets - withdrawnAssets;
299
+ // Completeness check the numbers themselves can make: if the shares in the window do not account
300
+ // for the shares held, the window missed history (or shares were transferred in/out).
301
+ const complete = depositedShares - withdrawnShares === shares;
302
+ // πŸ”΄ `complete` alone is a RECONCILIATION, and it is vacuously true for an empty window on an
303
+ // account with no shares β€” or, with a short lookback, for a window that saw neither the deposits nor
304
+ // the withdrawals that cancel out. Whole history is a claim about COVERAGE: the scan reached the
305
+ // block the vault was deployed at, nothing was cut short, and the shares reconcile.
306
+ const wholeHistory = deployed !== undefined && fromBlock <= deployed && !capped && complete;
307
+ // πŸ”΄ A LIFETIME FIGURE IS REPORTED ONLY WHEN THE SCAN COVERED THE LIFETIME. Basis and yield
308
+ // are sums over the account's whole history; a window that reconciles is not evidence it saw that
309
+ // history. Measured: a live wallet at lookback 83,000 reported the
310
+ // right basis ONLY because that window happened to catch all thirteen events β€” which the client
311
+ // cannot know. Every earlier formulation was a special case of this one: `!complete` (an exited
312
+ // account whose window saw the withdrawal but not the deposit printed a NEGATIVE basis),
313
+ // and the empty-window clause (an account that deposited and exited before the window printed a
314
+ // confident "0 USDC"). `!wholeHistory` subsumes both, including the honest zero.
315
+ const basisUnknown = !wholeHistory;
316
+ const fmtA = (x) => `${formatAmount(x, vault.asset.decimals)} ${vault.asset.symbol}`;
317
+ return {
318
+ vault: vault.symbol,
319
+ principal,
320
+ sharesExact: formatAmount(shares, vault.shareDecimals),
321
+ shares: `${formatAmount(shares, vault.shareDecimals)} ${vault.symbol}`,
322
+ usdcValue: fmtA(value),
323
+ exit,
324
+ // On a scan failure NOTHING was read, so basis and yield are unknown β€” never 0 and valueβˆ’0, which
325
+ // would report the whole position as yield while the note says "unknown".
326
+ entryBasisUsdc: scanFailure ? UNKNOWN_AFTER_SCAN_FAILURE : basisUnknown ? UNKNOWN_INCOMPLETE_SCAN : fmtA(basis),
327
+ accruedYieldUsdc: scanFailure ? UNKNOWN_AFTER_SCAN_FAILURE : basisUnknown ? UNKNOWN_INCOMPLETE_SCAN : fmtA(value - basis),
328
+ sharePriceInAssets: `${formatAmount(oneShareInAssets, vault.asset.decimals)} ${vault.asset.symbol} per share`,
329
+ scan: {
330
+ fromBlock: fromBlock.toString(),
331
+ toBlock: block.toString(),
332
+ deposits: deps.length,
333
+ withdrawals: wds.length,
334
+ depositTxs: txsOf(deps, vault.asset.decimals, vault.asset.symbol),
335
+ withdrawTxs: txsOf(wds, vault.asset.decimals, vault.asset.symbol),
336
+ complete,
337
+ capped,
338
+ ...(providerWindow !== undefined ? { providerWindow: providerWindow.toString() } : {}),
339
+ source,
340
+ wholeHistory,
341
+ note: (handover && !scanFailure ? `the configured logs RPC could not cover this range (${handover}), so the fallback endpoint (TREASURY_LOGS_FALLBACK, Base's public endpoint by default) served the scan. ` : "") + (scanFailure
342
+ ? `event scan FAILED (${scanFailure}): the provider's eth_getLogs error was not one this client can size a window from, so no history was read β€” basis and yield are unknown, not zero. Set TREASURY_LOGS_RPC_BASE to a provider with a known window (Alchemy, Base public), or use the agent's own deposit receipts.`
343
+ : wholeHistory
344
+ ? "the scan covered every block from the vault's deployment, and shares in βˆ’ shares out reconciles to the balance: the basis covers this position's whole history"
345
+ : capped
346
+ ? `the scan was CUT SHORT β€” ${block - fromBlock + 1n} of the ${block - (deployed ?? 0n) + 1n} blocks since deployment, at the provider's ${providerWindow ?? "?"}-block eth_getLogs window and ${timedOut ? `a ${Math.round((args.budgetMs ?? 30_000) / 1000)}s time budget` : `${maxReq} requests`}; covering the rest needs about ${providerWindow ? (block - (deployed ?? 0n) + providerWindow) / providerWindow : BigInt(maxReq)} requests per event. ${complete ? "Shares in βˆ’ shares out happens to reconcile over that window, which an empty window does vacuously β€” it is NOT evidence the history was covered." : "Basis and yield are unknown, not bounds."} Set TREASURY_LOGS_RPC_BASE to a provider with a wide eth_getLogs range${timedOut ? "" : ", raise max_log_requests"}, or use the agent's own deposit receipts.`
347
+ : complete
348
+ ? `shares in βˆ’ shares out reconciles over the ${block - fromBlock + 1n} blocks scanned, but the scan started at block ${fromBlock}${deployed === undefined ? " and the registry does not record when this vault was deployed" : `, after the vault's deployment block ${deployed}`} β€” deposits and withdrawals before it cancel out unseen, so this is a WINDOW, NOT the whole history. Omit lookback_blocks to scan from deployment.`
349
+ : "shares in βˆ’ shares out β‰  balance: history predates the window or shares moved by transfer β€” basis and yield are unknown, not totals"),
350
+ },
351
+ measuredAtBlock: Number(block),
352
+ };
353
+ }
354
+ //# sourceMappingURL=position.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"position.js","sourceRoot":"","sources":["../src/position.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import { type Address, type Hex } from "viem";
2
+ import { type VaultEntry } from "./registry-schema.js";
3
+ import type { ReadClient } from "./client.js";
4
+ export type PreflightStatus =
5
+ /** Simulated deposit succeeds as-is: access open, allowance already sufficient. */
6
+ "OPEN_READY"
7
+ /** Simulated deposit reached the token pull and failed on allowance: access is OPEN; an approve is needed first. */
8
+ | "NEEDS_APPROVAL"
9
+ /** Access-managed revert: the vault restricts `deposit` to a role the depositor lacks. */
10
+ | "WHITELIST_GATED"
11
+ /** A definite revert this client cannot name. Candidates are listed; nothing is diagnosed. */
12
+ | "REVERTED_OTHER"
13
+ /** The client refused before touching the chain (chassis, or registry/chain mismatch). */
14
+ | "REFUSED_BY_CLIENT"
15
+ /** Transport failure. Not a verdict about the vault β€” an absence of evidence. */
16
+ | "UNRESOLVED";
17
+ export interface RevertObservation {
18
+ selector?: Hex;
19
+ reason?: string;
20
+ raw?: Hex;
21
+ }
22
+ /**
23
+ * Names a cause only where the instrument discriminated; otherwise lists candidates.
24
+ * A revert is an answer. A transport error is not, and must never land here.
25
+ */
26
+ export declare function classifyRevert(obs: RevertObservation): {
27
+ status: PreflightStatus;
28
+ note: string;
29
+ };
30
+ /** Pulls the revert payload out of viem's error chain. Returns undefined for anything that is not a definite revert. */
31
+ export declare function extractRevert(err: unknown): RevertObservation | undefined;
32
+ export interface PreflightResult {
33
+ vault: string;
34
+ depositor: Address;
35
+ status: PreflightStatus;
36
+ canDeposit: boolean;
37
+ /** Observations, in the order they were taken. Each is a sentence a human can act on. */
38
+ findings: string[];
39
+ balances?: {
40
+ asset: string;
41
+ shares: string;
42
+ allowance: string;
43
+ };
44
+ quotes?: {
45
+ sharePriceInAssets: string;
46
+ totalAssets: string;
47
+ previewShares?: string;
48
+ };
49
+ advisory?: {
50
+ maxDepositRaw: string;
51
+ note: string;
52
+ };
53
+ measuredAtBlock?: number;
54
+ }
55
+ export interface PreflightArgs {
56
+ vault: VaultEntry;
57
+ depositor: Address;
58
+ /** Optional. If omitted, one whole unit of the asset is simulated. */
59
+ assetsHuman?: string;
60
+ client: ReadClient;
61
+ }
62
+ export declare function preflightDeposit(args: PreflightArgs): Promise<PreflightResult>;