@gvnrdao/dh-sdk 0.0.328 → 0.0.330

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.
@@ -521,6 +521,14 @@ var MAINNET_DEPLOYMENT = {
521
521
  reason: "2026-08 agent-stack release. The mainnet PositionManagerViews at 0x9225647a was deployed as a BARE implementation (EIP-1967 slot 0x00), so upgradeToAndCall reverts UUPSUnauthorizedCallContext \u2014 it could never be upgraded. PositionManager.setViews (added in the same Execute B batch) removed the repoint blocker, so Views was replaced behind a new proxy rather than upgraded. This makes the Pashov F3 renewal debt-ceiling check REACHABLE for the first time: ExceedsMaxLoan (0x499e7985) is present in 0xE68DC096 and absent from 0x9225647a. Views holds no protocol state (8 wiring slots + roles + pause), which is what made replacement safe. The old contract is ABANDONED, not decommissioned \u2014 it stays live and callable as the rollback target for setViews. NOTE: VERSION reads 1.1.1 on both sides; verify by address.",
522
522
  executeTx: "0xf1f8d5fc13f45d7a3f932bf1a2d6e29381fdd41cd31298ad785bf7688df07fe6",
523
523
  block: 25673200
524
+ },
525
+ AgentDelegationRegistry: {
526
+ newImplementation: "0xa9fF405Edd4329fc3159a64F56B37EBD253e4928",
527
+ upgradedAt: "2026-07-31T22:03:35.000Z",
528
+ upgradedBy: "AdminModule/Safe audit-batch upgradeToAndCall; executed by 0xEba7BfAeB35ee18408b424Ee0BB45AdDf776589f in tx 0x8fed0ab7eee3aaaa3792a35b40b0ef74bd09cfb1a175934afd846bee546048d4 (block 25655710)",
529
+ reason: "Reconciled from chain \u2014 mainnet audit rollout batch (cross-ref onchain-auth/.safe-batches/mainnet-audit-execute.json)",
530
+ executeTx: "0x8fed0ab7eee3aaaa3792a35b40b0ef74bd09cfb1a175934afd846bee546048d4",
531
+ block: 25655710
524
532
  }
525
533
  },
526
534
  latestEnv: {
@@ -488,6 +488,14 @@ var MAINNET_DEPLOYMENT = {
488
488
  reason: "2026-08 agent-stack release. The mainnet PositionManagerViews at 0x9225647a was deployed as a BARE implementation (EIP-1967 slot 0x00), so upgradeToAndCall reverts UUPSUnauthorizedCallContext \u2014 it could never be upgraded. PositionManager.setViews (added in the same Execute B batch) removed the repoint blocker, so Views was replaced behind a new proxy rather than upgraded. This makes the Pashov F3 renewal debt-ceiling check REACHABLE for the first time: ExceedsMaxLoan (0x499e7985) is present in 0xE68DC096 and absent from 0x9225647a. Views holds no protocol state (8 wiring slots + roles + pause), which is what made replacement safe. The old contract is ABANDONED, not decommissioned \u2014 it stays live and callable as the rollback target for setViews. NOTE: VERSION reads 1.1.1 on both sides; verify by address.",
489
489
  executeTx: "0xf1f8d5fc13f45d7a3f932bf1a2d6e29381fdd41cd31298ad785bf7688df07fe6",
490
490
  block: 25673200
491
+ },
492
+ AgentDelegationRegistry: {
493
+ newImplementation: "0xa9fF405Edd4329fc3159a64F56B37EBD253e4928",
494
+ upgradedAt: "2026-07-31T22:03:35.000Z",
495
+ upgradedBy: "AdminModule/Safe audit-batch upgradeToAndCall; executed by 0xEba7BfAeB35ee18408b424Ee0BB45AdDf776589f in tx 0x8fed0ab7eee3aaaa3792a35b40b0ef74bd09cfb1a175934afd846bee546048d4 (block 25655710)",
496
+ reason: "Reconciled from chain \u2014 mainnet audit rollout batch (cross-ref onchain-auth/.safe-batches/mainnet-audit-execute.json)",
497
+ executeTx: "0x8fed0ab7eee3aaaa3792a35b40b0ef74bd09cfb1a175934afd846bee546048d4",
498
+ block: 25655710
491
499
  }
492
500
  },
493
501
  latestEnv: {
@@ -86,6 +86,174 @@ export interface UserRateLimitData {
86
86
  nextResetBlock: string;
87
87
  lastUpdated: string;
88
88
  }
89
+ export interface LoanEventsQueryResponse {
90
+ position: {
91
+ id: string;
92
+ payments?: Array<{
93
+ id: string;
94
+ payer: {
95
+ id: string;
96
+ };
97
+ amount: string;
98
+ type: string;
99
+ transactionHash: string;
100
+ timestamp: string;
101
+ blockNumber: string;
102
+ logIndex: string;
103
+ newDebt: string;
104
+ newCollateralRatio: string;
105
+ }>;
106
+ statusUpdates?: Array<{
107
+ id: string;
108
+ oldStatus: string;
109
+ newStatus: string;
110
+ reason?: string;
111
+ timestamp: string;
112
+ blockNumber: string;
113
+ transactionHash: string;
114
+ }>;
115
+ liquidation?: {
116
+ id: string;
117
+ liquidator: string;
118
+ liquidatedAmount: string;
119
+ collateralSeized: string;
120
+ transactionHash: string;
121
+ timestamp: string;
122
+ blockNumber: string;
123
+ commitHash?: string;
124
+ commitTimestamp?: string;
125
+ revealDelay?: string;
126
+ };
127
+ withdrawals?: Array<{
128
+ id: string;
129
+ withdrawalAmount: string;
130
+ withdrawalAddress: string;
131
+ networkFee?: string;
132
+ timestamp: string;
133
+ blockNumber: string;
134
+ transactionHash: string;
135
+ logIndex: string;
136
+ }>;
137
+ renewals?: Array<{
138
+ id: string;
139
+ extensionTerm: string;
140
+ extensionFee: string;
141
+ newExpiryDate: string;
142
+ timestamp: string;
143
+ blockNumber: string;
144
+ transactionHash: string;
145
+ logIndex: string;
146
+ }>;
147
+ operationFailures?: Array<{
148
+ id: string;
149
+ operationType: string;
150
+ reason: string;
151
+ errorCode?: string;
152
+ amount?: string;
153
+ timestamp: string;
154
+ blockNumber: string;
155
+ transactionHash: string;
156
+ logIndex: string;
157
+ }>;
158
+ mintRequests?: Array<{
159
+ id: string;
160
+ pkpId: string;
161
+ borrower: {
162
+ id: string;
163
+ };
164
+ mintAmount: string;
165
+ originationFee: string;
166
+ newDebt: string;
167
+ newCollateralRatio: string;
168
+ btcPrice: string;
169
+ quantumTimestamp: string;
170
+ opId: string;
171
+ timestamp: string;
172
+ blockNumber: string;
173
+ transactionHash: string;
174
+ logIndex: string;
175
+ }>;
176
+ burnRequests?: Array<{
177
+ id: string;
178
+ pkpId: string;
179
+ borrower: {
180
+ id: string;
181
+ };
182
+ burnAmount: string;
183
+ remainingDebt: string;
184
+ newCollateralRatio: string;
185
+ opId: string;
186
+ timestamp: string;
187
+ blockNumber: string;
188
+ transactionHash: string;
189
+ logIndex: string;
190
+ }>;
191
+ mintingFees?: Array<{
192
+ id: string;
193
+ borrower: {
194
+ id: string;
195
+ };
196
+ feeAmount: string;
197
+ mintAmount: string;
198
+ newDebt: string;
199
+ btcPrice: string;
200
+ quantumTimestamp: string;
201
+ timestamp: string;
202
+ blockNumber: string;
203
+ transactionHash: string;
204
+ logIndex: string;
205
+ }>;
206
+ renewalFees?: Array<{
207
+ id: string;
208
+ borrower: {
209
+ id: string;
210
+ };
211
+ feeAmount: string;
212
+ extensionTerm: string;
213
+ newExpiryDate: string;
214
+ timestamp: string;
215
+ blockNumber: string;
216
+ transactionHash: string;
217
+ logIndex: string;
218
+ }>;
219
+ };
220
+ positionCreatedEvents?: Array<{
221
+ id: string;
222
+ pkpId: string;
223
+ borrower: {
224
+ id: string;
225
+ };
226
+ requestedCollateralRatio: string;
227
+ selectedTerm: string;
228
+ expiryAt: string;
229
+ timestamp: string;
230
+ blockNumber: string;
231
+ transactionHash: string;
232
+ }>;
233
+ ucdmintEvents?: Array<{
234
+ id: string;
235
+ amount: string;
236
+ proof: string;
237
+ minter: {
238
+ id: string;
239
+ };
240
+ isCommunityMint: boolean;
241
+ timestamp: string;
242
+ blockNumber: string;
243
+ transactionHash: string;
244
+ }>;
245
+ collateralEvents?: Array<{
246
+ id: string;
247
+ eventType: string;
248
+ networkFee?: string;
249
+ remainingCollateral?: string;
250
+ collateralRatio?: string;
251
+ timestamp: string;
252
+ blockNumber: string;
253
+ transactionHash: string;
254
+ logIndex: string;
255
+ }>;
256
+ }
89
257
  export declare class DiamondHandsGraph {
90
258
  private client;
91
259
  private defaultPageSize;
@@ -115,6 +283,15 @@ export declare class DiamondHandsGraph {
115
283
  /**
116
284
  * Get user positions from subgraph
117
285
  */
286
+ private getUserPositionsOnly;
287
+ /**
288
+ * Get user positions, plus an accurate total count.
289
+ *
290
+ * The count is a SECOND round trip (`getTotalCountPaginated`, which pages to handle
291
+ * >1000 items). Callers that only need the rows should use `getUserPositionsOnly` and
292
+ * skip it — the event paths did not, and paid for a count they immediately discarded on
293
+ * every activity refresh.
294
+ */
118
295
  getUserPositions(userAddress: string, first?: number, skip?: number, orderBy?: string, orderDirection?: string): Promise<{
119
296
  positions: LoanData[];
120
297
  total: number;
@@ -262,6 +439,14 @@ export declare class DiamondHandsGraph {
262
439
  * @returns Complete event history for the position
263
440
  */
264
441
  getLoanEvents(positionId: string, filter?: LoanEventsFilter): Promise<LoanEvents>;
442
+ /**
443
+ * Map one position's raw event payload into `LoanEvents`.
444
+ *
445
+ * Extracted verbatim from getLoanEvents so the wallet-collapsed path produces
446
+ * byte-identical objects by construction rather than by a second implementation
447
+ * that has to be kept in step by hand.
448
+ */
449
+ private assembleLoanEvents;
265
450
  /**
266
451
  * Get the full loan-event history for every position owned by a wallet.
267
452
  *
@@ -280,6 +465,31 @@ export declare class DiamondHandsGraph {
280
465
  * @returns One LoanEvents object per position; empty array if the wallet has none.
281
466
  */
282
467
  getWalletLoanEvents(userAddress: string, filter?: LoanEventsFilter): Promise<LoanEvents[]>;
468
+ /**
469
+ * The per-position path: enumerate the wallet's positions, then one `GetLoanEvents` each.
470
+ *
471
+ * Used for filtered calls, and as the completeness fallback when the collapsed document
472
+ * hits a page limit. Costs `1 + N` requests, which is exactly why it is not the default.
473
+ */
474
+ private getWalletLoanEventsFanout;
475
+ /**
476
+ * The whole wallet's event history in ONE request.
477
+ *
478
+ * Replaces `1 + N` round trips (one position enumeration plus one per position) with a
479
+ * single document. Measured on Sepolia: a wallet holding 44 positions cost 46 requests
480
+ * per activity refresh against a per-wallet budget of 30/min — this makes it 1.
481
+ *
482
+ * Three subgraph facts make it possible, all verified against the deployed schema rather
483
+ * than assumed:
484
+ * - ten event collections are `@derivedFrom` on Position, so they nest under a
485
+ * borrower-filtered `positions(...)`;
486
+ * - `positionCreatedEvents` is ALSO derived on Position — `getLoanEvents` queries it
487
+ * top-level, which it never needed to;
488
+ * - `ucdmintEvents` / `collateralEvents` are not derived and carry no `borrower`
489
+ * field, but graph-node's nested `position_: { borrower }` filter reaches them.
490
+ * Without that last one this would be two requests, not one.
491
+ */
492
+ private getWalletLoanEventsCollapsed;
283
493
  /**
284
494
  * Retrieve events across the full protocol, optionally narrowed to a position.
285
495
  * Returns a merged, sorted discriminated-union timeline suitable for explorers.
package/dist/index.js CHANGED
@@ -546,6 +546,14 @@ var init_deployment_addresses = __esm({
546
546
  reason: "2026-08 agent-stack release. The mainnet PositionManagerViews at 0x9225647a was deployed as a BARE implementation (EIP-1967 slot 0x00), so upgradeToAndCall reverts UUPSUnauthorizedCallContext \u2014 it could never be upgraded. PositionManager.setViews (added in the same Execute B batch) removed the repoint blocker, so Views was replaced behind a new proxy rather than upgraded. This makes the Pashov F3 renewal debt-ceiling check REACHABLE for the first time: ExceedsMaxLoan (0x499e7985) is present in 0xE68DC096 and absent from 0x9225647a. Views holds no protocol state (8 wiring slots + roles + pause), which is what made replacement safe. The old contract is ABANDONED, not decommissioned \u2014 it stays live and callable as the rollback target for setViews. NOTE: VERSION reads 1.1.1 on both sides; verify by address.",
547
547
  executeTx: "0xf1f8d5fc13f45d7a3f932bf1a2d6e29381fdd41cd31298ad785bf7688df07fe6",
548
548
  block: 25673200
549
+ },
550
+ AgentDelegationRegistry: {
551
+ newImplementation: "0xa9fF405Edd4329fc3159a64F56B37EBD253e4928",
552
+ upgradedAt: "2026-07-31T22:03:35.000Z",
553
+ upgradedBy: "AdminModule/Safe audit-batch upgradeToAndCall; executed by 0xEba7BfAeB35ee18408b424Ee0BB45AdDf776589f in tx 0x8fed0ab7eee3aaaa3792a35b40b0ef74bd09cfb1a175934afd846bee546048d4 (block 25655710)",
554
+ reason: "Reconciled from chain \u2014 mainnet audit rollout batch (cross-ref onchain-auth/.safe-batches/mainnet-audit-execute.json)",
555
+ executeTx: "0x8fed0ab7eee3aaaa3792a35b40b0ef74bd09cfb1a175934afd846bee546048d4",
556
+ block: 25655710
549
557
  }
550
558
  },
551
559
  latestEnv: {
@@ -12120,6 +12128,169 @@ function normalizePkpId2(pkpId) {
12120
12128
  }
12121
12129
  return pkpId;
12122
12130
  }
12131
+ function hasLoanEventsFilter(filter) {
12132
+ if (!filter)
12133
+ return false;
12134
+ return filter.eventTypes !== void 0 || filter.fromTimestamp !== void 0 || filter.toTimestamp !== void 0 || filter.fromBlock !== void 0 || filter.toBlock !== void 0 || filter.limit !== void 0 || filter.orderDirection !== void 0;
12135
+ }
12136
+ var WALLET_LOAN_EVENTS_QUERY = `
12137
+ query GetWalletLoanEvents($borrower: Bytes!, $first: Int!, $limit: Int!, $orderDirection: OrderDirection!) {
12138
+ positions(where: { borrower: $borrower }, first: $first, orderBy: id) {
12139
+ id
12140
+ payments(first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12141
+ id
12142
+ payer { id }
12143
+ amount
12144
+ type
12145
+ transactionHash
12146
+ timestamp
12147
+ blockNumber
12148
+ logIndex
12149
+ newDebt
12150
+ newCollateralRatio
12151
+ }
12152
+ statusUpdates(first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12153
+ id
12154
+ oldStatus
12155
+ newStatus
12156
+ reason
12157
+ timestamp
12158
+ blockNumber
12159
+ transactionHash
12160
+ }
12161
+ liquidation {
12162
+ id
12163
+ liquidator
12164
+ liquidatedAmount
12165
+ collateralSeized
12166
+ transactionHash
12167
+ timestamp
12168
+ blockNumber
12169
+ commitHash
12170
+ commitTimestamp
12171
+ revealDelay
12172
+ }
12173
+ withdrawals(first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12174
+ id
12175
+ withdrawalAmount
12176
+ withdrawalAddress
12177
+ networkFee
12178
+ timestamp
12179
+ blockNumber
12180
+ transactionHash
12181
+ logIndex
12182
+ }
12183
+ renewals(first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12184
+ id
12185
+ extensionTerm
12186
+ extensionFee
12187
+ newExpiryDate
12188
+ timestamp
12189
+ blockNumber
12190
+ transactionHash
12191
+ logIndex
12192
+ }
12193
+ operationFailures(first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12194
+ id
12195
+ operationType
12196
+ reason
12197
+ errorCode
12198
+ amount
12199
+ timestamp
12200
+ blockNumber
12201
+ transactionHash
12202
+ logIndex
12203
+ }
12204
+ mintRequests(first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12205
+ id
12206
+ pkpId
12207
+ borrower { id }
12208
+ mintAmount
12209
+ originationFee
12210
+ newDebt
12211
+ newCollateralRatio
12212
+ btcPrice
12213
+ quantumTimestamp
12214
+ opId
12215
+ timestamp
12216
+ blockNumber
12217
+ transactionHash
12218
+ logIndex
12219
+ }
12220
+ burnRequests(first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12221
+ id
12222
+ pkpId
12223
+ borrower { id }
12224
+ burnAmount
12225
+ remainingDebt
12226
+ newCollateralRatio
12227
+ opId
12228
+ timestamp
12229
+ blockNumber
12230
+ transactionHash
12231
+ logIndex
12232
+ }
12233
+ mintingFees(first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12234
+ id
12235
+ borrower { id }
12236
+ feeAmount
12237
+ mintAmount
12238
+ newDebt
12239
+ btcPrice
12240
+ quantumTimestamp
12241
+ timestamp
12242
+ blockNumber
12243
+ transactionHash
12244
+ logIndex
12245
+ }
12246
+ renewalFees(first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12247
+ id
12248
+ borrower { id }
12249
+ feeAmount
12250
+ extensionTerm
12251
+ newExpiryDate
12252
+ timestamp
12253
+ blockNumber
12254
+ transactionHash
12255
+ logIndex
12256
+ }
12257
+ positionCreatedEvents(first: 1, orderBy: timestamp, orderDirection: asc) {
12258
+ id
12259
+ pkpId
12260
+ borrower { id }
12261
+ requestedCollateralRatio
12262
+ selectedTerm
12263
+ expiryAt
12264
+ timestamp
12265
+ blockNumber
12266
+ transactionHash
12267
+ }
12268
+ }
12269
+ ucdmintEvents(where: { position_: { borrower: $borrower } }, first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12270
+ id
12271
+ position { id }
12272
+ amount
12273
+ proof
12274
+ minter { id }
12275
+ isCommunityMint
12276
+ timestamp
12277
+ blockNumber
12278
+ transactionHash
12279
+ }
12280
+ collateralEvents(where: { position_: { borrower: $borrower } }, first: $limit, orderBy: timestamp, orderDirection: $orderDirection) {
12281
+ id
12282
+ position { id }
12283
+ eventType
12284
+ networkFee
12285
+ remainingCollateral
12286
+ collateralRatio
12287
+ timestamp
12288
+ blockNumber
12289
+ transactionHash
12290
+ logIndex
12291
+ }
12292
+ }
12293
+ `;
12123
12294
  var DiamondHandsGraph = class {
12124
12295
  client;
12125
12296
  defaultPageSize;
@@ -12225,7 +12396,7 @@ var DiamondHandsGraph = class {
12225
12396
  /**
12226
12397
  * Get user positions from subgraph
12227
12398
  */
12228
- async getUserPositions(userAddress, first, skip, orderBy, orderDirection) {
12399
+ async getUserPositionsOnly(userAddress, first, skip, orderBy, orderDirection) {
12229
12400
  const query = `
12230
12401
  query GetUserPositions($borrower: Bytes!, $first: Int, $skip: Int, $orderBy: Position_orderBy, $orderDirection: OrderDirection) {
12231
12402
  user(id: $borrower) {
@@ -12266,17 +12437,28 @@ var DiamondHandsGraph = class {
12266
12437
  query,
12267
12438
  variables
12268
12439
  );
12269
- const total = await this.getTotalCountPaginated("{ borrower: $borrower }", {
12270
- borrower: userAddress.toLowerCase()
12271
- });
12272
12440
  let positions = [];
12273
12441
  if (result && result.user && Array.isArray(result.user.positions)) {
12274
12442
  positions = result.user.positions.filter((p) => p != null).map((p) => this.transformGraphPositionToLoanData(p));
12275
12443
  }
12276
- return {
12277
- positions,
12278
- total
12279
- };
12444
+ return positions;
12445
+ }
12446
+ /**
12447
+ * Get user positions, plus an accurate total count.
12448
+ *
12449
+ * The count is a SECOND round trip (`getTotalCountPaginated`, which pages to handle
12450
+ * >1000 items). Callers that only need the rows should use `getUserPositionsOnly` and
12451
+ * skip it — the event paths did not, and paid for a count they immediately discarded on
12452
+ * every activity refresh.
12453
+ */
12454
+ async getUserPositions(userAddress, first, skip, orderBy, orderDirection) {
12455
+ const [positions, total] = await Promise.all([
12456
+ this.getUserPositionsOnly(userAddress, first, skip, orderBy, orderDirection),
12457
+ this.getTotalCountPaginated("{ borrower: $borrower }", {
12458
+ borrower: userAddress.toLowerCase()
12459
+ })
12460
+ ]);
12461
+ return { positions, total };
12280
12462
  }
12281
12463
  /**
12282
12464
  * Get user positions with enriched Bitcoin balance data
@@ -13367,6 +13549,16 @@ var DiamondHandsGraph = class {
13367
13549
  orderDirection
13368
13550
  };
13369
13551
  const result = await this.client.execute(query, variables);
13552
+ return this.assembleLoanEvents(positionId, result);
13553
+ }
13554
+ /**
13555
+ * Map one position's raw event payload into `LoanEvents`.
13556
+ *
13557
+ * Extracted verbatim from getLoanEvents so the wallet-collapsed path produces
13558
+ * byte-identical objects by construction rather than by a second implementation
13559
+ * that has to be kept in step by hand.
13560
+ */
13561
+ assembleLoanEvents(positionId, result) {
13370
13562
  const rawCreated = result.positionCreatedEvents?.[0];
13371
13563
  const positionCreated = rawCreated ? {
13372
13564
  id: rawCreated.id,
@@ -13571,7 +13763,22 @@ var DiamondHandsGraph = class {
13571
13763
  * @returns One LoanEvents object per position; empty array if the wallet has none.
13572
13764
  */
13573
13765
  async getWalletLoanEvents(userAddress, filter) {
13574
- const { positions } = await this.getUserPositions(userAddress);
13766
+ if (!hasLoanEventsFilter(filter)) {
13767
+ return this.getWalletLoanEventsCollapsed(userAddress);
13768
+ }
13769
+ return this.getWalletLoanEventsFanout(userAddress, filter);
13770
+ }
13771
+ /**
13772
+ * The per-position path: enumerate the wallet's positions, then one `GetLoanEvents` each.
13773
+ *
13774
+ * Used for filtered calls, and as the completeness fallback when the collapsed document
13775
+ * hits a page limit. Costs `1 + N` requests, which is exactly why it is not the default.
13776
+ */
13777
+ async getWalletLoanEventsFanout(userAddress, filter) {
13778
+ const positions = await this.getUserPositionsOnly(
13779
+ userAddress,
13780
+ THE_GRAPH_MAX_BATCH_SIZE
13781
+ );
13575
13782
  const positionIds = positions.map((p) => p?.id != null ? String(p.id) : "").filter((id) => id.length > 0);
13576
13783
  if (positionIds.length === 0)
13577
13784
  return [];
@@ -13586,6 +13793,81 @@ var DiamondHandsGraph = class {
13586
13793
  }
13587
13794
  return results;
13588
13795
  }
13796
+ /**
13797
+ * The whole wallet's event history in ONE request.
13798
+ *
13799
+ * Replaces `1 + N` round trips (one position enumeration plus one per position) with a
13800
+ * single document. Measured on Sepolia: a wallet holding 44 positions cost 46 requests
13801
+ * per activity refresh against a per-wallet budget of 30/min — this makes it 1.
13802
+ *
13803
+ * Three subgraph facts make it possible, all verified against the deployed schema rather
13804
+ * than assumed:
13805
+ * - ten event collections are `@derivedFrom` on Position, so they nest under a
13806
+ * borrower-filtered `positions(...)`;
13807
+ * - `positionCreatedEvents` is ALSO derived on Position — `getLoanEvents` queries it
13808
+ * top-level, which it never needed to;
13809
+ * - `ucdmintEvents` / `collateralEvents` are not derived and carry no `borrower`
13810
+ * field, but graph-node's nested `position_: { borrower }` filter reaches them.
13811
+ * Without that last one this would be two requests, not one.
13812
+ */
13813
+ async getWalletLoanEventsCollapsed(userAddress) {
13814
+ const borrower = userAddress.toLowerCase();
13815
+ const pageSize = THE_GRAPH_MAX_BATCH_SIZE;
13816
+ const result = await this.client.execute(
13817
+ WALLET_LOAN_EVENTS_QUERY,
13818
+ {
13819
+ borrower,
13820
+ first: pageSize,
13821
+ limit: pageSize,
13822
+ orderDirection: "desc"
13823
+ }
13824
+ );
13825
+ const positions = result.positions || [];
13826
+ const ucdmintEvents = result.ucdmintEvents || [];
13827
+ const collateralEvents = result.collateralEvents || [];
13828
+ const truncated = positions.length >= pageSize || ucdmintEvents.length >= pageSize || collateralEvents.length >= pageSize;
13829
+ if (truncated) {
13830
+ log.warn(
13831
+ "[DiamondHandsGraph] wallet event page limit reached \u2014 falling back to the per-position path to avoid returning a partial history",
13832
+ {
13833
+ borrower,
13834
+ pageSize,
13835
+ positions: positions.length,
13836
+ ucdmintEvents: ucdmintEvents.length,
13837
+ collateralEvents: collateralEvents.length
13838
+ }
13839
+ );
13840
+ return this.getWalletLoanEventsFanout(userAddress);
13841
+ }
13842
+ if (positions.length === 0)
13843
+ return [];
13844
+ const mintsByPosition = /* @__PURE__ */ new Map();
13845
+ for (const m of result.ucdmintEvents || []) {
13846
+ const key = m.position?.id;
13847
+ if (!key)
13848
+ continue;
13849
+ const bucket = mintsByPosition.get(key) || [];
13850
+ bucket.push(m);
13851
+ mintsByPosition.set(key, bucket);
13852
+ }
13853
+ const collateralByPosition = /* @__PURE__ */ new Map();
13854
+ for (const c of result.collateralEvents || []) {
13855
+ const key = c.position?.id;
13856
+ if (!key)
13857
+ continue;
13858
+ const bucket = collateralByPosition.get(key) || [];
13859
+ bucket.push(c);
13860
+ collateralByPosition.set(key, bucket);
13861
+ }
13862
+ return positions.map(
13863
+ (p) => this.assembleLoanEvents(p.id, {
13864
+ position: p,
13865
+ positionCreatedEvents: p.positionCreatedEvents || [],
13866
+ ucdmintEvents: mintsByPosition.get(p.id) || [],
13867
+ collateralEvents: collateralByPosition.get(p.id) || []
13868
+ })
13869
+ );
13870
+ }
13589
13871
  // ============================================================================
13590
13872
  // Protocol-wide Events
13591
13873
  // ============================================================================
@@ -18496,16 +18778,6 @@ var import_dh_lit_ops = require("@gvnrdao/dh-lit-ops");
18496
18778
  var import_dh_lit_actions2 = __toESM(require_pkg_src());
18497
18779
 
18498
18780
  // src/utils/telegram-messaging.utils.ts
18499
- var TelegramBot = null;
18500
- try {
18501
- if (typeof window === "undefined" && typeof global !== "undefined") {
18502
- TelegramBot = require("node-telegram-bot-api");
18503
- }
18504
- } catch (error) {
18505
- log.warn("Telegram bot API not available", {
18506
- error: error instanceof Error ? error.message : String(error)
18507
- });
18508
- }
18509
18781
  function formatMintMessage(mintAmount, loanId, txHash) {
18510
18782
  return `\u2705 DH SDK: ${mintAmount} UCD was minted for loan id: ${loanId} Tx: https://sepolia.etherscan.io/tx/${txHash}`;
18511
18783
  }