@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.
@@ -48,6 +48,8 @@ export interface ContractAddresses {
48
48
  agentDelegationRegistry?: string;
49
49
  /** DHAgentDelegate; EIP-7702 execution adapter (Gate 2) the borrower EOA delegates to. Sepolia only. */
50
50
  dhAgentDelegate?: string;
51
+ /** AgentModuleFactory; CREATE2 factory a multi-sig Safe uses to deploy its own AgentModule in the delegation ceremony. Sepolia only. */
52
+ agentModuleFactory?: string;
51
53
  mockUsdcToken?: string;
52
54
  mockUsdcOwner?: string;
53
55
  mockUsdtToken?: string;
@@ -148,6 +148,98 @@ export declare class DiamondHandsSDK {
148
148
  * No-op in standalone mode (no server session to prime).
149
149
  */
150
150
  primeServerSession(payload: DhServerLoginPayload): Promise<void>;
151
+ /**
152
+ * Build the Safe-delegation ceremony for a multi-sig Safe (Phase 1 of
153
+ * multi-sig support): asks lit-ops-server to mint (or recover) the Safe's
154
+ * agent PKP and returns the exact call batch the Safe's owners must execute
155
+ * (AgentModuleFactory.deploy → safe.enableModule → registerAgent), derived
156
+ * from live chain state so a half-done ceremony resumes.
157
+ *
158
+ * Service-mode only — the server holds the Chipotle account that mints the
159
+ * PKP and it gates the route to current Safe owners. `knownAgentAddress` is
160
+ * the caller-persisted agent from an earlier prepare whose ceremony has not
161
+ * landed yet; echoing it back prevents a duplicate mint after a server
162
+ * restart.
163
+ */
164
+ prepareSafeAgentModule(request: {
165
+ safeAddress: string;
166
+ knownAgentAddress?: string;
167
+ }): Promise<{
168
+ status: "ready" | "already-delegated";
169
+ agentAddress: string;
170
+ moduleAddress: string;
171
+ validUntil: number | null;
172
+ calls: {
173
+ to: string;
174
+ data: string;
175
+ value: string;
176
+ }[];
177
+ }>;
178
+ /**
179
+ * Shared transport for `/agent-module/{authorize,execute}`.
180
+ *
181
+ * Both routes run the agent PKP's key inside a Lit Action, gated on the
182
+ * caller's session being a CURRENT Safe owner (M-8c). Service-mode only, for
183
+ * the same reason as {@link prepareSafeAgentModule}: the key lives in the
184
+ * server's Chipotle account and has no standalone equivalent.
185
+ */
186
+ private postAgentModuleRoute;
187
+ /**
188
+ * The agent signs the borrower authorization envelope for `op` on `positionId`.
189
+ *
190
+ * The returned `{ timestamp, signature }` feeds the SDK's PRECOMPUTED
191
+ * authorization path (`generateExtendAuthorization` and siblings) — the same
192
+ * path Safe/EIP-1271 borrowers already use. It is NOT a generic message
193
+ * signer: the Lit Action REBUILDS the envelope from these fields rather than
194
+ * signing anything the caller supplies, which is what stops a delegated agent
195
+ * key being turned into an arbitrary oracle.
196
+ *
197
+ * `timestamp` must be quantum-aligned by the caller
198
+ * (`calculateNextQuantumTimestamp()`) and must be the SAME value later passed
199
+ * to the protocol call, or the validator recovers a different signer.
200
+ */
201
+ agentModuleAuthorize(request: {
202
+ safeAddress: string;
203
+ positionId: string;
204
+ op: "mint" | "repay" | "renew" | "withdraw";
205
+ timestamp: number;
206
+ amount?: string;
207
+ selectedTerm?: number;
208
+ }): Promise<{
209
+ module: string;
210
+ agent: string;
211
+ authorization: {
212
+ timestamp: number;
213
+ signature: string;
214
+ signer: string;
215
+ };
216
+ }>;
217
+ /**
218
+ * The agent signs `module.execute(target, innerData)` as a raw EIP-1559
219
+ * transaction. Returns the SIGNED transaction — the caller broadcasts it, so
220
+ * the tx hash and receipt come from the caller's own provider.
221
+ *
222
+ * `tx` fields are caller-supplied because the Lit Action runs on many nodes
223
+ * and reconciles results: anything fetched in-action (nonce, gas) would
224
+ * differ per node and fail consensus.
225
+ */
226
+ agentModuleExecute(request: {
227
+ safeAddress: string;
228
+ positionId: string;
229
+ op: "mint" | "repay" | "renew" | "withdraw";
230
+ target: string;
231
+ innerData: string;
232
+ tx: {
233
+ nonce: number;
234
+ gasLimit: string;
235
+ maxFeePerGas: string;
236
+ maxPriorityFeePerGas: string;
237
+ };
238
+ }): Promise<{
239
+ module: string;
240
+ agent: string;
241
+ signedTransaction: string;
242
+ }>;
151
243
  /**
152
244
  * Audit H-9: invalidate the LoanQuery cache so subsequent reads return
153
245
  * the post-write state. We clear the entire loan-query cache (not just
@@ -448,6 +540,24 @@ export declare class DiamondHandsSDK {
448
540
  * address strings, query the subgraph `WithdrawalAddressBook`.
449
541
  */
450
542
  getApprovedWithdrawalAddresses(user?: string): Promise<Result<import("./withdrawal-address/withdrawal-address.module").WithdrawalAddressEntry[], SDKError>>;
543
+ /**
544
+ * Recover the revert reason of an already-mined, already-reverted transaction.
545
+ *
546
+ * A status-0 receipt carries no revert data, and ethers does not re-fetch it, so
547
+ * the reason has to be recovered by replaying the exact calldata as an `eth_call`
548
+ * pinned to the block that mined it — the only block whose `block.timestamp`
549
+ * reproduces a timing-dependent revert such as `DeadZoneViolation()`.
550
+ *
551
+ * Caveat: the replay runs against end-of-block state rather than the state at the
552
+ * transaction's own index, so for a state-dependent revert the recovered name is
553
+ * diagnostic, not proof. Timing reverts (the case this exists for) are unaffected —
554
+ * they depend only on the block timestamp.
555
+ *
556
+ * @returns the decoded error name, its raw selector if unknown, or `null` when the
557
+ * replay yields no revert data at all (never throws — a failed diagnosis
558
+ * must not mask the underlying failure).
559
+ */
560
+ private decodeMinedRevert;
451
561
  /**
452
562
  * Withdraw Bitcoin from a position
453
563
  *
@@ -509,6 +619,11 @@ export declare class DiamondHandsSDK {
509
619
  * The service path's post-broadcast CRIT-2 re-verification exists to catch
510
620
  * a LYING SERVER; here the broadcast happens locally from the signatures we
511
621
  * just obtained, so the esplora-returned txid is already first-hand.
622
+ *
623
+ * Multi-UTXO consolidation in standalone mode requires the caller to supply
624
+ * `request.utxos` explicitly — `fetchConfirmedVaultUtxos` is service-mode
625
+ * only, so there is no automatic gather here; without the set, a multi-UTXO
626
+ * vault fails in the signer with its "Insufficient UTXO value" error.
512
627
  */
513
628
  private executeBTCWithdrawalStandalonePhase2;
514
629
  executeBTCWithdrawal(request: {
@@ -903,6 +1018,25 @@ export declare class DiamondHandsSDK {
903
1018
  * and catching — `ALL_DEPLOYMENTS` is published on the `@gvnrdao/dh-sdk/deployments` subpath.
904
1019
  */
905
1020
  private agentDelegationRegistryOrThrow;
1021
+ /**
1022
+ * `LoanGrant` fields that EVERY deployed registry version returns.
1023
+ *
1024
+ * Deliberately omits `minWithdrawRatioBps` — see {@link readLoanGrant}.
1025
+ */
1026
+ private static readonly LOAN_GRANT_PREFIX_IFACE;
1027
+ /**
1028
+ * Read a position's grant, decoding only the struct prefix that every deployed registry
1029
+ * version shares.
1030
+ *
1031
+ * `LoanGrant` gained a fourth member (`minWithdrawRatioBps`) in registry v2.1.0, and the
1032
+ * typechain bindings are generated from that source — but Sepolia (`0x6AE7fc6b…`) and mainnet
1033
+ * (`0x54853b7E…`) both run v2.0.0, whose `getLoanGrant` returns three words. Decoding that
1034
+ * with the generated four-field decoder fails `BAD_DATA` on every live chain, which is what
1035
+ * took the Agents tab down. The first three members are identical in both layouts, and ethers
1036
+ * ignores the trailing static word on a v2.1.0 registry, so this decoder is correct against
1037
+ * both. Nothing in this SDK reads `minWithdrawRatioBps`: WITHDRAW is not a scope it grants.
1038
+ */
1039
+ private readLoanGrant;
906
1040
  /**
907
1041
  * Read a position's auto-renew delegation state (used to drive the Enable/Disable toggle).
908
1042
  * Pure view — no signer required.
@@ -916,6 +1050,49 @@ export declare class DiamondHandsSDK {
916
1050
  reason: number;
917
1051
  } | null;
918
1052
  }>;
1053
+ /**
1054
+ * Read every delegation scope a position has granted, plus the mint floor and the protocol
1055
+ * minimum the UI must clamp its editor to. Pure view — no signer required.
1056
+ *
1057
+ * Superset of `getAutoRenewStatus`, which predates the multi-scope UI and is kept for
1058
+ * callers that only care about renew.
1059
+ */
1060
+ getDelegationStatus(positionId: string, user?: string): Promise<{
1061
+ renewEnabled: boolean;
1062
+ repayEnabled: boolean;
1063
+ mintEnabled: boolean;
1064
+ /** Grant's post-mint CR floor in bps; 0 when MINT is not granted. */
1065
+ minCollateralRatioBps: number;
1066
+ /** What `canMint` actually enforces: `max(grant floor, protocol min)`. 0 when not granted. */
1067
+ effectiveMintFloorBps: number;
1068
+ /** Governance floor-of-floors — the lowest value the user may set (15000 = 150%). */
1069
+ protocolMinFloorBps: number;
1070
+ borrower: string;
1071
+ agentActive: boolean | null;
1072
+ /** Agent expiry (unix seconds) — the ONLY time bound on every grant. Null without `user`. */
1073
+ agentValidUntil: number | null;
1074
+ }>;
1075
+ /** Governance floor-of-floors for agent mints (bps). The UI's minimum for the floor editor. */
1076
+ getAgentMintFloorMinBps(): Promise<number>;
1077
+ /**
1078
+ * Shared enable-path preamble for EVERY scope: resolve the registry, ensure the borrower has
1079
+ * an active agent (minting + registering a per-user PKP on first use), and make that agent the
1080
+ * position's Gate-1 delegate. Returns the signer-connected registry and the agent address.
1081
+ *
1082
+ * Every `enableAuto*` runs this: the registry reverts `NoActiveAgent` without an agent, and
1083
+ * `lit-ops-server.isPositionDelegate` 403s the agent on the execute routes without Gate 1 —
1084
+ * so a scope enabled without this preamble would look on but never execute.
1085
+ */
1086
+ private prepareAgentDelegation;
1087
+ /**
1088
+ * Shared disable-path epilogue: drop the position's Gate-1 delegate, but ONLY once no scope
1089
+ * remains. Scopes compose, so clearing Gate 1 on every disable would silently break the
1090
+ * surviving ones server-side (the agent would 403 on the execute routes while its remaining
1091
+ * grant still reads as enabled on-chain).
1092
+ *
1093
+ * Also refuses to clobber a delegate registered for anything other than this user's agent.
1094
+ */
1095
+ private clearGate1IfNoScopesRemain;
919
1096
  /**
920
1097
  * Enable auto-renew delegation for a position. Orchestrates the first-time setup: if the
921
1098
  * borrower has no active agent, mints a fresh per-user agent PKP (via lit-ops-server) and
@@ -938,6 +1115,54 @@ export declare class DiamondHandsSDK {
938
1115
  hash: string;
939
1116
  blockNumber: number;
940
1117
  }>;
1118
+ /**
1119
+ * Enable auto-repay delegation: the agent may repay this position's debt on the borrower's
1120
+ * behalf. Deliberately uncapped in the registry — repay only ever burns the borrower's own
1121
+ * debt from the borrower's own funds, and the ERC-20 allowance to PositionManager (never
1122
+ * granted to the agent) is the natural bound. Borrower-signed.
1123
+ */
1124
+ enableAutoRepay(positionId: string, options?: {
1125
+ agentValiditySeconds?: number;
1126
+ }): Promise<{
1127
+ hash: string;
1128
+ blockNumber: number;
1129
+ agentAddress?: string;
1130
+ }>;
1131
+ /** Disable auto-repay delegation for a position. Borrower-signed. */
1132
+ disableAutoRepay(positionId: string): Promise<{
1133
+ hash: string;
1134
+ blockNumber: number;
1135
+ }>;
1136
+ /**
1137
+ * Enable auto-mint delegation with a post-mint collateral-ratio floor (bps) the mint validator
1138
+ * enforces. `minCollateralRatioBps` must be at or above the governance minimum
1139
+ * (`getAgentMintFloorMinBps()`, 15000 = 150%) — checked here so the caller gets a readable
1140
+ * error instead of a `FloorBelowProtocolMin` revert after signing. Borrower-signed.
1141
+ */
1142
+ enableAutoMint(positionId: string, minCollateralRatioBps: number, options?: {
1143
+ agentValiditySeconds?: number;
1144
+ }): Promise<{
1145
+ hash: string;
1146
+ blockNumber: number;
1147
+ agentAddress?: string;
1148
+ }>;
1149
+ /** Disable auto-mint delegation for a position (also zeroes its mint floor). Borrower-signed. */
1150
+ disableAutoMint(positionId: string): Promise<{
1151
+ hash: string;
1152
+ blockNumber: number;
1153
+ }>;
1154
+ /**
1155
+ * Change an existing mint grant's collateral floor in place — no disable/re-enable dance.
1156
+ * MINT must already be granted; the new floor must clear the governance minimum. Note the
1157
+ * borrower may move it in either direction (above the minimum); only `REGISTRAR_ROLE` is
1158
+ * restricted to raising. Borrower-signed.
1159
+ */
1160
+ setMintCollateralFloor(positionId: string, newFloorBps: number): Promise<{
1161
+ hash: string;
1162
+ blockNumber: number;
1163
+ }>;
1164
+ /** Pre-flight the registry's `FloorBelowProtocolMin` guard with a message a user can act on. */
1165
+ private assertMintFloorAtOrAboveProtocolMin;
941
1166
  /**
942
1167
  * Get Bitcoin balance for an address
943
1168
  *
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Narrow entry point for Safe agent-delegation reads.
3
+ *
4
+ * A SUBPATH rather than a main-index re-export, for two reasons the frontend
5
+ * learned the hard way:
6
+ *
7
+ * - the app shadows the bare `@gvnrdao/dh-sdk` specifier with a hand-written
8
+ * ambient module (`types/@gvnrdao__dh-sdk.d.ts`), so anything imported from
9
+ * there is UNCHECKED against the real package — a call could take wrong
10
+ * arguments and still compile. Subpaths escape the shim and get the
11
+ * package's own types;
12
+ * - the main index pulls the whole SDK (and `@gvnrdao/dh-lit-actions`) for what
13
+ * is a handful of `eth_call`s.
14
+ */
15
+ export { getSafeAgentDelegation, buildSafeAgentDelegationDisableCalls, type SafeAgentDelegation, type SafeAgentDelegationDisablePlan, type SafeDelegationCall, type SafeDelegationStatus, } from "./utils/safe-agent-delegation.utils";