@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.
- package/LICENSE +201 -0
- package/NOTICE +10 -0
- package/README.md +153 -0
- package/THIRD_PARTY_NOTICES.md +366 -0
- package/dist/abi/erc4626.d.ts +243 -0
- package/dist/abi/erc4626.js +146 -0
- package/dist/abi/erc4626.js.map +1 -0
- package/dist/build.d.ts +88 -0
- package/dist/build.js +124 -0
- package/dist/build.js.map +1 -0
- package/dist/client.d.ts +429 -0
- package/dist/client.js +248 -0
- package/dist/client.js.map +1 -0
- package/dist/config/earn.d.ts +47 -0
- package/dist/config/earn.js +46 -0
- package/dist/config/earn.js.map +1 -0
- package/dist/disclosures.d.ts +14 -0
- package/dist/disclosures.js +28 -0
- package/dist/disclosures.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/links.d.ts +21 -0
- package/dist/links.js +32 -0
- package/dist/links.js.map +1 -0
- package/dist/mcp/server.d.ts +33 -0
- package/dist/mcp/server.js +346 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp-server.mjs +56281 -0
- package/dist/position.d.ts +142 -0
- package/dist/position.js +354 -0
- package/dist/position.js.map +1 -0
- package/dist/preflight.d.ts +62 -0
- package/dist/preflight.js +165 -0
- package/dist/preflight.js.map +1 -0
- package/dist/quote.d.ts +55 -0
- package/dist/quote.js +83 -0
- package/dist/quote.js.map +1 -0
- package/dist/redact.d.ts +44 -0
- package/dist/redact.js +92 -0
- package/dist/redact.js.map +1 -0
- package/dist/registry-schema.d.ts +127 -0
- package/dist/registry-schema.js +124 -0
- package/dist/registry-schema.js.map +1 -0
- package/dist/registry.d.ts +26 -0
- package/dist/registry.js +62 -0
- package/dist/registry.js.map +1 -0
- package/dist/units.d.ts +8 -0
- package/dist/units.js +24 -0
- package/dist/units.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +14 -0
- package/dist/version.js.map +1 -0
- package/package.json +58 -0
- package/registry/vaults.json +68 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { BaseError, ContractFunctionRevertedError, } from "viem";
|
|
2
|
+
import { erc4626Abi, knownRevertSelectors } from "./abi/erc4626.js";
|
|
3
|
+
import { erc4626Chassis } from "./registry-schema.js";
|
|
4
|
+
import { describeError } from "./redact.js";
|
|
5
|
+
import { parseAmount, formatAmount } from "./units.js";
|
|
6
|
+
/**
|
|
7
|
+
* Names a cause only where the instrument discriminated; otherwise lists candidates.
|
|
8
|
+
* A revert is an answer. A transport error is not, and must never land here.
|
|
9
|
+
*/
|
|
10
|
+
export function classifyRevert(obs) {
|
|
11
|
+
const sel = obs.selector?.toLowerCase();
|
|
12
|
+
if (sel === knownRevertSelectors.AccessManagedUnauthorized) {
|
|
13
|
+
return {
|
|
14
|
+
status: "WHITELIST_GATED",
|
|
15
|
+
note: `deposit() reverted AccessManagedUnauthorized (${sel}) — the vault's AccessManager restricts deposit to a role this address does not hold (on IPOR Fusion: role 800 WHITELIST). redeem() may still be public.`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (sel === knownRevertSelectors.TransferFromReverted) {
|
|
19
|
+
return {
|
|
20
|
+
status: "NEEDS_APPROVAL",
|
|
21
|
+
note: `deposit() reverted TransferFromReverted (${sel}) — the call passed every access gate and died pulling the asset: access is OPEN, approve first.`,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (obs.reason && /allowance|ERC20InsufficientAllowance|transfer amount exceeds/i.test(obs.reason)) {
|
|
25
|
+
return {
|
|
26
|
+
status: "NEEDS_APPROVAL",
|
|
27
|
+
note: `deposit() reverted "${obs.reason}" — died at the token pull: access is OPEN, approve first.`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
status: "REVERTED_OTHER",
|
|
32
|
+
note: `deposit() reverted${sel ? ` with selector ${sel}` : ""}${obs.reason ? ` ("${obs.reason}")` : ""}; ` +
|
|
33
|
+
`this client does not name the cause. Check, in no particular order: vault paused; per-block or supply cap; ` +
|
|
34
|
+
`insufficient asset balance at the depositor; a chassis-specific gate this client has not seen. Raw: ${obs.raw ?? "n/a"}.`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Pulls the revert payload out of viem's error chain. Returns undefined for anything that is not a definite revert. */
|
|
38
|
+
export function extractRevert(err) {
|
|
39
|
+
if (!(err instanceof BaseError))
|
|
40
|
+
return undefined;
|
|
41
|
+
const r = err.walk((e) => e instanceof ContractFunctionRevertedError);
|
|
42
|
+
if (!r)
|
|
43
|
+
return undefined;
|
|
44
|
+
const raw = r.raw;
|
|
45
|
+
const signature = r.signature;
|
|
46
|
+
const selector = signature ?? (raw && raw.length >= 10 ? raw.slice(0, 10) : undefined);
|
|
47
|
+
const out = {};
|
|
48
|
+
if (selector)
|
|
49
|
+
out.selector = selector;
|
|
50
|
+
if (r.reason)
|
|
51
|
+
out.reason = r.reason;
|
|
52
|
+
if (raw)
|
|
53
|
+
out.raw = raw;
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
export async function preflightDeposit(args) {
|
|
57
|
+
const { vault, depositor, client } = args;
|
|
58
|
+
const findings = [];
|
|
59
|
+
const refuse = (why) => ({
|
|
60
|
+
vault: vault.symbol,
|
|
61
|
+
depositor,
|
|
62
|
+
status: "REFUSED_BY_CLIENT",
|
|
63
|
+
canDeposit: false,
|
|
64
|
+
findings: [...findings, why],
|
|
65
|
+
});
|
|
66
|
+
if (!erc4626Chassis.has(vault.chassis)) {
|
|
67
|
+
return refuse(`${vault.chassis} exposes no ERC-4626 deposit path; refusing (${vault.depositOpen.detail ?? "see registry"})`);
|
|
68
|
+
}
|
|
69
|
+
if (!vault.depositOpen.open) {
|
|
70
|
+
findings.push(`registry says deposits were CLOSED when last measured (block ${vault.depositOpen.measuredAtBlock}, ${vault.depositOpen.reason}); re-measuring live rather than trusting the row`);
|
|
71
|
+
}
|
|
72
|
+
// Cross-artifact identity check: the registry row and the contract must agree about each other.
|
|
73
|
+
// A presence check cannot detect a swapped address; asking the vault what its asset is can.
|
|
74
|
+
let block;
|
|
75
|
+
let onchainAsset;
|
|
76
|
+
let onchainDecimals;
|
|
77
|
+
try {
|
|
78
|
+
[block, onchainAsset, onchainDecimals] = await Promise.all([
|
|
79
|
+
client.getBlockNumber(),
|
|
80
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "asset" }),
|
|
81
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "decimals" }),
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
return { vault: vault.symbol, depositor, status: "UNRESOLVED", canDeposit: false, findings: [...findings, `identity reads failed: ${describeError(e)}`] };
|
|
86
|
+
}
|
|
87
|
+
if (onchainAsset.toLowerCase() !== vault.asset.address.toLowerCase()) {
|
|
88
|
+
return refuse(`registry asset ${vault.asset.address} != on-chain asset() ${onchainAsset} — registry row is wrong or the address is a different contract`);
|
|
89
|
+
}
|
|
90
|
+
if (onchainDecimals !== vault.shareDecimals) {
|
|
91
|
+
return refuse(`registry shareDecimals ${vault.shareDecimals} != on-chain decimals() ${onchainDecimals}`);
|
|
92
|
+
}
|
|
93
|
+
findings.push(`identity OK at block ${block}: asset()=${onchainAsset}, decimals()=${onchainDecimals}`);
|
|
94
|
+
const assets = parseAmount(args.assetsHuman ?? "1", vault.asset.decimals, `deposit amount (${vault.asset.symbol})`);
|
|
95
|
+
// Reads. Each on its own; a failure here is UNRESOLVED, never a verdict.
|
|
96
|
+
let assetBal, shareBal, allowance, oneShareInAssets, totalAssets, maxDep;
|
|
97
|
+
try {
|
|
98
|
+
[assetBal, shareBal, allowance, oneShareInAssets, totalAssets, maxDep] = await Promise.all([
|
|
99
|
+
client.readContract({ address: vault.asset.address, abi: erc4626Abi, functionName: "balanceOf", args: [depositor] }),
|
|
100
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "balanceOf", args: [depositor] }),
|
|
101
|
+
client.readContract({ address: vault.asset.address, abi: erc4626Abi, functionName: "allowance", args: [depositor, vault.address] }),
|
|
102
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "convertToAssets", args: [10n ** BigInt(vault.shareDecimals)] }),
|
|
103
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "totalAssets" }),
|
|
104
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "maxDeposit", args: [depositor] }),
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
return { vault: vault.symbol, depositor, status: "UNRESOLVED", canDeposit: false, findings: [...findings, `state reads failed: ${describeError(e)}`] };
|
|
109
|
+
}
|
|
110
|
+
const balances = {
|
|
111
|
+
asset: `${formatAmount(assetBal, vault.asset.decimals)} ${vault.asset.symbol}`,
|
|
112
|
+
shares: `${formatAmount(shareBal, vault.shareDecimals)} ${vault.symbol}`,
|
|
113
|
+
allowance: `${formatAmount(allowance, vault.asset.decimals)} ${vault.asset.symbol}`,
|
|
114
|
+
};
|
|
115
|
+
const quotes = {
|
|
116
|
+
sharePriceInAssets: `${formatAmount(oneShareInAssets, vault.asset.decimals)} ${vault.asset.symbol} per share`,
|
|
117
|
+
totalAssets: `${formatAmount(totalAssets, vault.asset.decimals)} ${vault.asset.symbol}`,
|
|
118
|
+
};
|
|
119
|
+
const advisory = {
|
|
120
|
+
maxDepositRaw: maxDep.toString(),
|
|
121
|
+
note: "maxDeposit() is ADVISORY ONLY: measured returning uint256.max on a whitelist-gated Fusion vault and 0 on an open Morpho V2 vault. The simulation below is the verdict.",
|
|
122
|
+
};
|
|
123
|
+
if (assetBal < assets)
|
|
124
|
+
findings.push(`depositor holds ${balances.asset}, less than the ${formatAmount(assets, vault.asset.decimals)} requested — a live deposit would fail on balance even if access is open`);
|
|
125
|
+
// Preview (does not depend on access) — gives the shares quote where the chassis supports it.
|
|
126
|
+
try {
|
|
127
|
+
const previewShares = await client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "previewDeposit", args: [assets] });
|
|
128
|
+
quotes.previewShares = `${formatAmount(previewShares, vault.shareDecimals)} ${vault.symbol}`;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
findings.push("previewDeposit() reverted; no shares quote");
|
|
132
|
+
}
|
|
133
|
+
// The verdict: simulate the real call from the real depositor.
|
|
134
|
+
try {
|
|
135
|
+
await client.simulateContract({
|
|
136
|
+
address: vault.address,
|
|
137
|
+
abi: erc4626Abi,
|
|
138
|
+
functionName: "deposit",
|
|
139
|
+
args: [assets, depositor],
|
|
140
|
+
account: depositor,
|
|
141
|
+
});
|
|
142
|
+
findings.push("simulated deposit() SUCCEEDED from this address with the current allowance");
|
|
143
|
+
return { vault: vault.symbol, depositor, status: "OPEN_READY", canDeposit: true, findings, balances, quotes, advisory, measuredAtBlock: Number(block) };
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
const obs = extractRevert(e);
|
|
147
|
+
if (!obs) {
|
|
148
|
+
return { vault: vault.symbol, depositor, status: "UNRESOLVED", canDeposit: false, findings: [...findings, `simulation did not return a definite revert: ${describeError(e)}`], balances, quotes, advisory, measuredAtBlock: Number(block) };
|
|
149
|
+
}
|
|
150
|
+
const c = classifyRevert(obs);
|
|
151
|
+
findings.push(c.note);
|
|
152
|
+
return {
|
|
153
|
+
vault: vault.symbol,
|
|
154
|
+
depositor,
|
|
155
|
+
status: c.status,
|
|
156
|
+
canDeposit: c.status === "NEEDS_APPROVAL",
|
|
157
|
+
findings,
|
|
158
|
+
balances,
|
|
159
|
+
quotes,
|
|
160
|
+
advisory,
|
|
161
|
+
measuredAtBlock: Number(block),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"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"}
|
package/dist/quote.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
import { type VaultEntry } from "./registry-schema.js";
|
|
3
|
+
import type { ReadClient } from "./client.js";
|
|
4
|
+
import { type PreflightResult } from "./preflight.js";
|
|
5
|
+
/**
|
|
6
|
+
* Pre-trade quotes. A quote is three things kept apart:
|
|
7
|
+
* what the chain says the trade would do now (preview/simulate), what a data provider says the
|
|
8
|
+
* and what this client cannot know (gas at inclusion, slippage the
|
|
9
|
+
* vault does not bound). Each is labelled as itself.
|
|
10
|
+
*/
|
|
11
|
+
export interface DepositQuote {
|
|
12
|
+
vault: string;
|
|
13
|
+
depositor: Address;
|
|
14
|
+
amountUsdc: string;
|
|
15
|
+
expectedShares: string;
|
|
16
|
+
sharePriceInAssets: string;
|
|
17
|
+
preflight: PreflightResult;
|
|
18
|
+
canProceed: boolean;
|
|
19
|
+
rejectReason?: string;
|
|
20
|
+
bounds: string;
|
|
21
|
+
validUntil: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function quoteDeposit(args: {
|
|
24
|
+
vault: VaultEntry;
|
|
25
|
+
depositor: Address;
|
|
26
|
+
assetsHuman: string;
|
|
27
|
+
client: ReadClient;
|
|
28
|
+
}): Promise<DepositQuote>;
|
|
29
|
+
export interface WithdrawQuote {
|
|
30
|
+
vault: string;
|
|
31
|
+
owner: Address;
|
|
32
|
+
amountUsdc: string;
|
|
33
|
+
sharesToBurn: string;
|
|
34
|
+
sharesHeld: string;
|
|
35
|
+
simulated: "OK" | "REVERTED" | "UNRESOLVED";
|
|
36
|
+
note: string;
|
|
37
|
+
/**
|
|
38
|
+
* The vault's OWN balance of the asset — what it can pay out in this block without unwinding a
|
|
39
|
+
* position. On Fusion with no instant-withdrawal fuses this is the hard ceiling on a withdrawal,
|
|
40
|
+
* and `maxWithdraw()` does not know it (measured 2026-09-13: maxWithdraw 10.01, liquid 0.80).
|
|
41
|
+
*/
|
|
42
|
+
instantLiquidity: string;
|
|
43
|
+
advisory: {
|
|
44
|
+
maxWithdrawRaw: string;
|
|
45
|
+
note: string;
|
|
46
|
+
};
|
|
47
|
+
queue: string;
|
|
48
|
+
canProceed: boolean;
|
|
49
|
+
}
|
|
50
|
+
export declare function quoteWithdraw(args: {
|
|
51
|
+
vault: VaultEntry;
|
|
52
|
+
owner: Address;
|
|
53
|
+
assetsHuman: string;
|
|
54
|
+
client: ReadClient;
|
|
55
|
+
}): Promise<WithdrawQuote>;
|
package/dist/quote.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { erc4626Abi } from "./abi/erc4626.js";
|
|
2
|
+
import { describeError } from "./redact.js";
|
|
3
|
+
import { parseAmount, formatAmount } from "./units.js";
|
|
4
|
+
import { preflightDeposit, extractRevert } from "./preflight.js";
|
|
5
|
+
export async function quoteDeposit(args) {
|
|
6
|
+
const { vault, depositor, client } = args;
|
|
7
|
+
const assets = parseAmount(args.assetsHuman, vault.asset.decimals, `deposit amount (${vault.asset.symbol})`);
|
|
8
|
+
const pre = await preflightDeposit({ vault, depositor, assetsHuman: args.assetsHuman, client });
|
|
9
|
+
const [previewShares, oneShareInAssets] = await Promise.all([
|
|
10
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "previewDeposit", args: [assets] }).catch(() => undefined),
|
|
11
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "convertToAssets", args: [10n ** BigInt(vault.shareDecimals)] }),
|
|
12
|
+
]);
|
|
13
|
+
const q = {
|
|
14
|
+
vault: vault.symbol,
|
|
15
|
+
depositor,
|
|
16
|
+
amountUsdc: `${formatAmount(assets, vault.asset.decimals)} ${vault.asset.symbol}`,
|
|
17
|
+
expectedShares: previewShares === undefined ? "unavailable (previewDeposit reverted)" : `${formatAmount(previewShares, vault.shareDecimals)} ${vault.symbol}`,
|
|
18
|
+
sharePriceInAssets: `${formatAmount(oneShareInAssets, vault.asset.decimals)} ${vault.asset.symbol} per share`,
|
|
19
|
+
preflight: pre,
|
|
20
|
+
canProceed: pre.canDeposit,
|
|
21
|
+
bounds: "ERC-4626 deposit has no on-chain min-shares parameter; the share count at inclusion may differ slightly from expectedShares as the share price moves. Gas: estimate × 1.5 (see gasAdvice on the built calls).",
|
|
22
|
+
validUntil: "this block — re-quote before signing if more than a few blocks pass",
|
|
23
|
+
};
|
|
24
|
+
if (!pre.canDeposit)
|
|
25
|
+
q.rejectReason = pre.findings.at(-1) ?? pre.status;
|
|
26
|
+
return q;
|
|
27
|
+
}
|
|
28
|
+
export async function quoteWithdraw(args) {
|
|
29
|
+
const { vault, owner, client } = args;
|
|
30
|
+
const assets = parseAmount(args.assetsHuman, vault.asset.decimals, `withdraw amount (${vault.asset.symbol})`);
|
|
31
|
+
const [held, toBurn, maxW, liquid] = await Promise.all([
|
|
32
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "balanceOf", args: [owner] }),
|
|
33
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "previewWithdraw", args: [assets] }).catch(() => undefined),
|
|
34
|
+
client.readContract({ address: vault.address, abi: erc4626Abi, functionName: "maxWithdraw", args: [owner] }).catch(() => undefined),
|
|
35
|
+
client.readContract({ address: vault.asset.address, abi: erc4626Abi, functionName: "balanceOf", args: [vault.address] }),
|
|
36
|
+
]);
|
|
37
|
+
let simulated = "UNRESOLVED";
|
|
38
|
+
let note = "";
|
|
39
|
+
try {
|
|
40
|
+
await client.simulateContract({ address: vault.address, abi: erc4626Abi, functionName: "withdraw", args: [assets, owner, owner], account: owner });
|
|
41
|
+
simulated = "OK";
|
|
42
|
+
note = "simulated withdraw() from the owner succeeds at this block";
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
const obs = extractRevert(e);
|
|
46
|
+
if (obs) {
|
|
47
|
+
simulated = "REVERTED";
|
|
48
|
+
// Withdraw reverts have their own causes; classifyRevert is the DEPOSIT classifier and its
|
|
49
|
+
// "approve first" wording is wrong here (it was reused, and told an agent to approve USDC
|
|
50
|
+
// when the vault simply had 0.80 USDC liquid — measured 2026-09-13 on a Fusion vault).
|
|
51
|
+
const reason = obs.reason ?? "";
|
|
52
|
+
if (toBurn !== undefined && held < toBurn) {
|
|
53
|
+
note = `withdraw() reverted: the owner holds ${formatAmount(held, vault.shareDecimals)} ${vault.symbol} against ${formatAmount(toBurn, vault.shareDecimals)} needed — insufficient shares. (${reason || obs.selector})`;
|
|
54
|
+
}
|
|
55
|
+
else if (/transfer amount exceeds balance|ERC20InsufficientBalance/i.test(reason) || liquid < assets) {
|
|
56
|
+
note = `withdraw() reverted: the vault holds ${formatAmount(liquid, vault.asset.decimals)} ${vault.asset.symbol} liquid against ${formatAmount(assets, vault.asset.decimals)} requested — this chassis pays withdrawals from its own balance in the same block; the rest is deployed and needs the fund to unwind first. Withdraw at most the liquid amount now, or wait. maxWithdraw() (${maxW === undefined ? "reverted" : formatAmount(maxW, vault.asset.decimals)}) does not know this.`;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
note = `withdraw() reverted "${reason || obs.selector}" — not a balance or liquidity shortfall; treat as a vault-side refusal.`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
note = `simulation did not return a definite revert: ${describeError(e, 160)}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
vault: vault.symbol,
|
|
68
|
+
owner,
|
|
69
|
+
amountUsdc: `${formatAmount(assets, vault.asset.decimals)} ${vault.asset.symbol}`,
|
|
70
|
+
sharesToBurn: toBurn === undefined ? "unavailable (previewWithdraw reverted)" : `${formatAmount(toBurn, vault.shareDecimals)} ${vault.symbol}`,
|
|
71
|
+
sharesHeld: `${formatAmount(held, vault.shareDecimals)} ${vault.symbol}`,
|
|
72
|
+
simulated,
|
|
73
|
+
note,
|
|
74
|
+
instantLiquidity: `${formatAmount(liquid, vault.asset.decimals)} ${vault.asset.symbol}`,
|
|
75
|
+
advisory: {
|
|
76
|
+
maxWithdrawRaw: maxW === undefined ? "reverted" : maxW.toString(),
|
|
77
|
+
note: "maxWithdraw() is ADVISORY: Morpho Vault V2 returns 0 for every owner by design; The simulation above is the verdict.",
|
|
78
|
+
},
|
|
79
|
+
queue: "none — this chassis settles withdrawals in the same transaction; no claim step",
|
|
80
|
+
canProceed: simulated === "OK",
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=quote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quote.js","sourceRoot":"","sources":["../src/quote.ts"],"names":[],"mappings":"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"}
|
package/dist/redact.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Describe an error for a tool result WITHOUT leaking the RPC endpoint.
|
|
3
|
+
*
|
|
4
|
+
* viem's error messages embed the transport URL (`URL: https://…/v2/<key>`) and the request body. A
|
|
5
|
+
* keyed provider URL (Alchemy, Infura) IS a secret, and every tool handler's failure path would
|
|
6
|
+
* otherwise paste it into the model's context — measured in the first review of this package:
|
|
7
|
+
* `preflightDeposit` with a fake Alchemy key → `findings[]` contained the key verbatim.
|
|
8
|
+
*
|
|
9
|
+
* Preference order: viem's own `shortMessage` (never carries the URL), followed by viem's `details`
|
|
10
|
+
* when present — that is where a JSON-RPC error body's own sentence lives (a provider at its monthly
|
|
11
|
+
* cap says "Monthly capacity limit exceeded" there, and `shortMessage` alone is the useless
|
|
12
|
+
* "RPC Request failed."; measured in review) → the first line of the message with any `URL:` /
|
|
13
|
+
* `Request body:` / `http(s)://…` content masked → the error's name.
|
|
14
|
+
*/
|
|
15
|
+
export declare function describeError(e: unknown, max?: number): string;
|
|
16
|
+
/** Register the source of known-secret values. Called by the MCP server at build time. */
|
|
17
|
+
export declare function registerSecretSource(f: () => readonly string[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Mask literal secret VALUES wherever they appear, in any shape.
|
|
20
|
+
*
|
|
21
|
+
* 🔴 This is the PRIMARY defence and the pattern rules below are the backstop — the inverse of the
|
|
22
|
+
* original design, which had only a backstop. Measured by review against a real viem client
|
|
23
|
+
* and a real HTTP server: a provider that rejects a key and ECHOES IT BACK in the response body
|
|
24
|
+
* puts it in viem's `Details:` line as prose inside JSON — no scheme, no errno, no header keyword,
|
|
25
|
+
* so every shape rule misses it and the key reaches tool output. Patterns chase shapes forever;
|
|
26
|
+
* that was the third new shape in one day. We KNOW the value (`rpcUrlFromEnv` resolved it), so we
|
|
27
|
+
* match on the literal we are protecting instead of on where we guessed it would sit.
|
|
28
|
+
*
|
|
29
|
+
* Short values are ignored: a 2-character path segment like `v2` is not a secret and masking it
|
|
30
|
+
* would destroy every message it appears in.
|
|
31
|
+
*
|
|
32
|
+
* ⚠️ THE BOUNDARY IS CHOSEN, NOT MISSED. Value matching masks the literal and its percent-decoded
|
|
33
|
+
* form. It does NOT mask an arbitrary re-encoding — an upper-cased key, a base64 of the key, or one
|
|
34
|
+
* split across whitespace. No implementation can, and attempting it would over-redact wildly; those
|
|
35
|
+
* are the residual the shape rules below exist for (review).
|
|
36
|
+
*
|
|
37
|
+
* ⚠️ VALUE MASKING IS A PROPERTY OF THE SERVER, NOT OF THIS LIBRARY. `registerSecretSource` is
|
|
38
|
+
* called by the MCP server in `buildServer()`. A consumer importing `describeError`/`redactEndpoints`
|
|
39
|
+
* directly gets `secretSource = () => []` and therefore the shape rules only — which degrades safely
|
|
40
|
+
* and is the documented backstop, but is not inherited.
|
|
41
|
+
*/
|
|
42
|
+
export declare function redactSecrets(s: string, secrets?: readonly string[]): string;
|
|
43
|
+
/** Mask every http(s) URL and the viem `URL:` / `Request body:` lines in a string. Exported for the tool boundary. */
|
|
44
|
+
export declare function redactEndpoints(s: string): string;
|
package/dist/redact.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Describe an error for a tool result WITHOUT leaking the RPC endpoint.
|
|
3
|
+
*
|
|
4
|
+
* viem's error messages embed the transport URL (`URL: https://…/v2/<key>`) and the request body. A
|
|
5
|
+
* keyed provider URL (Alchemy, Infura) IS a secret, and every tool handler's failure path would
|
|
6
|
+
* otherwise paste it into the model's context — measured in the first review of this package:
|
|
7
|
+
* `preflightDeposit` with a fake Alchemy key → `findings[]` contained the key verbatim.
|
|
8
|
+
*
|
|
9
|
+
* Preference order: viem's own `shortMessage` (never carries the URL), followed by viem's `details`
|
|
10
|
+
* when present — that is where a JSON-RPC error body's own sentence lives (a provider at its monthly
|
|
11
|
+
* cap says "Monthly capacity limit exceeded" there, and `shortMessage` alone is the useless
|
|
12
|
+
* "RPC Request failed."; measured in review) → the first line of the message with any `URL:` /
|
|
13
|
+
* `Request body:` / `http(s)://…` content masked → the error's name.
|
|
14
|
+
*/
|
|
15
|
+
export function describeError(e, max = 200) {
|
|
16
|
+
const anyE = e;
|
|
17
|
+
let s;
|
|
18
|
+
if (anyE && typeof anyE.shortMessage === "string" && anyE.shortMessage.length > 0) {
|
|
19
|
+
s = anyE.shortMessage;
|
|
20
|
+
if (typeof anyE.details === "string" && anyE.details.length > 0 && !s.includes(anyE.details))
|
|
21
|
+
s = `${s} ${anyE.details}`;
|
|
22
|
+
}
|
|
23
|
+
else if (anyE && typeof anyE.message === "string" && anyE.message.length > 0)
|
|
24
|
+
s = anyE.message;
|
|
25
|
+
else
|
|
26
|
+
s = String(e);
|
|
27
|
+
s = redactEndpoints(s);
|
|
28
|
+
const firstLine = s.split("\n").find((l) => l.trim().length > 0) ?? s;
|
|
29
|
+
return firstLine.length > max ? `${firstLine.slice(0, max)}…` : firstLine;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The VALUES we are protecting, supplied by whoever resolved them. Registered rather than passed,
|
|
33
|
+
* so every existing `redactEndpoints`/`describeError` call site is covered without threading a
|
|
34
|
+
* parameter through the library. A FUNCTION, not an array: the environment can change inside a
|
|
35
|
+
* process (tests do it), and a snapshot taken at import time would go stale.
|
|
36
|
+
*/
|
|
37
|
+
let secretSource = () => [];
|
|
38
|
+
/** Register the source of known-secret values. Called by the MCP server at build time. */
|
|
39
|
+
export function registerSecretSource(f) {
|
|
40
|
+
secretSource = f;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Mask literal secret VALUES wherever they appear, in any shape.
|
|
44
|
+
*
|
|
45
|
+
* 🔴 This is the PRIMARY defence and the pattern rules below are the backstop — the inverse of the
|
|
46
|
+
* original design, which had only a backstop. Measured by review against a real viem client
|
|
47
|
+
* and a real HTTP server: a provider that rejects a key and ECHOES IT BACK in the response body
|
|
48
|
+
* puts it in viem's `Details:` line as prose inside JSON — no scheme, no errno, no header keyword,
|
|
49
|
+
* so every shape rule misses it and the key reaches tool output. Patterns chase shapes forever;
|
|
50
|
+
* that was the third new shape in one day. We KNOW the value (`rpcUrlFromEnv` resolved it), so we
|
|
51
|
+
* match on the literal we are protecting instead of on where we guessed it would sit.
|
|
52
|
+
*
|
|
53
|
+
* Short values are ignored: a 2-character path segment like `v2` is not a secret and masking it
|
|
54
|
+
* would destroy every message it appears in.
|
|
55
|
+
*
|
|
56
|
+
* ⚠️ THE BOUNDARY IS CHOSEN, NOT MISSED. Value matching masks the literal and its percent-decoded
|
|
57
|
+
* form. It does NOT mask an arbitrary re-encoding — an upper-cased key, a base64 of the key, or one
|
|
58
|
+
* split across whitespace. No implementation can, and attempting it would over-redact wildly; those
|
|
59
|
+
* are the residual the shape rules below exist for (review).
|
|
60
|
+
*
|
|
61
|
+
* ⚠️ VALUE MASKING IS A PROPERTY OF THE SERVER, NOT OF THIS LIBRARY. `registerSecretSource` is
|
|
62
|
+
* called by the MCP server in `buildServer()`. A consumer importing `describeError`/`redactEndpoints`
|
|
63
|
+
* directly gets `secretSource = () => []` and therefore the shape rules only — which degrades safely
|
|
64
|
+
* and is the documented backstop, but is not inherited.
|
|
65
|
+
*/
|
|
66
|
+
export function redactSecrets(s, secrets = secretSource()) {
|
|
67
|
+
let out = s;
|
|
68
|
+
for (const sec of secrets) {
|
|
69
|
+
if (!sec || sec.length < 8)
|
|
70
|
+
continue;
|
|
71
|
+
out = out.split(sec).join("<redacted>"); // split/join: no regex escaping hazard
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
/** Mask every http(s) URL and the viem `URL:` / `Request body:` lines in a string. Exported for the tool boundary. */
|
|
76
|
+
export function redactEndpoints(s) {
|
|
77
|
+
return redactSecrets(s)
|
|
78
|
+
// ANY scheme://… — not just http(s). A ws:// or wss:// endpoint carries the same key.
|
|
79
|
+
.replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s"'`)\]]+/gi, "<rpc endpoint>")
|
|
80
|
+
// DNS and socket failures name a BARE host, sometimes with the keyed path still attached
|
|
81
|
+
// (`getaddrinfo ENOTFOUND base-mainnet.g.alchemy.com/v2/KEY`) — no scheme for the rule above.
|
|
82
|
+
// ⚠️ The token after an errno must be HOST-SHAPED. `\S+` ate whatever followed: `ETIMEDOUT
|
|
83
|
+
// after 30000ms` became `ETIMEDOUT <rpc endpoint> 30000ms`, fabricating a redaction in a
|
|
84
|
+
// message containing no endpoint at all (review). Loopback and private ranges are
|
|
85
|
+
// never secrets and are exactly what a developer needs to see (anvil not running).
|
|
86
|
+
.replace(/\b(ENOTFOUND|EAI_AGAIN|ECONNREFUSED|ECONNRESET|ETIMEDOUT)\s+((?:[a-z0-9-]+\.)+[a-z]{2,}(?::\d+)?(?:\/\S*)?)/gi, (m, errno, host) => /^(localhost|127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.)/i.test(host) ? m : `${errno} <rpc endpoint>`)
|
|
87
|
+
// a key can travel as a header rather than in the URL
|
|
88
|
+
.replace(/\b(x-api-key|api[-_]?key|authorization)\b\s*[:=]\s*.*/gi, "$1: <redacted>")
|
|
89
|
+
.replace(/^\s*(URL|Request body|Raw Call Arguments):.*$/gim, "")
|
|
90
|
+
.replace(/\n{2,}/g, "\n");
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAAC,CAAU,EAAE,GAAG,GAAG,GAAG;IACjD,MAAM,IAAI,GAAG,CAA4F,CAAC;IAC1G,IAAI,CAAS,CAAC;IACd,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClF,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC;QACtB,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;IAC3H,CAAC;SAAM,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;;QAC5F,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACtE,OAAO,SAAS,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5E,CAAC;AAED;;;;;GAKG;AACH,IAAI,YAAY,GAA4B,GAAG,EAAE,CAAC,EAAE,CAAC;AAErD,0FAA0F;AAC1F,MAAM,UAAU,oBAAoB,CAAC,CAA0B;IAC7D,YAAY,GAAG,CAAC,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,aAAa,CAAC,CAAS,EAAE,UAA6B,YAAY,EAAE;IAClF,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QACrC,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,uCAAuC;IAClF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,sHAAsH;AACtH,MAAM,UAAU,eAAe,CAAC,CAAS;IACvC,OAAO,aAAa,CAAC,CAAC,CAAC;QACrB,sFAAsF;SACrF,OAAO,CAAC,wCAAwC,EAAE,gBAAgB,CAAC;QACpE,yFAAyF;QACzF,8FAA8F;QAC9F,2FAA2F;QAC3F,yFAAyF;QACzF,kFAAkF;QAClF,mFAAmF;SAClF,OAAO,CACN,+GAA+G,EAC/G,CAAC,CAAC,EAAE,KAAa,EAAE,IAAY,EAAE,EAAE,CACjC,+DAA+D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,iBAAiB,CAC7G;QACD,sDAAsD;SACrD,OAAO,CAAC,yDAAyD,EAAE,gBAAgB,CAAC;SACpF,OAAO,CAAC,kDAAkD,EAAE,EAAE,CAAC;SAC/D,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const chassisSchema: z.ZodEnum<{
|
|
3
|
+
"morpho-v2": "morpho-v2";
|
|
4
|
+
fusion: "fusion";
|
|
5
|
+
enzyme: "enzyme";
|
|
6
|
+
}>;
|
|
7
|
+
export type Chassis = z.infer<typeof chassisSchema>;
|
|
8
|
+
/**
|
|
9
|
+
* Which chassis expose a standard ERC-4626 `deposit`/`redeem` to a depositor. Enzyme does not
|
|
10
|
+
* (`buyShares` via the comptroller), which is what every refusal path in this client is measured
|
|
11
|
+
* against: build, pre-flight, the MCP boundary and the default-vault rule all discriminate on it.
|
|
12
|
+
*/
|
|
13
|
+
export declare const erc4626Chassis: ReadonlySet<Chassis>;
|
|
14
|
+
/**
|
|
15
|
+
* Whose contract the depositor's USDC actually enters.
|
|
16
|
+
* - `morpho`: a public third-party Morpho vault, reached directly. No row uses it today (Tempora vaults only).
|
|
17
|
+
* - `tempora`: a Tempora fund vault (the product; each fund joins as it goes live).
|
|
18
|
+
*/
|
|
19
|
+
export declare const backendSchema: z.ZodEnum<{
|
|
20
|
+
morpho: "morpho";
|
|
21
|
+
tempora: "tempora";
|
|
22
|
+
}>;
|
|
23
|
+
export type Backend = z.infer<typeof backendSchema>;
|
|
24
|
+
/**
|
|
25
|
+
* Whether a third party can deposit is a MEASUREMENT, not a config flag. `maxDeposit()` lies on
|
|
26
|
+
* two of the three live chassis (Fusion returns uint256.max behind a whitelist; Morpho V2 returns 0
|
|
27
|
+
* on an open vault), so the only honest value is the result of a simulated `deposit` from a
|
|
28
|
+
* stranger, stamped with when and how it was taken.
|
|
29
|
+
*/
|
|
30
|
+
export declare const depositOpenSchema: z.ZodObject<{
|
|
31
|
+
open: z.ZodBoolean;
|
|
32
|
+
method: z.ZodLiteral<"simulated-deposit-from-stranger">;
|
|
33
|
+
measuredAtBlock: z.ZodNumber;
|
|
34
|
+
measuredAtIso: z.ZodString;
|
|
35
|
+
reason: z.ZodOptional<z.ZodEnum<{
|
|
36
|
+
WHITELIST_GATED: "WHITELIST_GATED";
|
|
37
|
+
NOT_ALLOWLISTED: "NOT_ALLOWLISTED";
|
|
38
|
+
NOT_ERC4626: "NOT_ERC4626";
|
|
39
|
+
PAUSED: "PAUSED";
|
|
40
|
+
REVERTED_OTHER: "REVERTED_OTHER";
|
|
41
|
+
}>>;
|
|
42
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
export declare const vaultEntrySchema: z.ZodObject<{
|
|
45
|
+
symbol: z.ZodString;
|
|
46
|
+
name: z.ZodString;
|
|
47
|
+
warning: z.ZodString;
|
|
48
|
+
chainId: z.ZodLiteral<8453>;
|
|
49
|
+
address: z.ZodPipe<z.ZodString & z.ZodType<`0x${string}`, string, z.core.$ZodTypeInternals<`0x${string}`, string>>, z.ZodTransform<`0x${string}`, `0x${string}`>>;
|
|
50
|
+
chassis: z.ZodEnum<{
|
|
51
|
+
"morpho-v2": "morpho-v2";
|
|
52
|
+
fusion: "fusion";
|
|
53
|
+
enzyme: "enzyme";
|
|
54
|
+
}>;
|
|
55
|
+
backend: z.ZodEnum<{
|
|
56
|
+
morpho: "morpho";
|
|
57
|
+
tempora: "tempora";
|
|
58
|
+
}>;
|
|
59
|
+
isDefault: z.ZodDefault<z.ZodBoolean>;
|
|
60
|
+
asset: z.ZodObject<{
|
|
61
|
+
address: z.ZodPipe<z.ZodString & z.ZodType<`0x${string}`, string, z.core.$ZodTypeInternals<`0x${string}`, string>>, z.ZodTransform<`0x${string}`, `0x${string}`>>;
|
|
62
|
+
symbol: z.ZodString;
|
|
63
|
+
decimals: z.ZodNumber;
|
|
64
|
+
}, z.core.$strip>;
|
|
65
|
+
shareDecimals: z.ZodNumber;
|
|
66
|
+
depositOpen: z.ZodObject<{
|
|
67
|
+
open: z.ZodBoolean;
|
|
68
|
+
method: z.ZodLiteral<"simulated-deposit-from-stranger">;
|
|
69
|
+
measuredAtBlock: z.ZodNumber;
|
|
70
|
+
measuredAtIso: z.ZodString;
|
|
71
|
+
reason: z.ZodOptional<z.ZodEnum<{
|
|
72
|
+
WHITELIST_GATED: "WHITELIST_GATED";
|
|
73
|
+
NOT_ALLOWLISTED: "NOT_ALLOWLISTED";
|
|
74
|
+
NOT_ERC4626: "NOT_ERC4626";
|
|
75
|
+
PAUSED: "PAUSED";
|
|
76
|
+
REVERTED_OTHER: "REVERTED_OTHER";
|
|
77
|
+
}>>;
|
|
78
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
79
|
+
}, z.core.$strip>;
|
|
80
|
+
deployedAtBlock: z.ZodOptional<z.ZodNumber>;
|
|
81
|
+
notes: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
82
|
+
}, z.core.$strict>;
|
|
83
|
+
export type VaultEntry = z.infer<typeof vaultEntrySchema>;
|
|
84
|
+
export declare const registrySchema: z.ZodObject<{
|
|
85
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
86
|
+
reconciledAtIso: z.ZodString;
|
|
87
|
+
vaults: z.ZodArray<z.ZodObject<{
|
|
88
|
+
symbol: z.ZodString;
|
|
89
|
+
name: z.ZodString;
|
|
90
|
+
warning: z.ZodString;
|
|
91
|
+
chainId: z.ZodLiteral<8453>;
|
|
92
|
+
address: z.ZodPipe<z.ZodString & z.ZodType<`0x${string}`, string, z.core.$ZodTypeInternals<`0x${string}`, string>>, z.ZodTransform<`0x${string}`, `0x${string}`>>;
|
|
93
|
+
chassis: z.ZodEnum<{
|
|
94
|
+
"morpho-v2": "morpho-v2";
|
|
95
|
+
fusion: "fusion";
|
|
96
|
+
enzyme: "enzyme";
|
|
97
|
+
}>;
|
|
98
|
+
backend: z.ZodEnum<{
|
|
99
|
+
morpho: "morpho";
|
|
100
|
+
tempora: "tempora";
|
|
101
|
+
}>;
|
|
102
|
+
isDefault: z.ZodDefault<z.ZodBoolean>;
|
|
103
|
+
asset: z.ZodObject<{
|
|
104
|
+
address: z.ZodPipe<z.ZodString & z.ZodType<`0x${string}`, string, z.core.$ZodTypeInternals<`0x${string}`, string>>, z.ZodTransform<`0x${string}`, `0x${string}`>>;
|
|
105
|
+
symbol: z.ZodString;
|
|
106
|
+
decimals: z.ZodNumber;
|
|
107
|
+
}, z.core.$strip>;
|
|
108
|
+
shareDecimals: z.ZodNumber;
|
|
109
|
+
depositOpen: z.ZodObject<{
|
|
110
|
+
open: z.ZodBoolean;
|
|
111
|
+
method: z.ZodLiteral<"simulated-deposit-from-stranger">;
|
|
112
|
+
measuredAtBlock: z.ZodNumber;
|
|
113
|
+
measuredAtIso: z.ZodString;
|
|
114
|
+
reason: z.ZodOptional<z.ZodEnum<{
|
|
115
|
+
WHITELIST_GATED: "WHITELIST_GATED";
|
|
116
|
+
NOT_ALLOWLISTED: "NOT_ALLOWLISTED";
|
|
117
|
+
NOT_ERC4626: "NOT_ERC4626";
|
|
118
|
+
PAUSED: "PAUSED";
|
|
119
|
+
REVERTED_OTHER: "REVERTED_OTHER";
|
|
120
|
+
}>>;
|
|
121
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
122
|
+
}, z.core.$strip>;
|
|
123
|
+
deployedAtBlock: z.ZodOptional<z.ZodNumber>;
|
|
124
|
+
notes: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
125
|
+
}, z.core.$strict>>;
|
|
126
|
+
}, z.core.$strict>;
|
|
127
|
+
export type Registry = z.infer<typeof registrySchema>;
|