@gvnrdao/dh-sdk 0.0.320 → 0.0.324

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.
@@ -39,3 +39,24 @@ export interface DecodedRevert {
39
39
  export declare function decodeQuantumRevert(e: any): DecodedRevert;
40
40
  /** True iff the error decodes to `DeadZoneViolation()` from any provider nesting. */
41
41
  export declare function isDeadZoneViolation(e: any): boolean;
42
+ /**
43
+ * Whether a failed quantum-signed operation can be safely retried with a fresh
44
+ * signature. Shared by the payment and BTC-withdrawal retry loops so the two paths
45
+ * cannot drift apart again (they had: withdrawal recognised only
46
+ * `QuantumOutsideWindow`, and never decoded a mined revert at all, so the mainnet
47
+ * `DeadZoneViolation` of 2026-08-07 surfaced as a hard failure on a flow that
48
+ * payments recover from automatically).
49
+ *
50
+ * **Retryable** — the operation provably did not happen:
51
+ * - a pre-send simulation quantum error (nothing was ever broadcast), or
52
+ * - a mined revert (`status === 0`): atomic, so no funds moved, no authorization
53
+ * was recorded, and the quantum replay lane is untouched. Re-signing is safe.
54
+ *
55
+ * **NOT retryable** — the outcome is unknown, so a resubmit risks double-spending:
56
+ * - a confirmation timeout (the tx may still be pending), or
57
+ * - a confirmation failure with no receipt (transport died mid-wait).
58
+ *
59
+ * Callers MUST therefore only produce a "Transaction reverted" message after
60
+ * observing a receipt with `status === 0`.
61
+ */
62
+ export declare function isRetryableQuantumFailure(message: string | null | undefined): boolean;
@@ -37,13 +37,21 @@ export declare class QuantumRevertError extends Error {
37
37
  constructor(errorName: string | null, selector: string | null, data: string | null, cause: unknown);
38
38
  }
39
39
  export interface SafeQuantumSubmissionOpts {
40
- /** Provider used for the `eth_call` simulation (only `.call` is needed). */
40
+ /**
41
+ * Provider used for the `eth_call` simulation and — when it exposes `getBlock`
42
+ * (every ethers provider does) — for the dead-zone gate's chain clock. Without
43
+ * `getBlock` the gate silently degrades to the client's local clock, which on the
44
+ * browser path is exactly the skew we are trying to design out.
45
+ */
41
46
  provider: {
42
47
  call(tx: {
43
48
  to: string;
44
49
  from: string;
45
50
  data: string;
46
51
  }): Promise<string>;
52
+ getBlock?(blockTag: string): Promise<{
53
+ timestamp: number;
54
+ } | null | undefined>;
47
55
  };
48
56
  /** Target contract address. */
49
57
  to: string;
@@ -59,6 +67,12 @@ export interface SafeQuantumSubmissionOpts {
59
67
  now?: () => number;
60
68
  /** Sleep seam, forwarded to the gate. */
61
69
  sleep?: (ms: number) => Promise<void>;
70
+ /**
71
+ * Chain-clock seam (latest mined block timestamp, whole seconds). Defaults to
72
+ * `provider.getBlock("latest")` when the provider exposes it. Pass explicitly to
73
+ * override in tests, or `null`-resolving to force the local-clock fallback.
74
+ */
75
+ chainNow?: () => Promise<number | null>;
62
76
  /** Debug sink; called with human-readable progress lines. */
63
77
  onDebug?: (msg: string) => void;
64
78
  /**
@@ -79,7 +93,9 @@ export interface SafeQuantumSubmissionOpts {
79
93
  * 1. **Gate** (`awaitSafeSubmissionWindow`): a NEXT-quantum signature mined in
80
94
  * the last DEAD_ZONE_SECONDS of the current quantum reverts
81
95
  * `DeadZoneViolation()` on-chain, so defer the send across the boundary
82
- * when inclusion could land there.
96
+ * when inclusion could land there. Anchored on `provider.getBlock("latest")`
97
+ * — the same clock `block.timestamp` comes from — so a skewed client clock
98
+ * cannot wave a doomed send through.
83
99
  * 2. **Simulate** (`eth_call`) and route the outcome:
84
100
  * - success → safe to broadcast.
85
101
  * - `DeadZoneViolation()` → `eth_call` runs against the LATEST block's
@@ -87,7 +103,11 @@ export interface SafeQuantumSubmissionOpts {
87
103
  * the signature is already the CURRENT quantum in real time it can never
88
104
  * be dead-zoned on-chain — stale-block artifact, proceed. Otherwise the
89
105
  * signature is still NEXT near the boundary: re-gate across it and
90
- * re-simulate (bounded by `maxResimulations`).
106
+ * re-simulate (bounded by `maxResimulations`). This artifact test must use
107
+ * the LOCAL clock, not the chain head: the chain head IS the stale value
108
+ * the simulation reverted against, so anchoring it there would classify
109
+ * every artifact as real. A fast client clock wrongly reaching "artifact"
110
+ * is caught by the chain-anchored final re-gate in step 3.
91
111
  * - any other DECODABLE revert → throw `QuantumRevertError` (fail fast: no
92
112
  * broadcast, no gas burned on a doomed tx).
93
113
  * - UNDECODABLE failure (no revert data: RPC timeout, rate limit, provider
@@ -28,13 +28,38 @@
28
28
  */
29
29
  export declare const QUANTUM_WINDOW_SECONDS = 60;
30
30
  export declare const DEAD_ZONE_SECONDS = 8;
31
+ /** Ethereum slot cadence. Block timestamps are multiples of 12s from genesis. */
32
+ export declare const SLOT_SECONDS = 12;
33
+ /**
34
+ * Slots of inclusion latency we insure against. A broadcast is NOT guaranteed to
35
+ * land in the very next slot: builders skip low-tip transactions and slots are
36
+ * missed, so 2–3 slot inclusion is routine on mainnet.
37
+ *
38
+ * Sized from a real mainnet failure (tx 0x5933d64d…, 2026-08-07): a NEXT-quantum
39
+ * withdrawal was broadcast with ~25s to the boundary — outside the old 16s budget,
40
+ * so the gate let it through — then sat out one near-empty block (0.0007 gwei tip)
41
+ * and was mined 24s later at second 59, one second inside the trailing dead zone.
42
+ * `DeadZoneViolation()`. 3 slots (36s) covers that skip with a slot to spare.
43
+ */
44
+ export declare const INCLUSION_SLOT_TOLERANCE = 3;
31
45
  /**
32
46
  * Seconds of mainnet inclusion latency we insure against BEFORE the quantum
33
- * boundary. ~1.3 of Ethereum's 12s slots. A NEXT/PAST-quantum send within
47
+ * boundary. A NEXT/PAST-quantum send within
34
48
  * `DEAD_ZONE_SECONDS + INCLUSION_LATENCY_BUDGET` of the boundary is deferred so it
35
49
  * cannot be mined in the trailing dead zone `[boundary - 8, boundary)`.
50
+ *
51
+ * Used by the LOCAL-CLOCK fallback path only. When a chain clock is available the
52
+ * gate reasons in whole slots instead (see `awaitSafeSubmissionWindow`), which is
53
+ * both tighter and immune to client clock skew.
36
54
  */
37
- export declare const INCLUSION_LATENCY_BUDGET = 16;
55
+ export declare const INCLUSION_LATENCY_BUDGET: number;
56
+ /**
57
+ * Cap on chain-clock polls while deferring across a boundary. Each poll sleeps at
58
+ * most one slot, so this bounds a deferral at ~`MAX_GATE_POLLS` slots — comfortably
59
+ * more than the ~44s worst-case wait, while refusing to spin forever on a stuck or
60
+ * lying RPC.
61
+ */
62
+ export declare const MAX_GATE_POLLS = 12;
38
63
  /**
39
64
  * Seconds of client-clock-vs-chain skew guard we add AFTER the boundary when
40
65
  * deferring. A CURRENT-quantum signature is never dead-zoned, so this only needs to
@@ -108,6 +133,16 @@ export interface SafeSubmissionOptions {
108
133
  now?: () => number;
109
134
  /** Sleeps for `ms` milliseconds. Defaults to `setTimeout`. */
110
135
  sleep?: (ms: number) => Promise<void>;
136
+ /**
137
+ * Latest MINED block timestamp, in whole seconds — the only clock the on-chain
138
+ * dead-zone rule is expressed in. Supply this wherever a provider is available:
139
+ * the local-clock path below cannot see client clock skew, and the primary
140
+ * consumer of this gate is a browser wallet whose clock is not trustworthy.
141
+ *
142
+ * Resolve to `null` (or throw) to fall back to the local clock — a flaky RPC
143
+ * must never block a valid money-path operation.
144
+ */
145
+ chainNow?: () => Promise<number | null>;
111
146
  }
112
147
  export interface SafeSubmissionResult {
113
148
  /** Whether the send was deferred across the quantum boundary. */
@@ -136,6 +171,18 @@ export interface SafeSubmissionResult {
136
171
  * acceptance window (`QuantumOutsideWindow`). They must be handled by re-signing
137
172
  * upstream. In practice the SDK only ever signs CURRENT/NEXT.
138
173
  *
174
+ * Two implementations, same predicate:
175
+ *
176
+ * - **Chain-anchored** (`opts.chainNow` supplied — always prefer this): reasons in
177
+ * whole slots off the latest mined block timestamp `H`, the same clock the
178
+ * contract's `block.timestamp` comes from. A broadcast issued now can only be
179
+ * mined at `H + 12k`, so it is safe iff EVERY plausible `k` lands clear of the
180
+ * dead zone. No client clock is consulted at all — only sleep *durations*, which
181
+ * are immune to an offset clock.
182
+ * - **Local-clock fallback** (no `chainNow`, or the chain read failed): the original
183
+ * `Date.now()` math with the widened {@link INCLUSION_LATENCY_BUDGET}. Retained so
184
+ * a flaky RPC degrades rather than blocks, but it cannot see client clock skew.
185
+ *
139
186
  * @param quantumTimestamp The quantum timestamp embedded in the LIT-signed payload.
140
187
  * @returns whether it waited, and for how long.
141
188
  */
@@ -0,0 +1,154 @@
1
+ /**
2
+ * "Is this Safe delegated, and to which agent?" — the single implementation.
3
+ *
4
+ * Every consumer that needs to know whether a multi-sig Safe can act through an
5
+ * AgentModule asks this: the frontend gate, the CLI, MCP. It was previously
6
+ * reimplemented per-consumer, and this session shows what that costs — the same
7
+ * invariant lived in two places twice, and both times only one copy was fixed
8
+ * when it turned out to be wrong.
9
+ *
10
+ * ── WHAT MAKES A DELEGATION REAL ───────────────────────────────────────────
11
+ * A module counts only when ALL of these hold:
12
+ * - it is enabled on the Safe (`getModulesPaginated`)
13
+ * - `safe()` is that Safe and `positionManager()` is this chain's
14
+ * - `AgentModuleFactory.isFromFactory(module)` claims it
15
+ *
16
+ * That last one is not decoration. The agent-module-executor Lit Action refuses
17
+ * at its second guard to sign through any module the factory disowns, so an
18
+ * unprovenanced module is one nothing can ever use. Measured on the Sepolia test
19
+ * Safe (2026-08-05): it carried a pre-factory module from an old e2e harness,
20
+ * correctly bound and pointing at an EOA agent nothing could sign with — and
21
+ * without the provenance check it read as a working delegation.
22
+ *
23
+ * ── WHY THE ANSWER IS TRI-STATE ────────────────────────────────────────────
24
+ * `unknown` is not a rounding error, it is the whole safety property. Callers
25
+ * act on "not-delegated" by BLOCKING loan creation, so a check that merely
26
+ * failed to run must never produce it. The distinctions below are load-bearing
27
+ * and were each learned from a live failure:
28
+ *
29
+ * - `safe()` unreadable → unknown. Every module here answers it, so a
30
+ * failure means we could not read, not that the
31
+ * module is wrong.
32
+ * - `positionManager()` absent → EVIDENCE. It is the discriminator (absent on
33
+ * VaultProvisionerModule), so a revert is a real
34
+ * answer: not an AgentModule.
35
+ * - provenance unreadable → unknown.
36
+ * - no factory on this chain → unknown, never "not-delegated". Mainnet has
37
+ * no AgentModuleFactory, and reporting that as
38
+ * not-delegated blocked vault creation behind a
39
+ * ceremony that cannot run there at all.
40
+ *
41
+ * ── NOT A SUBSTITUTE FOR THE LIT ACTION'S OWN CHECKS ───────────────────────
42
+ * The executor re-derives provenance and the registry binding itself. It must:
43
+ * it is the enforcement point and cannot trust anything a caller computed.
44
+ * Sharing this code with it would weaken it, so it stays independent.
45
+ */
46
+ import { type Provider } from "ethers";
47
+ export type SafeDelegationStatus = "delegated" | "not-delegated" | "unknown";
48
+ export interface SafeAgentDelegation {
49
+ /** Lowercased Safe the answer describes. */
50
+ safeAddress: string;
51
+ /** Chain the answer describes — a module on one chain says nothing about another. */
52
+ chainId: number;
53
+ status: SafeDelegationStatus;
54
+ /** The AgentModule, or null when there isn't one (or we could not tell). */
55
+ moduleAddress: string | null;
56
+ /**
57
+ * The agent EOA that SIGNS AND PAYS for delegated operations — read from the
58
+ * module, not the registry. They should agree, but the module's `agent()` is
59
+ * who `onlyAgent` actually admits, so it is the truth about who needs gas.
60
+ */
61
+ agentAddress: string | null;
62
+ /** Registry expiry for the Safe's agent record, when readable. */
63
+ validUntil: number | null;
64
+ /** True when the Safe's module list exceeded one page — the answer may be partial. */
65
+ truncated: boolean;
66
+ }
67
+ /**
68
+ * Resolve the Safe's agent delegation from chain state.
69
+ *
70
+ * `provider` is the CALLER'S, deliberately: it must read the chain the caller is
71
+ * actually on. Resolving it internally would let an SDK configured for one chain
72
+ * answer about another, which is the exact confusion that made a live Sepolia
73
+ * delegation look absent while the wallet had silently defaulted to mainnet.
74
+ *
75
+ * Never throws — every failure resolves to `unknown`.
76
+ */
77
+ export declare function getSafeAgentDelegation(params: {
78
+ safeAddress: string;
79
+ chainId: number;
80
+ provider: Provider;
81
+ }): Promise<SafeAgentDelegation>;
82
+ /** One entry in a Safe transaction batch. */
83
+ export interface SafeDelegationCall {
84
+ to: string;
85
+ data: string;
86
+ value: string;
87
+ }
88
+ export interface SafeAgentDelegationDisablePlan {
89
+ /**
90
+ * The calls, in execution order. They must land ATOMICALLY — see below for
91
+ * why a half-applied revocation is worse than none.
92
+ */
93
+ calls: SafeDelegationCall[];
94
+ /** The module being removed. */
95
+ moduleAddress: string;
96
+ /** The agent being revoked, when the module could name it. */
97
+ agentAddress: string | null;
98
+ /** The predecessor `disableModule` needs — SENTINEL when the module heads the list. */
99
+ prevModule: string;
100
+ }
101
+ /**
102
+ * Build the calls that undo a Safe's agent delegation.
103
+ *
104
+ * THE COUNTERPART TO {@link getSafeAgentDelegation}, and here rather than in any
105
+ * one consumer for the reason that reader is here: it needs the same module
106
+ * enumeration, and a second copy of that walk is how the two drift. The
107
+ * frontend, the CLI and MCP all revoke the same way or none of them can be
108
+ * trusted to.
109
+ *
110
+ * ── WHY TWO CALLS ──────────────────────────────────────────────────────────
111
+ * Neither alone is a full revocation:
112
+ *
113
+ * - `revokeAgent` flips the registry record to Revoked, which is what the Lit
114
+ * Action's `can*` gates read. After it, no mint/repay/renew/withdraw can be
115
+ * authorized for this agent.
116
+ * - `disableModule` removes the on-chain execution path, and it is the one
117
+ * that matters for the calls needing NO validator attestation: with the
118
+ * module still enabled, a live agent key can forward `approve` and
119
+ * `setPositionDelegate` through the Safe whatever the registry says
120
+ * (`AgentModule.execute` checks only `msg.sender == agent` and its own
121
+ * selector whitelist).
122
+ *
123
+ * Submit them as ONE batch. Revoking the record while leaving the module
124
+ * enabled reads as "not delegated" everywhere in the UI while those unattested
125
+ * paths stay open — the worst of both states.
126
+ *
127
+ * ── WHAT IT DOES NOT UNDO ──────────────────────────────────────────────────
128
+ * A `setPositionDelegate` the agent already installed on PositionDelegateRegistry
129
+ * SURVIVES both calls (vigil C-43). Clearing that is per-position and is not
130
+ * part of this plan.
131
+ *
132
+ * THROWS, unlike `getSafeAgentDelegation` — the asymmetry is deliberate. That
133
+ * one answers a question and "unknown" is a usable answer. This one produces a
134
+ * transaction the Safe's owners must gather to sign, so a guess costs them an
135
+ * approval round on something that must revert. Every failure is loud:
136
+ *
137
+ * - the chain has no AgentDelegationRegistry;
138
+ * - the Safe's module list cannot be read (never guess a predecessor: a wrong
139
+ * `prevModule` is Safe's GS103, AFTER the owners have signed);
140
+ * - the module is not enabled on the Safe (the caller is acting on a stale
141
+ * verdict).
142
+ *
143
+ * @param params.moduleAddress Optional. Supply the module from a verdict already
144
+ * on screen so the transaction describes what the user was looking at;
145
+ * omit it and the delegation is resolved here.
146
+ */
147
+ export declare function buildSafeAgentDelegationDisableCalls(params: {
148
+ safeAddress: string;
149
+ chainId: number;
150
+ provider: Provider;
151
+ moduleAddress?: string;
152
+ /** bytes32 recorded against the revocation. Defaults to `bytes32("user-disabled")`. */
153
+ reason?: string;
154
+ }): Promise<SafeAgentDelegationDisablePlan>;
@@ -3,23 +3,36 @@
3
3
  * (`BTCSpendAuthorizer.getAuthorizedSpends`) against BITCOIN truth before any
4
4
  * UI offers "Execute" or any server invokes the TEE signer.
5
5
  *
6
- * Why this exists (incident 2026-07-22, position 0x992d5c…): the contract can
7
- * never know whether a Phase-2 BTC broadcast happened, and a pre-P6/#8
8
- * authorization could record a `(vout, satoshis)` pair that never matched the
9
- * chain (declared 96,049 vs on-chain 33,000). Executing such an entry can only
10
- * die at the signer's parent-fetch guard; and an entry whose outpoint was
11
- * already spent paying the target is DONE and must auto-clear — while an
12
- * entry whose funding tx merely confirmed must NOT be cleared as "complete".
6
+ * `satoshis` semantics — AGGREGATE, by design: the authorized `satoshis` is
7
+ * the TOTAL input value the consolidation will consume across the vault's
8
+ * confirmed UTXO set (btc-withdrawal.ts signs `vaultSatoshis = newCollateral +
9
+ * totalDeduction`), while `(txid, vout)` pins ONE representative outpoint.
10
+ * `BTCSpendAuthorizer.sol` enforces `targetAmount < satoshis`
11
+ * (TargetMustLeaveFeeRoom) — a withdrawal near the vault's full balance could
12
+ * never be authorized against a single small outpoint's value, so the
13
+ * aggregate is structurally required. NEVER compare `satoshis` to the
14
+ * representative outpoint's own value: for any vault holding more than one
15
+ * UTXO they legitimately differ (incident 2026-08-07, position 0x992d5c…, a
16
+ * 4-UTXO vault whose valid authorization was misclassified as corrupt).
17
+ *
18
+ * What IS invariant, and what this module verifies:
19
+ * - the funding tx exists and is confirmed (else UNFUNDED);
20
+ * - the representative `vout` exists on that tx (else CORRUPT);
21
+ * - the output at `vout` pays the VAULT address, when the caller supplies it
22
+ * (else CORRUPT — this is the real 2026-07-20 (vout, satoshis)-decoupling
23
+ * bug class: a vout pointing at an output the vault does not own);
24
+ * - `targetAmount < satoshis`, mirroring the contract invariant (else CORRUPT);
25
+ * - the outpoint's spend state (EXECUTED / SPENT_MISMATCH / EXECUTABLE).
13
26
  *
14
27
  * Statuses:
15
- * - EXECUTABLE — outpoint confirmed, unspent, values coherent → offer Execute.
28
+ * - EXECUTABLE — outpoint confirmed, unspent, record coherent → offer Execute.
16
29
  * - EXECUTED — outpoint spent by a tx that pays the authorized target →
17
30
  * auto-clear, show `spendingTxid` as the completion proof.
18
31
  * - SPENT_MISMATCH — outpoint spent but the spending tx pays the target
19
32
  * nothing → unexecutable; recoverStaleSpend clears it.
20
- * - CORRUPT — authorization contradicts the chain (declared value ≠
21
- * real output value, targetAmount > real value, or vout
22
- * out of range) → operator recovery (admin clearing path);
33
+ * - CORRUPT — authorization contradicts the chain (vout out of range,
34
+ * output not owned by the vault, or targetAmount ≥
35
+ * satoshis) → operator recovery (admin clearing path);
23
36
  * never Execute.
24
37
  * - UNFUNDED — funding tx unknown/unconfirmed → wait; no Execute yet.
25
38
  *
@@ -43,7 +56,11 @@ export interface ReconciledWithdrawal<T extends AuthorizedSpendLike = Authorized
43
56
  status: PendingWithdrawalStatus;
44
57
  /** Human-readable, single-sentence explanation of the classification. */
45
58
  reason: string;
46
- /** Real value of the referenced outpoint, when the funding tx is known. */
59
+ /**
60
+ * Real value of the referenced outpoint, when the funding tx is known.
61
+ * Diagnostic only — for a multi-UTXO vault it is legitimately smaller than
62
+ * the aggregate `satoshis`.
63
+ */
47
64
  onChainOutputValue?: number;
48
65
  /** The verified spending tx, for EXECUTED / SPENT_MISMATCH. */
49
66
  spendingTxid?: string;
@@ -61,5 +78,14 @@ export type HttpGetJson = (url: string) => Promise<{
61
78
  body: unknown;
62
79
  }>;
63
80
  export declare const defaultHttpGetJson: HttpGetJson;
64
- /** Classify one authorized spend against the esplora at `esploraBaseUrl`. */
65
- export declare function reconcileAuthorizedSpend<T extends AuthorizedSpendLike>(spend: T, esploraBaseUrl: string, httpGetJson?: HttpGetJson): Promise<ReconciledWithdrawal<T>>;
81
+ /**
82
+ * Classify one authorized spend against the esplora at `esploraBaseUrl`.
83
+ *
84
+ * `opts.vaultAddress` enables the vault-ownership check (the strongest guard
85
+ * against the (vout, satoshis)-decoupling bug class). When absent the check is
86
+ * SKIPPED, not assumed — production callers (lit-ops-server, frontend) must
87
+ * supply it.
88
+ */
89
+ export declare function reconcileAuthorizedSpend<T extends AuthorizedSpendLike>(spend: T, esploraBaseUrl: string, httpGetJson?: HttpGetJson, opts?: {
90
+ vaultAddress?: string;
91
+ }): Promise<ReconciledWithdrawal<T>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gvnrdao/dh-sdk",
3
- "version": "0.0.320",
3
+ "version": "0.0.324",
4
4
  "description": "TypeScript SDK for Diamond Hands Protocol - Bitcoin-backed lending with LIT Protocol PKPs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,6 +29,11 @@
29
29
  "types": "./dist/deployments.d.ts",
30
30
  "import": "./dist/deployments.mjs",
31
31
  "require": "./dist/deployments.js"
32
+ },
33
+ "./safe-delegation": {
34
+ "types": "./dist/safe-delegation.d.ts",
35
+ "import": "./dist/safe-delegation.mjs",
36
+ "require": "./dist/safe-delegation.js"
32
37
  }
33
38
  },
34
39
  "files": [
@@ -82,8 +87,8 @@
82
87
  },
83
88
  "sideEffects": false,
84
89
  "dependencies": {
85
- "@gvnrdao/dh-lit-actions": "^0.0.319",
86
- "@gvnrdao/dh-lit-ops": "^0.0.310",
90
+ "@gvnrdao/dh-lit-actions": "^0.0.320",
91
+ "@gvnrdao/dh-lit-ops": "^0.0.311",
87
92
  "@noble/hashes": "^1.5.0",
88
93
  "axios": "^1.17.0",
89
94
  "bech32": "^2.0.0",