@augustdigital/sdk 8.17.0 → 8.20.1

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.
Files changed (38) hide show
  1. package/lib/adapters/evm/index.js +4 -2
  2. package/lib/adapters/stellar/soroban.d.ts +8 -3
  3. package/lib/adapters/stellar/soroban.js +9 -4
  4. package/lib/adapters/sui/constants.d.ts +1 -1
  5. package/lib/adapters/sui/constants.js +6 -1
  6. package/lib/core/analytics/constants.d.ts +1 -1
  7. package/lib/core/analytics/constants.js +1 -1
  8. package/lib/core/analytics/sentry.d.ts +7 -0
  9. package/lib/core/analytics/sentry.js +182 -1
  10. package/lib/core/analytics/version.d.ts +1 -1
  11. package/lib/core/analytics/version.js +1 -1
  12. package/lib/core/attribution.d.ts +111 -0
  13. package/lib/core/attribution.js +142 -0
  14. package/lib/core/base.class.d.ts +17 -1
  15. package/lib/core/base.class.js +6 -1
  16. package/lib/core/constants/core.js +42 -15
  17. package/lib/core/constants/web3.d.ts +17 -0
  18. package/lib/core/constants/web3.js +22 -1
  19. package/lib/core/fetcher.js +10 -1
  20. package/lib/core/helpers/chain-error.d.ts +140 -0
  21. package/lib/core/helpers/chain-error.js +412 -0
  22. package/lib/core/helpers/chain-support.d.ts +80 -0
  23. package/lib/core/helpers/chain-support.js +115 -0
  24. package/lib/core/helpers/signer.d.ts +21 -0
  25. package/lib/core/helpers/signer.js +52 -0
  26. package/lib/core/helpers/web3.d.ts +172 -3
  27. package/lib/core/helpers/web3.js +357 -49
  28. package/lib/core/index.d.ts +2 -0
  29. package/lib/core/index.js +2 -0
  30. package/lib/evm/methods/crossChainVault.js +4 -0
  31. package/lib/modules/vaults/getters.js +115 -23
  32. package/lib/modules/vaults/main.d.ts +24 -3
  33. package/lib/modules/vaults/main.js +32 -31
  34. package/lib/modules/vaults/write.actions.d.ts +41 -1
  35. package/lib/modules/vaults/write.actions.js +302 -86
  36. package/lib/sdk.d.ts +11315 -10736
  37. package/lib/services/subgraph/vaults.js +85 -14
  38. package/package.json +1 -1
@@ -352,6 +352,51 @@ async function getVaultSubaccountLoans(vault, options) {
352
352
  throw new Error(`#getVaultSubaccountLoans::${vault}:${e?.message}`);
353
353
  }
354
354
  }
355
+ /**
356
+ * HTTP statuses that mean "no such record for this subaccount", not "something
357
+ * broke". The backend returns 404 for a subaccount with no CeFi/OTC position,
358
+ * which is the normal case for most vault borrowers.
359
+ */
360
+ const EXPECTED_SUBACCOUNT_FETCH_STATUSES = new Set([204, 404]);
361
+ /**
362
+ * Log a per-subaccount enrichment fetch failure at the right severity.
363
+ *
364
+ * Why: `getVaultAllocations` issues one CeFi and one OTC request per borrower
365
+ * on every call. Logging the "no record" responses at `error` level captured
366
+ * them as Sentry issues, producing thousands of `AugustServerError: Request
367
+ * failed: 404` events a day for a condition that is not a fault and that
368
+ * callers never need to act on. Expected statuses become breadcrumbs; genuine
369
+ * failures (5xx, auth, transport) stay at `error`.
370
+ *
371
+ * @param tag - Call-site tag, e.g. `getVaultAllocations:cefi`. Becomes the
372
+ * `sdk.origin` Sentry tag for grouping.
373
+ * @param status - HTTP status, or `undefined` when the failure was a thrown
374
+ * transport/typed error with no status attached.
375
+ * @param detail - Status text or error to attach as context.
376
+ * @param context - Identifiers scoping the failure (`vault`, `borrower`).
377
+ */
378
+ function logSubaccountFetchFailure(tag, status, detail, context) {
379
+ if (status !== undefined && EXPECTED_SUBACCOUNT_FETCH_STATUSES.has(status)) {
380
+ core_1.Logger.log.warn(tag, { ...context, status, reason: 'no record' });
381
+ return;
382
+ }
383
+ core_1.Logger.log.error(tag, detail, { ...context, status });
384
+ }
385
+ /**
386
+ * Extract the HTTP status from a thrown fetch error, when it carries one.
387
+ *
388
+ * `fetchAugustWithKey` throws `AugustServerError`/`AugustAuthError` for non-2xx
389
+ * responses, so the status-code branch in the callers is unreachable for those
390
+ * — the status has to be recovered from the error to classify it.
391
+ *
392
+ * @param error - Any thrown value.
393
+ * @returns The HTTP status, or `undefined` for errors without one (network
394
+ * failures, aborts, programming errors).
395
+ */
396
+ function httpStatusFromError(error) {
397
+ const status = error?.status;
398
+ return typeof status === 'number' ? status : undefined;
399
+ }
355
400
  /**
356
401
  * Vault Allocations
357
402
  */
@@ -485,22 +530,26 @@ async function getVaultAllocations(vault, options) {
485
530
  }
486
531
  }
487
532
  else {
488
- core_1.Logger.log.error(`getVaultAllocations:no_fetcher`, new Error(`No portfolio fetcher for chain type: ${chainType}`), {
533
+ // Not an error: portfolio providers simply have no coverage for this
534
+ // chain type yet (Stellar, Sui). Reporting it as an exception filled
535
+ // Sentry with a known, permanent gap, and setting `debankErr` made
536
+ // every Stellar vault throw `failure to fetch debank response`
537
+ // instead of returning the CeFi/OTC/loan allocations it did resolve.
538
+ core_1.Logger.log.warn(`getVaultAllocations:no_fetcher`, {
489
539
  vault,
490
540
  borrower,
491
541
  chainType,
542
+ reason: `No portfolio fetcher for chain type: ${chainType}`,
492
543
  });
493
- debankErr = true;
494
544
  }
495
545
  }
496
546
  // fetch cefi_positions
497
547
  try {
498
548
  const cefiResponse = await (0, core_1.fetchAugustWithKey)(options.augustKey, core_1.WEBSERVER_ENDPOINTS.subaccount.cefi(borrower), { headers: options?.headers });
499
549
  if (cefiResponse.status !== 200) {
500
- core_1.Logger.log.error('getVaultAllocations:cefi', cefiResponse.statusText, {
501
- borrower,
502
- status: cefiResponse.status,
503
- });
550
+ // 404 means "this subaccount has no CeFi position", which is the
551
+ // common case for most borrowers — a breadcrumb, not an exception.
552
+ logSubaccountFetchFailure('getVaultAllocations:cefi', cefiResponse.status, cefiResponse.statusText, { vault, borrower });
504
553
  }
505
554
  if (cefiResponse.status === 200) {
506
555
  const cefiRes = (await cefiResponse.json());
@@ -508,16 +557,15 @@ async function getVaultAllocations(vault, options) {
508
557
  }
509
558
  }
510
559
  catch (e) {
511
- core_1.Logger.log.error('getVaultAllocations:cefi', e, { borrower });
560
+ logSubaccountFetchFailure('getVaultAllocations:cefi', httpStatusFromError(e), e, { vault, borrower });
512
561
  }
513
562
  // fetch otc_positions
514
563
  try {
515
564
  const otcResponse = await (0, core_1.fetchAugustWithKey)(options.augustKey, core_1.WEBSERVER_ENDPOINTS.subaccount.otc_positions(borrower), { headers: options?.headers });
516
565
  if (otcResponse.status !== 200) {
517
- core_1.Logger.log.error('getVaultAllocations:otc', otcResponse.statusText, {
518
- borrower,
519
- status: otcResponse.status,
520
- });
566
+ // 404 means "this subaccount has no OTC positions" — expected for
567
+ // nearly every borrower. See logSubaccountFetchFailure.
568
+ logSubaccountFetchFailure('getVaultAllocations:otc', otcResponse.status, otcResponse.statusText, { vault, borrower });
521
569
  }
522
570
  if (otcResponse.status === 200) {
523
571
  const otcRes = (await otcResponse.json());
@@ -525,7 +573,7 @@ async function getVaultAllocations(vault, options) {
525
573
  }
526
574
  }
527
575
  catch (e) {
528
- core_1.Logger.log.error('getVaultAllocations:otc', e, { borrower });
576
+ logSubaccountFetchFailure('getVaultAllocations:otc', httpStatusFromError(e), e, { vault, borrower });
529
577
  }
530
578
  }
531
579
  }
@@ -552,6 +600,34 @@ async function getVaultAllocations(vault, options) {
552
600
  unfilteredTokens: unfilteredTokens,
553
601
  };
554
602
  }
603
+ /**
604
+ * Coerce a subgraph numeric field to `bigint`, treating absent fields as zero.
605
+ *
606
+ * Why: the evm-1 and evm-2 subgraphs expose different field names on
607
+ * `WithdrawalRequested` — evm-1 emits `assets` plus explicit `year`/`month`/
608
+ * `day`, evm-2 emits `shares` and a raw `timestamp_`. Reading the wrong one
609
+ * yields `undefined`, and bare `BigInt(undefined)` throws
610
+ * `TypeError: Cannot convert undefined to a BigInt`, which aborted the whole
611
+ * redemption scan and returned an empty list to the caller (the second
612
+ * highest-volume SDK error in production).
613
+ *
614
+ * `BigInt(x) || BigInt(0)` does **not** protect against this — the throw
615
+ * happens before `||` is ever evaluated.
616
+ *
617
+ * @param value - Subgraph field: decimal string, number, bigint, `null`, or
618
+ * `undefined`.
619
+ * @returns The value as `bigint`, or `0n` when absent or non-numeric.
620
+ */
621
+ function subgraphAmountToBigInt(value) {
622
+ if (value === undefined || value === null || value === '')
623
+ return BigInt(0);
624
+ try {
625
+ return BigInt(value);
626
+ }
627
+ catch {
628
+ return BigInt(0);
629
+ }
630
+ }
555
631
  async function getVaultAvailableRedemptions({ vault, wallet, options, prefetchedReads, }) {
556
632
  try {
557
633
  // Stellar vaults don't support on-chain redemptions yet
@@ -669,9 +745,12 @@ async function getVaultAvailableRedemptions({ vault, wallet, options, prefetched
669
745
  const redKey = (0, date_utils_1.formatDateKey)(redDate.getUTCFullYear(), redDate.getUTCMonth() + 1, redDate.getUTCDate());
670
746
  return redKey === requestDateKey;
671
747
  })
672
- : availableRedemptions.find((red) => BigInt(red.day.raw) === BigInt(ev.day) &&
673
- BigInt(red.month.raw) === BigInt(ev.month) &&
674
- BigInt(red.year.raw) === BigInt(ev.year));
748
+ : availableRedemptions.find((red) => subgraphAmountToBigInt(red.day.raw) ===
749
+ subgraphAmountToBigInt(ev.day) &&
750
+ subgraphAmountToBigInt(red.month.raw) ===
751
+ subgraphAmountToBigInt(ev.month) &&
752
+ subgraphAmountToBigInt(red.year.raw) ===
753
+ subgraphAmountToBigInt(ev.year));
675
754
  if (!(foundRedemptionAgainstClaim && alreadyRedeemed)) {
676
755
  // double check if user has already claimed
677
756
  try {
@@ -692,7 +771,7 @@ async function getVaultAvailableRedemptions({ vault, wallet, options, prefetched
692
771
  // Has passed lag duration - check if claim is not settled before adding to pending
693
772
  try {
694
773
  const burnableAmount = (await vaultContract?.getBurnableAmountByReceiver?.(BigInt(year), BigInt(month), BigInt(day), (0, ethers_1.getAddress)(ev.receiverAddr))) || BigInt(0);
695
- const claimAmount = BigInt(ev.shares) || BigInt(0);
774
+ const claimAmount = subgraphAmountToBigInt(ev.shares);
696
775
  // If burnableAmount >= claimAmount, claim hasn't been settled by processAllClaims
697
776
  // Only add to pending if it's still unsettled
698
777
  if (burnableAmount >= claimAmount) {
@@ -704,7 +783,7 @@ async function getVaultAvailableRedemptions({ vault, wallet, options, prefetched
704
783
  day: (0, core_1.toNormalizedBn)(day, 0),
705
784
  month: (0, core_1.toNormalizedBn)(month, 0),
706
785
  year: (0, core_1.toNormalizedBn)(year, 0),
707
- amount: (0, core_1.toNormalizedBn)(BigInt(ev.shares) || BigInt(0), decimals),
786
+ amount: (0, core_1.toNormalizedBn)(subgraphAmountToBigInt(ev.shares), decimals),
708
787
  date: fullDate,
709
788
  vault,
710
789
  status: types_1.VaultRedemptionStatus.READY_TO_CLAIM,
@@ -726,7 +805,7 @@ async function getVaultAvailableRedemptions({ vault, wallet, options, prefetched
726
805
  day: (0, core_1.toNormalizedBn)(day, 0),
727
806
  month: (0, core_1.toNormalizedBn)(month, 0),
728
807
  year: (0, core_1.toNormalizedBn)(year, 0),
729
- amount: (0, core_1.toNormalizedBn)(BigInt(ev.shares), decimals),
808
+ amount: (0, core_1.toNormalizedBn)(subgraphAmountToBigInt(ev.shares), decimals),
730
809
  date: fullDate,
731
810
  vault,
732
811
  status: types_1.VaultRedemptionStatus.AWAITING_COOLDOWN,
@@ -736,7 +815,12 @@ async function getVaultAvailableRedemptions({ vault, wallet, options, prefetched
736
815
  break;
737
816
  }
738
817
  default: {
739
- const trueClaimableAmount = await vaultContract?.getClaimableAmountByReceiver?.(BigInt(ev.year), BigInt(ev.month), BigInt(ev.day), (0, ethers_1.getAddress)(wallet));
818
+ // Safe to read the raw subgraph dates here: the validation
819
+ // block above `continue`s for any non-evm-2 event missing
820
+ // `year`/`month`/`day`, so this path is only reached with all
821
+ // three present. The coercion below therefore never
822
+ // substitutes 0 for a real date.
823
+ const trueClaimableAmount = await vaultContract?.getClaimableAmountByReceiver?.(subgraphAmountToBigInt(ev.year), subgraphAmountToBigInt(ev.month), subgraphAmountToBigInt(ev.day), (0, ethers_1.getAddress)(wallet));
740
824
  if (trueClaimableAmount > BigInt(0)) {
741
825
  // Use computeClaimableDate for UTC-correct date with lag
742
826
  const v1Claimable = (0, date_utils_1.computeClaimableDate)(Number(ev.timestamp_), lagDuration);
@@ -809,7 +893,7 @@ async function getVaultAvailableRedemptions({ vault, wallet, options, prefetched
809
893
  day: (0, core_1.toNormalizedBn)(ev.day, 0),
810
894
  month: (0, core_1.toNormalizedBn)(ev.month, 0),
811
895
  year: (0, core_1.toNormalizedBn)(ev.year, 0),
812
- amount: (0, core_1.toNormalizedBn)(BigInt(ev.assets) || BigInt(0), decimals),
896
+ amount: (0, core_1.toNormalizedBn)(subgraphAmountToBigInt(ev.assets), decimals),
813
897
  date: fullDate,
814
898
  vault,
815
899
  status: types_1.VaultRedemptionStatus.AWAITING_COOLDOWN,
@@ -910,7 +994,11 @@ async function getVaultRedemptionHistory({ vault, wallet, lookbackBlocks, option
910
994
  const firstMessage = firstReason instanceof Error
911
995
  ? firstReason.message
912
996
  : String(firstReason);
913
- core_1.Logger.log.error('getVaultRedemptionHistory', 'log fetch chunk(s) failed', {
997
+ // Breadcrumb only the throw below is caught and logged by this
998
+ // function's own catch block, so capturing here duplicated every
999
+ // failure into a second Sentry issue ("log fetch chunk(s) failed").
1000
+ core_1.Logger.log.warn('getVaultRedemptionHistory', {
1001
+ reason: 'log fetch chunk(s) failed',
914
1002
  failedChunks: failed.length,
915
1003
  totalChunks: batch.length,
916
1004
  firstReason: firstMessage,
@@ -2133,8 +2221,10 @@ async function getVaultUserLifetimePnl({ vault, wallet, options, }) {
2133
2221
  });
2134
2222
  let sharePriceRaw = BigInt(0);
2135
2223
  try {
2224
+ // Retried on transport blips only (bounded, no fallback); a vault that
2225
+ // genuinely has no `lpTokenAddress()` still throws into the catch below.
2136
2226
  const lpTokenAddress = version === 'evm-2'
2137
- ? (await vaultContract.lpTokenAddress())
2227
+ ? await (0, core_1.getReceiptTokenAddressOrThrow)(provider, vault, 'getVaultUserLifetimePnl:receiptToken')
2138
2228
  : vault;
2139
2229
  let currentShares = BigInt(0);
2140
2230
  if (version === 'evm-2') {
@@ -2648,7 +2738,9 @@ async function getPreviewRedemption({ vault, sharesAmount, options, }) {
2648
2738
  abi: TokenizedVaultV2_1.ABI_TOKENIZED_VAULT_V2,
2649
2739
  provider,
2650
2740
  });
2651
- const lpTokenAddress = (await contract.lpTokenAddress());
2741
+ // Retried on transport blips only (bounded, no fallback); a misroute
2742
+ // still surfaces the original error.
2743
+ const lpTokenAddress = await (0, core_1.getReceiptTokenAddressOrThrow)(provider, vault, 'getPreviewRedemption:receiptToken');
2652
2744
  const lpTokenContract = (0, core_1.createContract)({
2653
2745
  address: lpTokenAddress,
2654
2746
  abi: abis_1.ABI_LENDING_POOL_V2,
@@ -107,6 +107,9 @@ export declare class AugustVaults extends AugustBase {
107
107
  * @param chainId Optional chain ID (uses active network if not provided)
108
108
  * @param options Enrichment and wallet options
109
109
  * @returns Single vault object with optional position data
110
+ * @throws {@link AugustValidationError} (`INVALID_CHAIN`) when `chainId` is
111
+ * not a chain the SDK recognises, or is a supported EVM chain with no RPC
112
+ * URL configured on this SDK instance.
110
113
  */
111
114
  getVault({ vault, chainId, options, loadSubaccounts, loadSnapshots, }: {
112
115
  vault: IAddress;
@@ -116,21 +119,39 @@ export declare class AugustVaults extends AugustBase {
116
119
  loadSnapshots?: boolean;
117
120
  }): Promise<import("../../types").IVault>;
118
121
  /**
119
- *
122
+ * Fetch the active loans issued by a vault.
123
+ * @param vault Vault contract address
124
+ * @param chainId Optional chain ID (uses active network if not provided)
125
+ * @returns Loan data for the vault
126
+ * @throws {@link AugustValidationError} (`INVALID_CHAIN`) when `chainId` is
127
+ * not a chain the SDK recognises, or is a supported EVM chain with no RPC
128
+ * URL configured on this SDK instance.
120
129
  */
121
130
  getVaultLoans({ vault, chainId, }: {
122
131
  vault: IAddress;
123
132
  chainId?: IChainId;
124
133
  }): Promise<import("../../types").IVaultLoan[]>;
125
134
  /**
126
- *
135
+ * Fetch a vault's loans broken down by sub-account.
136
+ * @param vault Vault contract address
137
+ * @param chainId Optional chain ID (uses active network if not provided)
138
+ * @returns Sub-account loan data for the vault
139
+ * @throws {@link AugustValidationError} (`INVALID_CHAIN`) when `chainId` is
140
+ * not a chain the SDK recognises, or is a supported EVM chain with no RPC
141
+ * URL configured on this SDK instance.
127
142
  */
128
143
  getVaultSubaccountLoans({ vault, chainId, }: {
129
144
  vault: IAddress;
130
145
  chainId?: IChainId;
131
146
  }): Promise<import("../../types").IVaultLoan[]>;
132
147
  /**
133
- *
148
+ * Fetch a vault's DeFi / CeFi / OTC allocation breakdown.
149
+ * @param vault Vault contract address
150
+ * @param chainId Optional chain ID (uses active network if not provided)
151
+ * @returns Allocation data for the vault
152
+ * @throws {@link AugustValidationError} (`INVALID_CHAIN`) when `chainId` is
153
+ * not a chain the SDK recognises, or is a supported EVM chain with no RPC
154
+ * URL configured on this SDK instance.
134
155
  */
135
156
  getVaultAllocations({ vault, chainId, }: {
136
157
  vault: IAddress;
@@ -326,6 +326,9 @@ class AugustVaults extends core_1.AugustBase {
326
326
  * @param chainId Optional chain ID (uses active network if not provided)
327
327
  * @param options Enrichment and wallet options
328
328
  * @returns Single vault object with optional position data
329
+ * @throws {@link AugustValidationError} (`INVALID_CHAIN`) when `chainId` is
330
+ * not a chain the SDK recognises, or is a supported EVM chain with no RPC
331
+ * URL configured on this SDK instance.
329
332
  */
330
333
  async getVault({ vault, chainId, options, loadSubaccounts, loadSnapshots, }) {
331
334
  if (!vault)
@@ -334,12 +337,8 @@ class AugustVaults extends core_1.AugustBase {
334
337
  // throw new Error(
335
338
  // `Vault input parameter is not an address: ${String(vault)}`,
336
339
  // );
337
- if (typeof chainId !== 'undefined') {
338
- if (!this.providers?.[chainId]) {
339
- const error = new Error(`Missing RPC URL for chainId ${chainId}`);
340
- core_1.Logger.log.error('getVault:missing_provider', error, { chainId });
341
- }
342
- }
340
+ (0, core_1.assertKnownChainId)(chainId, this.providers, 'getVault');
341
+ (0, core_1.assertEvmProviderConfigured)(chainId, this.providers, 'getVault');
343
342
  // get vault data
344
343
  const vaultResponse = await (0, getters_1.getVault)({
345
344
  vault: vault,
@@ -398,7 +397,13 @@ class AugustVaults extends core_1.AugustBase {
398
397
  return vaultResponse;
399
398
  }
400
399
  /**
401
- *
400
+ * Fetch the active loans issued by a vault.
401
+ * @param vault Vault contract address
402
+ * @param chainId Optional chain ID (uses active network if not provided)
403
+ * @returns Loan data for the vault
404
+ * @throws {@link AugustValidationError} (`INVALID_CHAIN`) when `chainId` is
405
+ * not a chain the SDK recognises, or is a supported EVM chain with no RPC
406
+ * URL configured on this SDK instance.
402
407
  */
403
408
  async getVaultLoans({ vault, chainId, }) {
404
409
  // Sanitize
@@ -407,12 +412,8 @@ class AugustVaults extends core_1.AugustBase {
407
412
  throw new Error('Vault input parameter is undefined.');
408
413
  if (!(0, ethers_1.isAddress)(vault))
409
414
  throw new Error(`Vault input parameter is not an address: ${String(vault)}`);
410
- if (typeof chainId !== 'undefined') {
411
- if (!this.providers?.[chainId]) {
412
- const error = new Error(`Missing RPC URL for chainId ${chainId}`);
413
- core_1.Logger.log.error('getVaultLoans:missing_provider', error, { chainId });
414
- }
415
- }
415
+ (0, core_1.assertKnownChainId)(chainId, this.providers, 'getVaultLoans');
416
+ (0, core_1.assertEvmProviderConfigured)(chainId, this.providers, 'getVaultLoans');
416
417
  // get vault loans data
417
418
  const vaultResponse = await (0, getters_1.getVaultLoans)(vault, {
418
419
  rpcUrl: chainId
@@ -429,7 +430,13 @@ class AugustVaults extends core_1.AugustBase {
429
430
  return vaultResponse;
430
431
  }
431
432
  /**
432
- *
433
+ * Fetch a vault's loans broken down by sub-account.
434
+ * @param vault Vault contract address
435
+ * @param chainId Optional chain ID (uses active network if not provided)
436
+ * @returns Sub-account loan data for the vault
437
+ * @throws {@link AugustValidationError} (`INVALID_CHAIN`) when `chainId` is
438
+ * not a chain the SDK recognises, or is a supported EVM chain with no RPC
439
+ * URL configured on this SDK instance.
433
440
  */
434
441
  async getVaultSubaccountLoans({ vault, chainId, }) {
435
442
  // Sanitize
@@ -437,14 +444,8 @@ class AugustVaults extends core_1.AugustBase {
437
444
  throw new Error('Vault input parameter is undefined.');
438
445
  if (!(0, ethers_1.isAddress)(vault))
439
446
  throw new Error(`Vault input parameter is not an address: ${String(vault)}`);
440
- if (typeof chainId !== 'undefined') {
441
- if (!this.providers?.[chainId]) {
442
- const error = new Error(`Missing RPC URL for chainId ${chainId}`);
443
- core_1.Logger.log.error('getVaultSubaccountLoans:missing_provider', error, {
444
- chainId,
445
- });
446
- }
447
- }
447
+ (0, core_1.assertKnownChainId)(chainId, this.providers, 'getVaultSubaccountLoans');
448
+ (0, core_1.assertEvmProviderConfigured)(chainId, this.providers, 'getVaultSubaccountLoans');
448
449
  // get vault subaccount loans data
449
450
  const vaultResponse = await (0, getters_1.getVaultSubaccountLoans)(vault, {
450
451
  rpcUrl: chainId
@@ -461,7 +462,13 @@ class AugustVaults extends core_1.AugustBase {
461
462
  return vaultResponse;
462
463
  }
463
464
  /**
464
- *
465
+ * Fetch a vault's DeFi / CeFi / OTC allocation breakdown.
466
+ * @param vault Vault contract address
467
+ * @param chainId Optional chain ID (uses active network if not provided)
468
+ * @returns Allocation data for the vault
469
+ * @throws {@link AugustValidationError} (`INVALID_CHAIN`) when `chainId` is
470
+ * not a chain the SDK recognises, or is a supported EVM chain with no RPC
471
+ * URL configured on this SDK instance.
465
472
  */
466
473
  async getVaultAllocations({ vault, chainId, }) {
467
474
  // Sanitize
@@ -472,14 +479,8 @@ class AugustVaults extends core_1.AugustBase {
472
479
  !utils_1.SolanaUtils.isSolanaAddress(vault) &&
473
480
  !(0, utils_2.isStellarAddress)(vault))
474
481
  throw new Error(`Vault input parameter is not an address: ${String(vault)}`);
475
- if (typeof chainId !== 'undefined') {
476
- if (!this.providers?.[chainId]) {
477
- const error = new Error(`Missing RPC URL for chainId ${chainId}`);
478
- core_1.Logger.log.error('getVaultAllocations:missing_provider', error, {
479
- chainId,
480
- });
481
- }
482
- }
482
+ (0, core_1.assertKnownChainId)(chainId, this.providers, 'getVaultAllocations');
483
+ (0, core_1.assertEvmProviderConfigured)(chainId, this.providers, 'getVaultAllocations');
483
484
  // get vault allocations data
484
485
  try {
485
486
  const vaultResponse = await (0, getters_1.getVaultAllocations)(vault, {
@@ -81,7 +81,47 @@ export declare function resolveSpender(args: {
81
81
  export declare function validateAmountPrecision(amount: string | bigint | number): void;
82
82
  /** @internal */
83
83
  export declare function isNonceParsing(error: unknown): boolean;
84
- /** @internal */
84
+ /**
85
+ * Await a broadcast transaction's receipt, surviving both malformed-nonce RPCs
86
+ * and transient transport faults while still reporting genuine on-chain
87
+ * failures.
88
+ *
89
+ * `tx.wait()` is tried first because it preserves ethers' replacement-tx
90
+ * detection and revert checks. Two recoverable failure modes are handled:
91
+ *
92
+ * 1. **Malformed nonce** ({@link isNonceParsing}) — Monad-style RPCs return
93
+ * `nonce: "undefined"` on the pending tx and ethers throws while parsing.
94
+ * One direct `provider.waitForTransaction()` recovers it (unchanged
95
+ * behaviour).
96
+ * 2. **Transient transport fault** ({@link isRetryableRpcError}) — the provider
97
+ * hiccups while polling `eth_getTransactionReceipt` and ethers surfaces
98
+ * `could not coalesce error (… "code": -32603 …)`. This used to propagate
99
+ * and make every write path report a **successfully mined** transaction as
100
+ * failed, driving users to retry into `ERC20InsufficientBalance`. The hash
101
+ * is already on the wire and receipt polling is idempotent, so we re-poll
102
+ * with bounded exponential backoff instead of rethrowing.
103
+ *
104
+ * Everything else — notably a real revert — is rethrown untouched.
105
+ *
106
+ * Every error this function throws is stamped by {@link markBroadcast}: by the
107
+ * time `tx.wait()` can fail, the transaction is already on the wire, so the
108
+ * caller must never report it as "never sent". See
109
+ * {@link localTxBroadcastContext} for how that reaches
110
+ * `AugustSDKError.context`.
111
+ *
112
+ * @param tx - The broadcast transaction response to await.
113
+ * @returns The mined receipt (never `null` on the fallback paths; `tx.wait()`
114
+ * itself may return `null` when the caller configured 0 confirmations).
115
+ * @throws {Error} `Transaction <hash> reverted on-chain` when the receipt
116
+ * reports `status === 0`. Marked `confirmationUnknown: false` — the chain
117
+ * answered.
118
+ * @throws {Error} `Transaction <hash> was not confirmed within <n>s` when the
119
+ * overall wait times out with no receipt. Marked
120
+ * `confirmationUnknown: true`.
121
+ * @throws The underlying transport error once receipt-poll retries are
122
+ * exhausted, marked `confirmationUnknown: true`.
123
+ * @internal
124
+ */
85
125
  export declare function safeWaitForTx(tx: TransactionResponse): Promise<import("ethers").TransactionReceipt>;
86
126
  /**
87
127
  * Wraps an ethers contract call that returns a TransactionResponse.