@varla/sdk 1.11.2 → 1.11.4

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.
@@ -1,4 +1,5 @@
1
1
  // Note: explicit .js extension is required for Node ESM resolution.
2
+ import { erc1155Abi } from "viem";
2
3
  import { multicallChunks } from "../batch.js";
3
4
  import { abis } from "../generated.js";
4
5
  /**
@@ -536,19 +537,17 @@ export async function previewRepay(params) {
536
537
  /**
537
538
  * A small convenience bundle for frontends/backends.
538
539
  */
539
- // wraps: VarlaCore.getCollateralValue,VarlaCore.getDebt,VarlaCore.getMaxBorrow,VarlaCore.getHealthFactor
540
+ // wraps: VarlaCore.getAccountSummary,VarlaCore.getHealthFactor
540
541
  export async function readBorrowLimits(params) {
541
- const [collateralValue, debt, maxBorrow, hf] = await Promise.all([
542
- params.core.read.getCollateralValue([params.user]),
543
- params.core.read.getDebt([params.user]),
544
- params.core.read.getMaxBorrow([params.user]),
542
+ const [snap, hf] = await Promise.all([
543
+ readAccountSnapshot({ core: params.core, user: params.user }),
545
544
  readHealthFactor({ core: params.core, user: params.user }),
546
545
  ]);
547
546
  return {
548
547
  user: params.user,
549
- collateralValue,
550
- debt,
551
- maxBorrow,
548
+ collateralValue: snap.collateralValue,
549
+ debt: snap.debt,
550
+ maxBorrow: snap.maxBorrow,
552
551
  healthFactor: hf.healthFactor,
553
552
  canBeLiquidated: hf.canBeLiquidated,
554
553
  };
@@ -556,7 +555,7 @@ export async function readBorrowLimits(params) {
556
555
  /**
557
556
  * Multicall-chunked version of `readBorrowLimits`.
558
557
  */
559
- // wraps: VarlaCore.getCollateralValue,VarlaCore.getDebt,VarlaCore.getMaxBorrow,VarlaCore.getHealthFactor
558
+ // wraps: VarlaCore.getAccountSummary,VarlaCore.getHealthFactor
560
559
  export async function readManyBorrowLimits(params) {
561
560
  const chunkSize = params.chunkSize ?? 256;
562
561
  if (params.users.length === 0)
@@ -565,19 +564,7 @@ export async function readManyBorrowLimits(params) {
565
564
  {
566
565
  address: params.core.address,
567
566
  abi: abis.VARLACORE_ABI,
568
- functionName: "getCollateralValue",
569
- args: [user],
570
- },
571
- {
572
- address: params.core.address,
573
- abi: abis.VARLACORE_ABI,
574
- functionName: "getDebt",
575
- args: [user],
576
- },
577
- {
578
- address: params.core.address,
579
- abi: abis.VARLACORE_ABI,
580
- functionName: "getMaxBorrow",
567
+ functionName: "getAccountSummary",
581
568
  args: [user],
582
569
  },
583
570
  {
@@ -593,26 +580,27 @@ export async function readManyBorrowLimits(params) {
593
580
  chunkSize,
594
581
  });
595
582
  const out = [];
596
- const stride = 4;
583
+ const stride = 2;
597
584
  for (let i = 0; i < params.users.length; i++) {
598
585
  const base = i * stride;
599
586
  const r0 = res[base + 0];
600
587
  const r1 = res[base + 1];
601
- const r2 = res[base + 2];
602
- const r3 = res[base + 3];
603
588
  if (r0.status !== "success") {
604
- throw new Error(`Core getCollateralValue multicall failed: ${String(r0.error ?? "unknown")}`);
589
+ throw new Error(`Core getAccountSummary multicall failed: ${String(r0.error ?? "unknown")}`);
605
590
  }
606
591
  if (r1.status !== "success") {
607
- throw new Error(`Core getDebt multicall failed: ${String(r1.error ?? "unknown")}`);
592
+ throw new Error(`Core getHealthFactor multicall failed: ${String(r1.error ?? "unknown")}`);
608
593
  }
609
- if (r2.status !== "success") {
610
- throw new Error(`Core getMaxBorrow multicall failed: ${String(r2.error ?? "unknown")}`);
594
+ const snapRaw = r0.result;
595
+ const collateralValue = snapRaw.collateralValue ?? snapRaw[1];
596
+ const debt = snapRaw.debt ?? snapRaw[2];
597
+ const maxBorrow = snapRaw.maxBorrow ?? snapRaw[4];
598
+ if (typeof collateralValue !== "bigint" ||
599
+ typeof debt !== "bigint" ||
600
+ typeof maxBorrow !== "bigint") {
601
+ throw new Error("Unexpected getAccountSummary() return shape");
611
602
  }
612
- if (r3.status !== "success") {
613
- throw new Error(`Core getHealthFactor multicall failed: ${String(r3.error ?? "unknown")}`);
614
- }
615
- const hfRaw = r3.result;
603
+ const hfRaw = r1.result;
616
604
  const healthFactor = hfRaw.healthFactor ?? hfRaw[0];
617
605
  const canBeLiquidated = hfRaw.canBeLiquidated ?? hfRaw[1];
618
606
  if (typeof healthFactor !== "bigint" || typeof canBeLiquidated !== "boolean") {
@@ -620,12 +608,172 @@ export async function readManyBorrowLimits(params) {
620
608
  }
621
609
  out.push({
622
610
  user: params.users[i],
623
- collateralValue: r0.result,
624
- debt: r1.result,
625
- maxBorrow: r2.result,
611
+ collateralValue,
612
+ debt,
613
+ maxBorrow,
626
614
  healthFactor,
627
615
  canBeLiquidated,
628
616
  });
629
617
  }
630
618
  return out;
631
619
  }
620
+ function _normalizeOraclePositionSnapshot(raw, positionId) {
621
+ const r = raw;
622
+ const priceOk = r.priceOk ?? r[0];
623
+ const priceE8 = r.priceE8 ?? r[1];
624
+ const manuallyInvalidated = r.manuallyInvalidated ?? r[2];
625
+ const riskTierRaw = r.riskTier ?? r[3];
626
+ const earlyClosureFactorWad = r.earlyClosureFactorWad ?? r[4];
627
+ if (typeof priceOk !== "boolean" ||
628
+ typeof priceE8 !== "bigint" ||
629
+ typeof manuallyInvalidated !== "boolean" ||
630
+ (typeof riskTierRaw !== "number" && typeof riskTierRaw !== "bigint") ||
631
+ typeof earlyClosureFactorWad !== "bigint") {
632
+ throw new Error("Unexpected getPositionSnapshot() return shape");
633
+ }
634
+ return {
635
+ positionId,
636
+ priceOk,
637
+ priceE8,
638
+ manuallyInvalidated,
639
+ riskTier: Number(riskTierRaw),
640
+ earlyClosureFactorWad,
641
+ };
642
+ }
643
+ function _tierDefaultLtv(defaultLtv, riskTier) {
644
+ if (riskTier === 0)
645
+ return defaultLtv.conservative;
646
+ if (riskTier === 1)
647
+ return defaultLtv.moderate;
648
+ return defaultLtv.risk;
649
+ }
650
+ /**
651
+ * Computes current vs potential borrowing capacity.
652
+ *
653
+ * - `current` comes from Core.getAccountSummary(user) (deposited positions only).
654
+ * - `wallet` is computed by reading ERC1155 wallet balances for the provided `walletPositionIds`
655
+ * and applying VarlaOracle pricing + VarlaCore LTV rules.
656
+ *
657
+ * This helper exists to power UI flows like “Deposit Positions” where you want to show:
658
+ * - Current max loan (already deposited)
659
+ * - Potential max loan (if the user also deposits their wallet positions)
660
+ */
661
+ export async function readHypotheticalBorrowCapacity(params) {
662
+ const chunkSize = params.chunkSize ?? 256;
663
+ const [current, defaultLtv] = await Promise.all([
664
+ readAccountSnapshot({ core: params.core, user: params.user }),
665
+ readDefaultLtvConfig({ core: params.core }),
666
+ ]);
667
+ // Fast path: no wallet ids.
668
+ if (params.walletPositionIds.length === 0) {
669
+ const potentialMaxBorrow = current.collateralValue > current.debt ? current.collateralValue - current.debt : 0n;
670
+ return {
671
+ user: params.user,
672
+ current,
673
+ wallet: { positionIds: [], balances: [], portfolioValue: 0n, collateralValue: 0n },
674
+ potential: { collateralValue: current.collateralValue, maxBorrow: potentialMaxBorrow },
675
+ };
676
+ }
677
+ // 1) Wallet balances (ERC1155 balanceOf)
678
+ const balCalls = params.walletPositionIds.map((pid) => ({
679
+ address: params.positionsToken.address,
680
+ abi: erc1155Abi,
681
+ functionName: "balanceOf",
682
+ args: [params.user, pid],
683
+ }));
684
+ const balRes = await multicallChunks({
685
+ client: params.client,
686
+ contracts: balCalls,
687
+ chunkSize,
688
+ });
689
+ const heldIds = [];
690
+ const heldBals = [];
691
+ for (let i = 0; i < balRes.length; i++) {
692
+ const r = balRes[i];
693
+ if (r.status !== "success") {
694
+ throw new Error(`ERC1155 balanceOf multicall failed: ${String(r.error ?? "unknown")}`);
695
+ }
696
+ const bal = r.result;
697
+ if (typeof bal !== "bigint")
698
+ throw new Error("Unexpected ERC1155 balanceOf return type");
699
+ if (bal > 0n) {
700
+ heldIds.push(params.walletPositionIds[i]);
701
+ heldBals.push(bal);
702
+ }
703
+ }
704
+ // No wallet positions held.
705
+ if (heldIds.length === 0) {
706
+ const potentialMaxBorrow = current.collateralValue > current.debt ? current.collateralValue - current.debt : 0n;
707
+ return {
708
+ user: params.user,
709
+ current,
710
+ wallet: { positionIds: [], balances: [], portfolioValue: 0n, collateralValue: 0n },
711
+ potential: { collateralValue: current.collateralValue, maxBorrow: potentialMaxBorrow },
712
+ };
713
+ }
714
+ // 2) Oracle snapshots + Core LTV overrides
715
+ const snapCalls = heldIds.map((pid) => ({
716
+ address: params.oracle.address,
717
+ abi: abis.VARLAORACLE_ABI,
718
+ functionName: "getPositionSnapshot",
719
+ args: [pid],
720
+ }));
721
+ const ovCalls = heldIds.map((pid) => ({
722
+ address: params.core.address,
723
+ abi: abis.VARLACORE_ABI,
724
+ functionName: "getPositionLtvOverride",
725
+ args: [pid],
726
+ }));
727
+ const [snapRes, ovRes] = await Promise.all([
728
+ multicallChunks({ client: params.client, contracts: snapCalls, chunkSize }),
729
+ multicallChunks({ client: params.client, contracts: ovCalls, chunkSize }),
730
+ ]);
731
+ const WAD = 1000000000000000000n;
732
+ const E8 = 100000000n;
733
+ let walletPortfolioValue = 0n;
734
+ let walletCollateralValue = 0n;
735
+ for (let i = 0; i < heldIds.length; i++) {
736
+ const snapR = snapRes[i];
737
+ if (snapR.status !== "success") {
738
+ throw new Error(`Oracle getPositionSnapshot multicall failed: ${String(snapR.error ?? "unknown")}`);
739
+ }
740
+ const snap = _normalizeOraclePositionSnapshot(snapR.result, heldIds[i]);
741
+ const ovR = ovRes[i];
742
+ if (ovR.status !== "success") {
743
+ throw new Error(`Core getPositionLtvOverride multicall failed: ${String(ovR.error ?? "unknown")}`);
744
+ }
745
+ const ovRaw = ovR.result;
746
+ const isSet = ovRaw.isSet ?? ovRaw[0];
747
+ const ltv = ovRaw.ltv ?? ovRaw[1];
748
+ if (typeof isSet !== "boolean" || typeof ltv !== "bigint") {
749
+ throw new Error("Unexpected getPositionLtvOverride() return shape");
750
+ }
751
+ // Mirror Core accounting semantics.
752
+ if (snap.manuallyInvalidated)
753
+ continue;
754
+ if (!snap.priceOk)
755
+ continue;
756
+ const bal = heldBals[i];
757
+ const pv = (bal * snap.priceE8) / E8;
758
+ if (pv === 0n)
759
+ continue;
760
+ walletPortfolioValue += pv;
761
+ const baseLtv = isSet ? ltv : _tierDefaultLtv(defaultLtv, snap.riskTier);
762
+ const effectiveLtv = (baseLtv * snap.earlyClosureFactorWad) / WAD;
763
+ const cv = (pv * effectiveLtv) / WAD;
764
+ walletCollateralValue += cv;
765
+ }
766
+ const potentialCollateralValue = current.collateralValue + walletCollateralValue;
767
+ const potentialMaxBorrow = potentialCollateralValue > current.debt ? potentialCollateralValue - current.debt : 0n;
768
+ return {
769
+ user: params.user,
770
+ current,
771
+ wallet: {
772
+ positionIds: heldIds,
773
+ balances: heldBals,
774
+ portfolioValue: walletPortfolioValue,
775
+ collateralValue: walletCollateralValue,
776
+ },
777
+ potential: { collateralValue: potentialCollateralValue, maxBorrow: potentialMaxBorrow },
778
+ };
779
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@varla/sdk",
3
- "version": "1.11.2",
3
+ "version": "1.11.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,