@gvnrdao/dh-sdk 0.0.305 → 0.0.307
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/browser/dist/browser.js +1 -1
- package/dist/deployments.js +32 -30
- package/dist/deployments.mjs +32 -30
- package/dist/index.d.ts +2 -0
- package/dist/index.js +442 -36
- package/dist/index.mjs +441 -37
- package/dist/interfaces/chunks/config.i.d.ts +12 -0
- package/dist/modules/diamond-hands-sdk.d.ts +41 -0
- package/dist/utils/lane-guard.utils.d.ts +36 -0
- package/dist/utils/quantum-submission.utils.d.ts +8 -0
- package/dist/utils/withdrawal-reconciliation.utils.d.ts +64 -0
- package/package.json +4 -4
|
@@ -18,6 +18,7 @@ import { SDKError } from "../utils/error-handler";
|
|
|
18
18
|
import type { CreateLoanRequest, CreateLoanResult, LoanDataDetail, UCDMintRequest, UCDMintResult, PartialPaymentRequest, PartialPaymentResult, BTCWithdrawalResult, RenewPositionRequest, RenewPositionResult, LiquidationRequest, LiquidationResult, ConfirmBalanceRequest, ConfirmBalanceResult, TermsWithFeesResult } from "../interfaces/chunks/loan-operations.i";
|
|
19
19
|
import type { DiamondHandsSDKConfig } from "../interfaces/chunks/config.i";
|
|
20
20
|
import type { PKPData } from "../interfaces/chunks/pkp-integration.i";
|
|
21
|
+
import { type ReconciledWithdrawal } from "../utils/withdrawal-reconciliation.utils";
|
|
21
22
|
import { ContractManager } from "./contract/contract-manager.module";
|
|
22
23
|
import { WithdrawalAddressModule } from "./withdrawal-address/withdrawal-address.module";
|
|
23
24
|
import { BitcoinOperations } from "./bitcoin/bitcoin-operations.module";
|
|
@@ -475,6 +476,18 @@ export declare class DiamondHandsSDK {
|
|
|
475
476
|
* @param request - Execution request with positionId, utxoIdentifier, and networkFee
|
|
476
477
|
* @returns Execution result with Bitcoin txid
|
|
477
478
|
*/
|
|
479
|
+
/**
|
|
480
|
+
* STANDALONE Phase 2: sign + broadcast the withdrawal Bitcoin transaction
|
|
481
|
+
* in-process — the same orchestration lit-ops-server performs, composed
|
|
482
|
+
* from the same primitives (`litOps.signBTCTransaction`, which has always
|
|
483
|
+
* had a standalone path, and `broadcastSignedBitcoinTransaction`).
|
|
484
|
+
* Both modes must support withdrawal execution (Master mandate 2026-07-21).
|
|
485
|
+
*
|
|
486
|
+
* The service path's post-broadcast CRIT-2 re-verification exists to catch
|
|
487
|
+
* a LYING SERVER; here the broadcast happens locally from the signatures we
|
|
488
|
+
* just obtained, so the esplora-returned txid is already first-hand.
|
|
489
|
+
*/
|
|
490
|
+
private executeBTCWithdrawalStandalonePhase2;
|
|
478
491
|
executeBTCWithdrawal(request: {
|
|
479
492
|
positionId: string;
|
|
480
493
|
utxoIdentifier: string;
|
|
@@ -544,6 +557,27 @@ export declare class DiamondHandsSDK {
|
|
|
544
557
|
authorizedAt: number;
|
|
545
558
|
utxoKey: string;
|
|
546
559
|
}>>;
|
|
560
|
+
/**
|
|
561
|
+
* Reconcile every pending withdrawal against BITCOIN truth (incident
|
|
562
|
+
* 2026-07-22): `getPendingWithdrawals` only reflects on-chain
|
|
563
|
+
* authorizations, and the contract can never know whether the Phase-2 BTC
|
|
564
|
+
* broadcast happened. Callers MUST use the returned `status` to decide what
|
|
565
|
+
* to offer:
|
|
566
|
+
* - EXECUTABLE → offer Execute (the only status that may).
|
|
567
|
+
* - EXECUTED → auto-clear; `spendingTxid` is the completion proof.
|
|
568
|
+
* - SPENT_MISMATCH → unexecutable; offer cancelPendingWithdrawal.
|
|
569
|
+
* - 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
|
+
* - UNFUNDED → funding tx unknown/unconfirmed; wait.
|
|
573
|
+
*
|
|
574
|
+
* @param opts.esploraBaseUrl Esplora API base (e.g. the api proxy
|
|
575
|
+
* `/v1/proxy/esplora/<network>`). Falls back to
|
|
576
|
+
* `config.bitcoinProviders[0].url`; throws when neither is configured.
|
|
577
|
+
*/
|
|
578
|
+
reconcilePendingWithdrawals(positionId: string, opts?: {
|
|
579
|
+
esploraBaseUrl?: string;
|
|
580
|
+
}): Promise<Array<ReconciledWithdrawal<Awaited<ReturnType<DiamondHandsSDK["getPendingWithdrawals"]>>[number]>>>;
|
|
547
581
|
/**
|
|
548
582
|
* Cancel a pending BTC withdrawal
|
|
549
583
|
*
|
|
@@ -944,6 +978,13 @@ export declare class DiamondHandsSDK {
|
|
|
944
978
|
* Check if running on production network
|
|
945
979
|
*/
|
|
946
980
|
private isProductionNetwork;
|
|
981
|
+
/**
|
|
982
|
+
* Local-lane activation, verified against the LIVE node at call time (not
|
|
983
|
+
* the chainId cached at init — a provider that switched networks after
|
|
984
|
+
* init fails the fresh probe). Zero RPC cost outside a lane process tree:
|
|
985
|
+
* without LIT_LANE_GUARD=1 this short-circuits to false before any probe.
|
|
986
|
+
*/
|
|
987
|
+
private isLocalLaneGuardActive;
|
|
947
988
|
/**
|
|
948
989
|
* Get Bitcoin network based on chain.
|
|
949
990
|
*
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local-verification-lane guard — the ONLY file in the SDK allowed to read
|
|
3
|
+
* the `LIT_LANE_*` environment (enforced by
|
|
4
|
+
* `contracts/tests/unit/lane-guard-env-allowlist.unit.test.ts`).
|
|
5
|
+
*
|
|
6
|
+
* The lane hooks (quantum-phase alignment before mint authorization, the
|
|
7
|
+
* simulated-SameBlockInteraction tolerance) exist solely to absorb local
|
|
8
|
+
* hardhat artifacts: tunnel latency and automine's stale-latest-block
|
|
9
|
+
* simulation. They are never correct on a live network, so activation is
|
|
10
|
+
* TRIPLY bound, verified against the live node at the moment of use:
|
|
11
|
+
*
|
|
12
|
+
* 1. `LIT_LANE_GUARD=1` — exported only by `scripts/lane-env-guard.sh`
|
|
13
|
+
* for the detached local lane's process tree, AND
|
|
14
|
+
* 2. a fresh `eth_chainId` probe (NOT ethers' init-time network cache, so a
|
|
15
|
+
* provider that switched networks after init cannot keep the hooks
|
|
16
|
+
* alive) returns a hardhat chainId (1337 `npx hardhat node`, 31337
|
|
17
|
+
* in-process default), AND
|
|
18
|
+
* 3. the node self-identifies as Hardhat via `web3_clientVersion` — a
|
|
19
|
+
* live/private network that merely reuses chainId 1337/31337 does not.
|
|
20
|
+
*
|
|
21
|
+
* Any probe failure, missing `send` capability, or unexpected answer is
|
|
22
|
+
* treated as NOT the lane — fail closed. The on-chain guards remain fully
|
|
23
|
+
* authoritative in every mode regardless.
|
|
24
|
+
*/
|
|
25
|
+
/** Minimal raw-RPC seam — satisfied by ethers v6 JsonRpcApiProvider. */
|
|
26
|
+
export interface RawRpcSender {
|
|
27
|
+
send?(method: string, params: unknown[]): Promise<unknown>;
|
|
28
|
+
}
|
|
29
|
+
/** The env half of the guard: is the lane environment exported at all? */
|
|
30
|
+
export declare function laneGuardEnvEnabled(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Full lane-guard check against the LIVE node. Cheap short-circuit (no RPC)
|
|
33
|
+
* when the lane env is not exported — the two probes only ever run inside a
|
|
34
|
+
* lane process tree.
|
|
35
|
+
*/
|
|
36
|
+
export declare function isLaneGuardActiveOnProvider(provider: RawRpcSender | undefined | null): Promise<boolean>;
|
|
@@ -61,6 +61,14 @@ export interface SafeQuantumSubmissionOpts {
|
|
|
61
61
|
sleep?: (ms: number) => Promise<void>;
|
|
62
62
|
/** Debug sink; called with human-readable progress lines. */
|
|
63
63
|
onDebug?: (msg: string) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Local-lane activation, computed by the caller at submission time via
|
|
66
|
+
* `isLaneGuardActiveOnProvider` (lane env exported + live node probes as a
|
|
67
|
+
* hardhat chain/client). Only consulted by the local-lane
|
|
68
|
+
* SameBlockInteraction tolerance; omitted or false keeps the fail-fast
|
|
69
|
+
* behavior on every decodable revert.
|
|
70
|
+
*/
|
|
71
|
+
laneGuardActive?: boolean;
|
|
64
72
|
}
|
|
65
73
|
/**
|
|
66
74
|
* Gate + pre-send simulation loop. Resolves when it is safe to broadcast;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pending-withdrawal reconciliation — classify each on-chain authorized spend
|
|
3
|
+
* (`BTCSpendAuthorizer.getAuthorizedSpends`) against BITCOIN truth before any
|
|
4
|
+
* UI offers "Execute" or any server invokes the TEE signer.
|
|
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".
|
|
13
|
+
*
|
|
14
|
+
* Statuses:
|
|
15
|
+
* - EXECUTABLE — outpoint confirmed, unspent, values coherent → offer Execute.
|
|
16
|
+
* - EXECUTED — outpoint spent by a tx that pays the authorized target →
|
|
17
|
+
* auto-clear, show `spendingTxid` as the completion proof.
|
|
18
|
+
* - SPENT_MISMATCH — outpoint spent but the spending tx pays the target
|
|
19
|
+
* nothing → unexecutable; surface Cancel.
|
|
20
|
+
* - CORRUPT — authorization contradicts the chain (declared value ≠
|
|
21
|
+
* real output value, targetAmount > real value, or vout
|
|
22
|
+
* out of range) → surface Cancel & re-request; never Execute.
|
|
23
|
+
* - UNFUNDED — funding tx unknown/unconfirmed → wait; no Execute yet.
|
|
24
|
+
*
|
|
25
|
+
* Esplora `spent: true` claims are only trusted when the spending tx can be
|
|
26
|
+
* fetched AND provably includes this outpoint among its inputs — the regtest
|
|
27
|
+
* faucet's esplora answers `spent: true` for arbitrary txids, and a false
|
|
28
|
+
* "executed" here would silently dismiss a withdrawal the user was never paid
|
|
29
|
+
* for. Unverifiable claims classify as EXECUTABLE (chain truth: no proven
|
|
30
|
+
* spend); a genuinely-spent outpoint then simply fails downstream, safely.
|
|
31
|
+
*/
|
|
32
|
+
export type PendingWithdrawalStatus = "EXECUTABLE" | "EXECUTED" | "SPENT_MISMATCH" | "CORRUPT" | "UNFUNDED";
|
|
33
|
+
export interface AuthorizedSpendLike {
|
|
34
|
+
txid: string;
|
|
35
|
+
vout: number;
|
|
36
|
+
satoshis: number;
|
|
37
|
+
targetAddress: string;
|
|
38
|
+
targetAmount: number;
|
|
39
|
+
}
|
|
40
|
+
export interface ReconciledWithdrawal<T extends AuthorizedSpendLike = AuthorizedSpendLike> {
|
|
41
|
+
spend: T;
|
|
42
|
+
status: PendingWithdrawalStatus;
|
|
43
|
+
/** Human-readable, single-sentence explanation of the classification. */
|
|
44
|
+
reason: string;
|
|
45
|
+
/** Real value of the referenced outpoint, when the funding tx is known. */
|
|
46
|
+
onChainOutputValue?: number;
|
|
47
|
+
/** The verified spending tx, for EXECUTED / SPENT_MISMATCH. */
|
|
48
|
+
spendingTxid?: string;
|
|
49
|
+
/** Sats the verified spending tx pays to `targetAddress` (EXECUTED only). */
|
|
50
|
+
paidToTargetSats?: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* HTTP seam: GET `url`, resolve `{ status, body }` (body null on non-JSON).
|
|
54
|
+
* Injectable for tests; the default uses global `fetch` (node ≥18 + browsers).
|
|
55
|
+
* Transport failures throw — reconciliation must fail LOUD, never classify on
|
|
56
|
+
* missing data.
|
|
57
|
+
*/
|
|
58
|
+
export type HttpGetJson = (url: string) => Promise<{
|
|
59
|
+
status: number;
|
|
60
|
+
body: unknown;
|
|
61
|
+
}>;
|
|
62
|
+
export declare const defaultHttpGetJson: HttpGetJson;
|
|
63
|
+
/** Classify one authorized spend against the esplora at `esploraBaseUrl`. */
|
|
64
|
+
export declare function reconcileAuthorizedSpend<T extends AuthorizedSpendLike>(spend: T, esploraBaseUrl: string, httpGetJson?: HttpGetJson): Promise<ReconciledWithdrawal<T>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gvnrdao/dh-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.307",
|
|
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": "
|
|
86
|
-
"@gvnrdao/dh-lit-ops": "
|
|
85
|
+
"@gvnrdao/dh-lit-actions": "0.0.315",
|
|
86
|
+
"@gvnrdao/dh-lit-ops": "0.0.306",
|
|
87
87
|
"@noble/hashes": "^1.5.0",
|
|
88
88
|
"axios": "^1.17.0",
|
|
89
89
|
"bech32": "^2.0.0",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"bs58check": "^3.0.1",
|
|
93
93
|
"crypto-js": "^4.2.0",
|
|
94
94
|
"dotenv": "^17.4.2",
|
|
95
|
-
"ethers": "
|
|
95
|
+
"ethers": "6.16.0",
|
|
96
96
|
"valibot": "^1.1.0"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|