@gvnrdao/dh-sdk 0.0.299 → 0.0.301
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 +14 -0
- package/dist/deployments.mjs +14 -0
- package/dist/index.js +442 -571
- package/dist/index.mjs +351 -480
- package/dist/utils/chunks/eip1559-broadcast.utils.d.ts +15 -24
- package/dist/utils/quantum-revert.utils.d.ts +41 -0
- package/dist/utils/quantum-submission.utils.d.ts +93 -0
- package/package.json +3 -3
|
@@ -4,27 +4,24 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { type Provider, type Signer, type TransactionResponse } from "ethers";
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* ~1.5-2x-headroom convention -- a smaller margin than those because this
|
|
21
|
-
* ceiling is a rarely-hit fallback/cap, not the everyday operating value, so
|
|
22
|
-
* a little extra buffer for cold-storage variance is cheap insurance.
|
|
7
|
+
* Fixed-gas ceiling for mintUCD's broadcast. Since the gold-standard refactor
|
|
8
|
+
* (2026-07-08) this IS the everyday submitted gasLimit: mintUCD no longer runs
|
|
9
|
+
* eth_estimateGas (its round-trip latency re-introduced the quantum-boundary
|
|
10
|
+
* race the submission gate exists to prevent), matching makePayment /
|
|
11
|
+
* withdrawBTC / extendPosition. Grounded in 16 real mint transactions
|
|
12
|
+
* (1 mainnet, 15 recent Sepolia, 2026-07-02): the estimate-derived gasLimit
|
|
13
|
+
* actually submitted ranged 388,620-886,988, and those limits all succeeded —
|
|
14
|
+
* so 886,988 is a KNOWN-SUFFICIENT limit, not a bare gasUsed figure.
|
|
15
|
+
* 1,300,000 gives ~1.47x headroom over it, matching MAKE_PAYMENT_GAS_CEILING's
|
|
16
|
+
* ~1.5x convention. Deliberately NOT higher: wallets (MetaMask) reject a tx
|
|
17
|
+
* when balance < gasLimit × maxFeePerGas, so an oversized fixed ceiling
|
|
18
|
+
* (previously 2M as a rarely-hit cap) would block low-ETH users from an
|
|
19
|
+
* affordable mint.
|
|
23
20
|
*/
|
|
24
21
|
export declare const MINT_UCD_GAS_CEILING: bigint;
|
|
25
22
|
/**
|
|
26
|
-
* Fixed-gas ceiling for
|
|
27
|
-
*
|
|
23
|
+
* Fixed-gas ceiling for withdrawBTC's broadcast (the everyday submitted
|
|
24
|
+
* gasLimit — no estimateGas runs on this path). The on-chain flow now spans PositionManager →
|
|
28
25
|
* CollateralManager → LoanOperationsManager → BTCSpendAuthorizer plus the audit
|
|
29
26
|
* #3 Chainlink feed-staleness gate and the BitcoinWithdrawalAddressRegistry
|
|
30
27
|
* allowlist STATICCALL; observed end-to-end cost is ~1.0–1.3M gas, so the prior
|
|
@@ -89,12 +86,6 @@ export declare const LIQUIDATION_COMMIT_GAS_CEILING: bigint;
|
|
|
89
86
|
* provisional until re-measured against a real liquidation.
|
|
90
87
|
*/
|
|
91
88
|
export declare const LIQUIDATION_REVEAL_GAS_CEILING: bigint;
|
|
92
|
-
/** Headroom on eth_estimateGas (25%). */
|
|
93
|
-
export declare const MINT_UCD_ESTIMATE_MARGIN_BPS = 2500;
|
|
94
|
-
/**
|
|
95
|
-
* Returns gas limit with margin, capped, or null if estimateGas reverts/fails.
|
|
96
|
-
*/
|
|
97
|
-
export declare function estimateContractCallGasWithMargin(provider: Provider, from: string, to: string, data: string, marginBps: number, ceiling: bigint): Promise<bigint | null>;
|
|
98
89
|
export declare function resolveEip1559FeeFields(provider: Provider): Promise<{
|
|
99
90
|
maxFeePerGas: bigint;
|
|
100
91
|
maxPriorityFeePerGas: bigint;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared decoder for custom-error reverts surfaced by quantum-signed operations
|
|
3
|
+
* (mintUCD / makePayment / withdrawBTC / extendPosition / liquidation).
|
|
4
|
+
*
|
|
5
|
+
* Consolidates what used to be three hand-rolled selector maps + ad-hoc error-data
|
|
6
|
+
* extraction scattered across diamond-hands-sdk.ts. The extraction probes EVERY
|
|
7
|
+
* nesting ethers v6 uses across provider types — notably `info.error.data`, which
|
|
8
|
+
* `BrowserProvider` (MetaMask) uses and the older per-site extractors missed, so a
|
|
9
|
+
* browser-provider DeadZoneViolation could slip through undetected and wrongly throw.
|
|
10
|
+
*/
|
|
11
|
+
/** `DeadZoneViolation()` selector — the stale-latest-block artifact we tolerate. */
|
|
12
|
+
export declare const DEAD_ZONE_VIOLATION_SELECTOR = "0xbe4b82c1";
|
|
13
|
+
/** Solidity `Error(string)` (require/revert with a message). */
|
|
14
|
+
export declare const ERROR_STRING_SELECTOR = "0x08c379a0";
|
|
15
|
+
/** Solidity `Panic(uint256)` (assert failures, overflow, div-by-zero, …). */
|
|
16
|
+
export declare const PANIC_SELECTOR = "0x4e487b71";
|
|
17
|
+
/**
|
|
18
|
+
* Union of the custom-error selectors the mint/payment/quantum paths decode. Keep in
|
|
19
|
+
* sync with OperationAuthorizationRegistry / PositionManager / LoanOperationsManager.
|
|
20
|
+
*/
|
|
21
|
+
export declare const QUANTUM_REVERT_NAMES: Record<string, string>;
|
|
22
|
+
export interface DecodedRevert {
|
|
23
|
+
/** Raw revert data (`0x…`) if any provider nesting carried it, else null. */
|
|
24
|
+
data: string | null;
|
|
25
|
+
/** 4-byte custom-error selector (`0x…`) if the data is a valid custom error. */
|
|
26
|
+
selector: string | null;
|
|
27
|
+
/** Human-readable error name if the selector is known, else null. */
|
|
28
|
+
name: string | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Extract the revert data / custom-error selector / known name from an ethers error,
|
|
32
|
+
* probing every provider nesting (JsonRpc, Browser/MetaMask, wrapped `error.error`).
|
|
33
|
+
*
|
|
34
|
+
* Besides the custom-error selector map, decodes the two standard Solidity revert
|
|
35
|
+
* shapes so require-message reverts stay actionable when call sites rely solely on
|
|
36
|
+
* this decoder: `Error(string)` yields `name = 'Error("<message>")'` and
|
|
37
|
+
* `Panic(uint256)` yields `name = "Panic(0x<code>)"`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function decodeQuantumRevert(e: any): DecodedRevert;
|
|
40
|
+
/** True iff the error decodes to `DeadZoneViolation()` from any provider nesting. */
|
|
41
|
+
export declare function isDeadZoneViolation(e: any): boolean;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared submission-time safety for quantum-signed broadcasts
|
|
3
|
+
* (makePayment / mintUCD / withdrawBTC / extendPosition).
|
|
4
|
+
*
|
|
5
|
+
* One helper owns the dead-zone gate AND the pre-send simulate/re-simulate loop
|
|
6
|
+
* that used to exist as three subtly different inline copies in
|
|
7
|
+
* diamond-hands-sdk.ts. Callers encode calldata, call
|
|
8
|
+
* `assertSafeQuantumSubmission`, then broadcast ONCE with a fixed gas ceiling
|
|
9
|
+
* (`sendEip1559Transaction`) — never `estimateGas`, whose latency re-introduces
|
|
10
|
+
* the boundary race the gate exists to prevent, and never a re-broadcast.
|
|
11
|
+
*
|
|
12
|
+
* See docs/sdk-quantum-goldstandard-refactor-plan-2026-07-08.md.
|
|
13
|
+
*/
|
|
14
|
+
/** Default cap on dead-zone-triggered re-simulations (mirrors old makePayment). */
|
|
15
|
+
export declare const MAX_DEADZONE_RESIMULATIONS = 3;
|
|
16
|
+
/**
|
|
17
|
+
* Thrown when the pre-send simulation proves the transaction would revert.
|
|
18
|
+
* Carries everything a caller needs to enrich the failure without re-probing
|
|
19
|
+
* the provider error itself:
|
|
20
|
+
*
|
|
21
|
+
* - `errorName` — decoded name, e.g. `"QuantumExpired()"` or `Error("msg")`
|
|
22
|
+
* (named to avoid shadowing `Error.name`).
|
|
23
|
+
* - `selector` — 4-byte selector, e.g. `"0x131d9a21"`.
|
|
24
|
+
* - `data` — FULL revert data (mintUCD decodes
|
|
25
|
+
* `DebtUpdateVerificationFailedDetailed` args from it).
|
|
26
|
+
* - `cause` — the original provider error (`reason` / `shortMessage`
|
|
27
|
+
* fallbacks, empty-data detection → `diagnoseMintUCD`).
|
|
28
|
+
*
|
|
29
|
+
* Only thrown for DECODABLE reverts (revert data present). Transport-level
|
|
30
|
+
* `eth_call` failures never raise this — see `assertSafeQuantumSubmission`.
|
|
31
|
+
*/
|
|
32
|
+
export declare class QuantumRevertError extends Error {
|
|
33
|
+
readonly errorName: string | null;
|
|
34
|
+
readonly selector: string | null;
|
|
35
|
+
readonly data: string | null;
|
|
36
|
+
readonly cause: unknown;
|
|
37
|
+
constructor(errorName: string | null, selector: string | null, data: string | null, cause: unknown);
|
|
38
|
+
}
|
|
39
|
+
export interface SafeQuantumSubmissionOpts {
|
|
40
|
+
/** Provider used for the `eth_call` simulation (only `.call` is needed). */
|
|
41
|
+
provider: {
|
|
42
|
+
call(tx: {
|
|
43
|
+
to: string;
|
|
44
|
+
from: string;
|
|
45
|
+
data: string;
|
|
46
|
+
}): Promise<string>;
|
|
47
|
+
};
|
|
48
|
+
/** Target contract address. */
|
|
49
|
+
to: string;
|
|
50
|
+
/** Sender address — `eth_call` must run as the real sender (auth checks). */
|
|
51
|
+
from: string;
|
|
52
|
+
/** Encoded calldata; broadcast MUST send these exact bytes. */
|
|
53
|
+
data: string;
|
|
54
|
+
/** The quantum timestamp embedded in the LIT-signed payload. */
|
|
55
|
+
quantumTimestamp: number;
|
|
56
|
+
/** Cap on dead-zone re-simulations (default {@link MAX_DEADZONE_RESIMULATIONS}). */
|
|
57
|
+
maxResimulations?: number;
|
|
58
|
+
/** Clock seam (whole seconds). Drives BOTH the gate and the artifact test. */
|
|
59
|
+
now?: () => number;
|
|
60
|
+
/** Sleep seam, forwarded to the gate. */
|
|
61
|
+
sleep?: (ms: number) => Promise<void>;
|
|
62
|
+
/** Debug sink; called with human-readable progress lines. */
|
|
63
|
+
onDebug?: (msg: string) => void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Gate + pre-send simulation loop. Resolves when it is safe to broadcast;
|
|
67
|
+
* throws {@link QuantumRevertError} on a real (non-artifact) decodable revert.
|
|
68
|
+
* Never broadcasts anything itself.
|
|
69
|
+
*
|
|
70
|
+
* Sequence:
|
|
71
|
+
* 1. **Gate** (`awaitSafeSubmissionWindow`): a NEXT-quantum signature mined in
|
|
72
|
+
* the last DEAD_ZONE_SECONDS of the current quantum reverts
|
|
73
|
+
* `DeadZoneViolation()` on-chain, so defer the send across the boundary
|
|
74
|
+
* when inclusion could land there.
|
|
75
|
+
* 2. **Simulate** (`eth_call`) and route the outcome:
|
|
76
|
+
* - success → safe to broadcast.
|
|
77
|
+
* - `DeadZoneViolation()` → `eth_call` runs against the LATEST block's
|
|
78
|
+
* (slightly stale) timestamp while the on-chain rule uses MINE time. If
|
|
79
|
+
* the signature is already the CURRENT quantum in real time it can never
|
|
80
|
+
* be dead-zoned on-chain — stale-block artifact, proceed. Otherwise the
|
|
81
|
+
* signature is still NEXT near the boundary: re-gate across it and
|
|
82
|
+
* re-simulate (bounded by `maxResimulations`).
|
|
83
|
+
* - any other DECODABLE revert → throw `QuantumRevertError` (fail fast: no
|
|
84
|
+
* broadcast, no gas burned on a doomed tx).
|
|
85
|
+
* - UNDECODABLE failure (no revert data: RPC timeout, rate limit, provider
|
|
86
|
+
* quirk) → log and proceed. The fixed-ceiling broadcast degrades to the
|
|
87
|
+
* pre-refactor blind-broadcast behavior instead of letting a flaky RPC
|
|
88
|
+
* block a valid money-path operation.
|
|
89
|
+
* 3. **Final re-gate**: the sim loop adds RPC round-trips after step 1; this
|
|
90
|
+
* closes the drift with pure clock math (no RPC). If it waits, the
|
|
91
|
+
* signature is CURRENT afterward and needs no further simulation.
|
|
92
|
+
*/
|
|
93
|
+
export declare function assertSafeQuantumSubmission(opts: SafeQuantumSubmissionOpts): Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gvnrdao/dh-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.301",
|
|
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.
|
|
86
|
-
"@gvnrdao/dh-lit-ops": "^0.0.
|
|
85
|
+
"@gvnrdao/dh-lit-actions": "^0.0.313",
|
|
86
|
+
"@gvnrdao/dh-lit-ops": "^0.0.303",
|
|
87
87
|
"@noble/hashes": "^1.5.0",
|
|
88
88
|
"axios": "^1.17.0",
|
|
89
89
|
"bech32": "^2.0.0",
|