@gvnrdao/dh-sdk 0.0.307 → 0.0.308

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.
@@ -546,7 +546,7 @@ export declare class DiamondHandsSDK {
546
546
  * been broadcast to the Bitcoin network. An empty array means no pending withdrawals.
547
547
  *
548
548
  * @param positionId - Position identifier
549
- * @returns Array of pending withdrawals, each including a pre-computed utxoKey for use with cancelPendingWithdrawal
549
+ * @returns Array of pending withdrawals, each including a pre-computed utxoKey (the key recoverStaleSpend and the admin clearing path operate on)
550
550
  */
551
551
  getPendingWithdrawals(positionId: string): Promise<Array<{
552
552
  txid: string;
@@ -564,11 +564,15 @@ export declare class DiamondHandsSDK {
564
564
  * broadcast happened. Callers MUST use the returned `status` to decide what
565
565
  * to offer:
566
566
  * - EXECUTABLE → offer Execute (the only status that may).
567
- * - EXECUTED → auto-clear; `spendingTxid` is the completion proof.
568
- * - SPENT_MISMATCH → unexecutable; offer cancelPendingWithdrawal.
567
+ * - EXECUTED → auto-clear; `spendingTxid` is the completion proof
568
+ * feed it to recoverStaleSpend to clear the reservation.
569
+ * - SPENT_MISMATCH → unexecutable; recoverStaleSpend with the spending txid
570
+ * as invalidator clears the reservation.
569
571
  * - CORRUPT → authorization contradicts the chain (e.g. declared
570
- * satoshis ≠ real output value); offer Cancel &
571
- * re-request Execute can only die at the signer guard.
572
+ * satoshis ≠ real output value); Execute can only die at
573
+ * the signer guard, and no borrower-side cancel exists
574
+ * (audit #62210) — clearing needs the AdminModule
575
+ * cancelStaleSpendByAdmin operator override.
572
576
  * - UNFUNDED → funding tx unknown/unconfirmed; wait.
573
577
  *
574
578
  * @param opts.esploraBaseUrl Esplora API base (e.g. the api proxy
@@ -578,18 +582,6 @@ export declare class DiamondHandsSDK {
578
582
  reconcilePendingWithdrawals(positionId: string, opts?: {
579
583
  esploraBaseUrl?: string;
580
584
  }): Promise<Array<ReconciledWithdrawal<Awaited<ReturnType<DiamondHandsSDK["getPendingWithdrawals"]>>[number]>>>;
581
- /**
582
- * Cancel a pending BTC withdrawal
583
- *
584
- * Removes a stale authorized spend from BTCSpendAuthorizer, unlocking the UTXO
585
- * and allowing the borrower to retry the withdrawal from scratch.
586
- * Only the position's borrower may call this — requires a connected signer.
587
- *
588
- * @param positionId - Position identifier
589
- * @param txid - Bitcoin UTXO transaction ID (from getPendingWithdrawals)
590
- * @param vout - Output index (from getPendingWithdrawals)
591
- * @returns Transaction hash of the cancellation EVM transaction
592
- */
593
585
  /**
594
586
  * Recover (clear) a stale BTC reservation via LIT-attested proof.
595
587
  *
@@ -639,6 +631,59 @@ export declare class DiamondHandsSDK {
639
631
  error?: string;
640
632
  failedStep?: "attestation" | "submit" | "config";
641
633
  }>;
634
+ /**
635
+ * Sign + broadcast the PKP vault→vault self-spend that invalidates one
636
+ * stuck authorized outpoint (btc-utxo-invalidator 1.0.0). Once the returned
637
+ * `invalidatorTxid` reaches >=6 Bitcoin confirmations, `recoverStaleSpend`
638
+ * clears the on-chain reservation — the trustless replacement for the
639
+ * AdminModule cancelStaleSpendByAdmin path on unspent stuck/corrupt
640
+ * reservations (incident 2026-07-22). Requires the borrower (or position
641
+ * delegate) signer; the signature is scoped to exactly this outpoint.
642
+ */
643
+ invalidateStaleSpend(params: {
644
+ positionId: string;
645
+ utxoTxid: string;
646
+ utxoVout: number;
647
+ rpcUrl?: string;
648
+ }): Promise<{
649
+ success: boolean;
650
+ alreadySpent?: {
651
+ spendingTxid: string;
652
+ };
653
+ invalidatorTxid?: string;
654
+ invalidatorAmount?: number;
655
+ networkFee?: number;
656
+ /** True when the on-chain record's declared value ≠ the real output (corrupt-record recovery). */
657
+ valueMismatch?: boolean;
658
+ error?: string;
659
+ failedStep?: string;
660
+ }>;
661
+ /**
662
+ * Resumable, stateless clearing state machine for one stuck reservation —
663
+ * Bitcoin itself is the state store, so every call either advances the flow
664
+ * one step or reports where it stands (survives reloads and the multi-day
665
+ * 6-confirmation wait; no internal polling).
666
+ *
667
+ * (a) reservation gone → phase "cleared"
668
+ * (b) outpoint spent, >=6 confs → recoverStaleSpend → "cleared"/"failed"
669
+ * outpoint spent, <6 confs → "awaiting-confirmations" (x/6)
670
+ * (c) outpoint unspent → invalidateStaleSpend → "invalidator-broadcast"
671
+ */
672
+ clearStuckReservation(params: {
673
+ positionId: string;
674
+ utxoTxid: string;
675
+ utxoVout: number;
676
+ esploraBaseUrl?: string;
677
+ }): Promise<{
678
+ phase: "cleared" | "awaiting-confirmations" | "invalidator-broadcast" | "failed";
679
+ invalidatorTxid?: string;
680
+ confirmations?: number;
681
+ required?: number;
682
+ transactionHash?: string;
683
+ classification?: string;
684
+ valueMismatch?: boolean;
685
+ error?: string;
686
+ }>;
642
687
  /**
643
688
  * Withdraw BTC and execute transfer (Complete Flow)
644
689
  *
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Borrower authorization envelope for the btc-utxo-invalidator Lit Action —
3
+ * the SDK-side mirror of `AuthorizationModule.verifyRecoveryAuthorization`
4
+ * (lit-actions/src/modules/authorization.module.ts:539). Field order and
5
+ * types MUST match byte-for-byte; the action recomputes this hash and
6
+ * EIP-191-recovers the borrower/delegate from it.
7
+ *
8
+ * NOTE: the lit-actions side hashes with ethers v5 `solidityKeccak256`, this
9
+ * side with v6 `solidityPackedKeccak256` — identical packed encoding; the
10
+ * unit test asserts byte-equality of the preimages so drift cannot sneak in.
11
+ */
12
+ import { type Signer } from "ethers";
13
+ /** Must equal RECOVERY_INVALIDATE_ACTION_STRING in lit-actions constants. */
14
+ export declare const RECOVERY_INVALIDATE_ACTION = "btc-utxo-invalidator";
15
+ export interface InvalidateStaleSpendEnvelope {
16
+ positionId: string;
17
+ utxoTxid: string;
18
+ utxoVout: number;
19
+ /** Quantum-aligned unix seconds bound into the signature. */
20
+ timestamp: number;
21
+ chainId: number;
22
+ action: typeof RECOVERY_INVALIDATE_ACTION;
23
+ signature: string;
24
+ borrowerAddress: string;
25
+ }
26
+ /** The exact packed hash `verifyRecoveryAuthorization` recomputes in-TEE. */
27
+ export declare function buildInvalidateMessageHash(params: {
28
+ positionId: string;
29
+ timestamp: number;
30
+ chainId: number;
31
+ utxoTxid: string;
32
+ utxoVout: number;
33
+ }): string;
34
+ /**
35
+ * Build + sign the invalidate envelope with a quantum-aligned timestamp.
36
+ * The signature is scoped to exactly one (positionId, utxoTxid, utxoVout)
37
+ * recovery on one chain and cannot be replayed as any other authorization
38
+ * (the action string is pinned into the hash).
39
+ */
40
+ export declare function buildInvalidateStaleSpendEnvelope(params: {
41
+ positionId: string;
42
+ utxoTxid: string;
43
+ utxoVout: number;
44
+ chainId: number;
45
+ signer: Signer;
46
+ }): Promise<InvalidateStaleSpendEnvelope>;
@@ -16,10 +16,11 @@
16
16
  * - EXECUTED — outpoint spent by a tx that pays the authorized target →
17
17
  * auto-clear, show `spendingTxid` as the completion proof.
18
18
  * - SPENT_MISMATCH — outpoint spent but the spending tx pays the target
19
- * nothing → unexecutable; surface Cancel.
19
+ * nothing → unexecutable; recoverStaleSpend clears it.
20
20
  * - CORRUPT — authorization contradicts the chain (declared value ≠
21
21
  * real output value, targetAmount > real value, or vout
22
- * out of range) → surface Cancel & re-request; never Execute.
22
+ * out of range) → operator recovery (admin clearing path);
23
+ * never Execute.
23
24
  * - UNFUNDED — funding tx unknown/unconfirmed → wait; no Execute yet.
24
25
  *
25
26
  * Esplora `spent: true` claims are only trusted when the spending tx can be
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gvnrdao/dh-sdk",
3
- "version": "0.0.307",
3
+ "version": "0.0.308",
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",
@@ -82,8 +82,8 @@
82
82
  },
83
83
  "sideEffects": false,
84
84
  "dependencies": {
85
- "@gvnrdao/dh-lit-actions": "0.0.315",
86
- "@gvnrdao/dh-lit-ops": "0.0.306",
85
+ "@gvnrdao/dh-lit-actions": "^0.0.316",
86
+ "@gvnrdao/dh-lit-ops": "^0.0.307",
87
87
  "@noble/hashes": "^1.5.0",
88
88
  "axios": "^1.17.0",
89
89
  "bech32": "^2.0.0",