@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.
- package/AGENTS.md +95 -0
- package/BACKEND.md +95 -0
- package/FRONTEND.md +95 -0
- package/README.md +1 -0
- package/dist/abi/full/VarlaConvertLiquidator.d.ts +35 -0
- package/dist/abi/full/VarlaConvertLiquidator.d.ts.map +1 -1
- package/dist/abi/full/VarlaConvertLiquidator.js +45 -0
- package/dist/abi/full/VarlaLiquidator.d.ts +35 -0
- package/dist/abi/full/VarlaLiquidator.d.ts.map +1 -1
- package/dist/abi/full/VarlaLiquidator.js +45 -0
- package/dist/abi/full/VarlaMergeLiquidator.d.ts +35 -0
- package/dist/abi/full/VarlaMergeLiquidator.d.ts.map +1 -1
- package/dist/abi/full/VarlaMergeLiquidator.js +45 -0
- package/dist/actions/oracleUpdaterRouter.d.ts +24 -2
- package/dist/actions/oracleUpdaterRouter.d.ts.map +1 -1
- package/dist/actions/oracleUpdaterRouter.js +90 -16
- package/dist/generated.d.ts +105 -0
- package/dist/generated.d.ts.map +1 -1
- package/dist/views/core.d.ts +55 -7
- package/dist/views/core.d.ts.map +1 -1
- package/dist/views/core.js +184 -36
- package/package.json +1 -1
package/dist/views/core.js
CHANGED
|
@@ -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.
|
|
540
|
+
// wraps: VarlaCore.getAccountSummary,VarlaCore.getHealthFactor
|
|
540
541
|
export async function readBorrowLimits(params) {
|
|
541
|
-
const [
|
|
542
|
-
params.core
|
|
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.
|
|
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: "
|
|
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 =
|
|
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
|
|
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
|
|
592
|
+
throw new Error(`Core getHealthFactor multicall failed: ${String(r1.error ?? "unknown")}`);
|
|
608
593
|
}
|
|
609
|
-
|
|
610
|
-
|
|
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
|
-
|
|
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
|
|
624
|
-
debt
|
|
625
|
-
maxBorrow
|
|
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
|
+
}
|