@varla/sdk 2.17.0 → 2.19.0
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 +9 -9
- package/CHANGELOG.md +40 -0
- package/dist/actions/liquidator.d.ts +35 -0
- package/dist/actions/liquidator.d.ts.map +1 -1
- package/dist/actions/liquidator.js +46 -0
- package/dist/actions/liquidator.js.map +1 -1
- package/dist/actions/oracle.d.ts +14 -0
- package/dist/actions/oracle.d.ts.map +1 -1
- package/dist/actions/oracle.js +21 -2
- package/dist/actions/oracle.js.map +1 -1
- package/dist/views/core.d.ts +68 -0
- package/dist/views/core.d.ts.map +1 -1
- package/dist/views/core.js +291 -0
- package/dist/views/core.js.map +1 -1
- package/dist/views/liquidators.d.ts +26 -0
- package/dist/views/liquidators.d.ts.map +1 -1
- package/dist/views/liquidators.js +80 -14
- package/dist/views/liquidators.js.map +1 -1
- package/dist/views/oracle.d.ts +106 -0
- package/dist/views/oracle.d.ts.map +1 -1
- package/dist/views/oracle.js +305 -1
- package/dist/views/oracle.js.map +1 -1
- package/dist/views/pool.d.ts +24 -0
- package/dist/views/pool.d.ts.map +1 -1
- package/dist/views/pool.js +127 -0
- package/dist/views/pool.js.map +1 -1
- package/dist/views/system.d.ts +22 -2
- package/dist/views/system.d.ts.map +1 -1
- package/dist/views/system.js +33 -2
- package/dist/views/system.js.map +1 -1
- package/package.json +1 -1
- package/src/actions/liquidator.ts +81 -0
- package/src/actions/oracle.ts +37 -2
- package/src/views/core.ts +373 -0
- package/src/views/liquidators.ts +104 -21
- package/src/views/oracle.ts +388 -1
- package/src/views/pool.ts +153 -0
- package/src/views/system.ts +54 -4
package/src/views/oracle.ts
CHANGED
|
@@ -275,6 +275,22 @@ export type ReadOracleTiming = {
|
|
|
275
275
|
lastUpdated: bigint;
|
|
276
276
|
};
|
|
277
277
|
|
|
278
|
+
export type ReadOracleDashboardRow = {
|
|
279
|
+
positionId: bigint;
|
|
280
|
+
snapshot: ReadPositionSnapshot;
|
|
281
|
+
meta: ReadOraclePositionMeta;
|
|
282
|
+
resolvedStatus: { positionId: bigint; isResolved: boolean };
|
|
283
|
+
staleStatus: { positionId: bigint; isPriceStale: boolean };
|
|
284
|
+
priceData: ReadOraclePriceData;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
export type ReadOracleDashboard = {
|
|
288
|
+
config: ReadOracleConfig;
|
|
289
|
+
basics: ReadOracleBasics;
|
|
290
|
+
positionIds: bigint[];
|
|
291
|
+
rows: ReadOracleDashboardRow[];
|
|
292
|
+
};
|
|
293
|
+
|
|
278
294
|
// wraps: VarlaOracle.getPriceData
|
|
279
295
|
export async function readOraclePriceData(params: {
|
|
280
296
|
oracle: {
|
|
@@ -368,6 +384,302 @@ export async function readOracleTiming(params: {
|
|
|
368
384
|
};
|
|
369
385
|
}
|
|
370
386
|
|
|
387
|
+
/**
|
|
388
|
+
* Multicall-chunked collateral status hydration for many positions.
|
|
389
|
+
*/
|
|
390
|
+
// wraps: VarlaOracle.isConfigured,VarlaOracle.isResolved,VarlaOracle.isDepositAllowed,VarlaOracle.isValidCollateral,VarlaOracle.isPriceStale
|
|
391
|
+
export async function readManyOracleCollateralStatus(params: {
|
|
392
|
+
oracle: { address: Address };
|
|
393
|
+
client: { multicall: (args: any) => Promise<any> };
|
|
394
|
+
positionIds: readonly bigint[];
|
|
395
|
+
chunkSize?: number;
|
|
396
|
+
}): Promise<ReadOracleCollateralStatus[]> {
|
|
397
|
+
const chunkSize = params.chunkSize ?? 256;
|
|
398
|
+
if (params.positionIds.length === 0) return [];
|
|
399
|
+
|
|
400
|
+
const calls = params.positionIds.flatMap((pid) => [
|
|
401
|
+
{
|
|
402
|
+
address: params.oracle.address,
|
|
403
|
+
abi: abis.VARLAORACLE_ABI,
|
|
404
|
+
functionName: "isConfigured" as const,
|
|
405
|
+
args: [pid] as const,
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
address: params.oracle.address,
|
|
409
|
+
abi: abis.VARLAORACLE_ABI,
|
|
410
|
+
functionName: "isResolved" as const,
|
|
411
|
+
args: [pid] as const,
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
address: params.oracle.address,
|
|
415
|
+
abi: abis.VARLAORACLE_ABI,
|
|
416
|
+
functionName: "isDepositAllowed" as const,
|
|
417
|
+
args: [pid] as const,
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
address: params.oracle.address,
|
|
421
|
+
abi: abis.VARLAORACLE_ABI,
|
|
422
|
+
functionName: "isValidCollateral" as const,
|
|
423
|
+
args: [pid] as const,
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
address: params.oracle.address,
|
|
427
|
+
abi: abis.VARLAORACLE_ABI,
|
|
428
|
+
functionName: "isPriceStale" as const,
|
|
429
|
+
args: [pid] as const,
|
|
430
|
+
},
|
|
431
|
+
]);
|
|
432
|
+
|
|
433
|
+
const res = await multicallChunks({
|
|
434
|
+
client: params.client as any,
|
|
435
|
+
contracts: calls as any,
|
|
436
|
+
chunkSize,
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
const out: ReadOracleCollateralStatus[] = [];
|
|
440
|
+
const stride = 5;
|
|
441
|
+
for (let i = 0; i < params.positionIds.length; i++) {
|
|
442
|
+
const base = i * stride;
|
|
443
|
+
const r0: any = (res as any[])[base + 0];
|
|
444
|
+
const r1: any = (res as any[])[base + 1];
|
|
445
|
+
const r2: any = (res as any[])[base + 2];
|
|
446
|
+
const r3: any = (res as any[])[base + 3];
|
|
447
|
+
const r4: any = (res as any[])[base + 4];
|
|
448
|
+
if (
|
|
449
|
+
r0.status !== "success" ||
|
|
450
|
+
r1.status !== "success" ||
|
|
451
|
+
r2.status !== "success" ||
|
|
452
|
+
r3.status !== "success" ||
|
|
453
|
+
r4.status !== "success"
|
|
454
|
+
) {
|
|
455
|
+
throw new Error("Oracle collateral status multicall failed");
|
|
456
|
+
}
|
|
457
|
+
out.push({
|
|
458
|
+
positionId: params.positionIds[i]!,
|
|
459
|
+
isConfigured: r0.result as boolean,
|
|
460
|
+
isResolved: r1.result as boolean,
|
|
461
|
+
isDepositAllowed: r2.result as boolean,
|
|
462
|
+
isValidCollateral: r3.result as boolean,
|
|
463
|
+
isPriceStale: r4.result as boolean,
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
return out;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// wraps: VarlaOracle.isResolved,VarlaOracle.isPriceStale
|
|
470
|
+
export async function readManyOracleStatusFlags(params: {
|
|
471
|
+
oracle: { address: Address };
|
|
472
|
+
client: { multicall: (args: any) => Promise<any> };
|
|
473
|
+
positionIds: readonly bigint[];
|
|
474
|
+
chunkSize?: number;
|
|
475
|
+
}): Promise<Array<{ positionId: bigint; isResolved: boolean; isPriceStale: boolean }>> {
|
|
476
|
+
const chunkSize = params.chunkSize ?? 256;
|
|
477
|
+
if (params.positionIds.length === 0) return [];
|
|
478
|
+
|
|
479
|
+
const calls = params.positionIds.flatMap((pid) => [
|
|
480
|
+
{
|
|
481
|
+
address: params.oracle.address,
|
|
482
|
+
abi: abis.VARLAORACLE_ABI,
|
|
483
|
+
functionName: "isResolved" as const,
|
|
484
|
+
args: [pid] as const,
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
address: params.oracle.address,
|
|
488
|
+
abi: abis.VARLAORACLE_ABI,
|
|
489
|
+
functionName: "isPriceStale" as const,
|
|
490
|
+
args: [pid] as const,
|
|
491
|
+
},
|
|
492
|
+
]);
|
|
493
|
+
|
|
494
|
+
const res = await multicallChunks({
|
|
495
|
+
client: params.client as any,
|
|
496
|
+
contracts: calls as any,
|
|
497
|
+
chunkSize,
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
const out: Array<{ positionId: bigint; isResolved: boolean; isPriceStale: boolean }> = [];
|
|
501
|
+
const stride = 2;
|
|
502
|
+
for (let i = 0; i < params.positionIds.length; i++) {
|
|
503
|
+
const base = i * stride;
|
|
504
|
+
const r0: any = (res as any[])[base + 0];
|
|
505
|
+
const r1: any = (res as any[])[base + 1];
|
|
506
|
+
if (r0.status !== "success" || r1.status !== "success") {
|
|
507
|
+
throw new Error("Oracle status flags multicall failed");
|
|
508
|
+
}
|
|
509
|
+
out.push({
|
|
510
|
+
positionId: params.positionIds[i]!,
|
|
511
|
+
isResolved: r0.result as boolean,
|
|
512
|
+
isPriceStale: r1.result as boolean,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
return out;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Multicall-chunked timing hydration for many positions.
|
|
520
|
+
*/
|
|
521
|
+
// wraps: VarlaOracle.getEarlyClosureWindow,VarlaOracle.getEarlyClosureFactor,VarlaOracle.lastRecoveryFromStale,VarlaOracle.getLastUpdated
|
|
522
|
+
export async function readManyOracleTiming(params: {
|
|
523
|
+
oracle: { address: Address };
|
|
524
|
+
client: { multicall: (args: any) => Promise<any> };
|
|
525
|
+
positionIds: readonly bigint[];
|
|
526
|
+
chunkSize?: number;
|
|
527
|
+
}): Promise<ReadOracleTiming[]> {
|
|
528
|
+
const chunkSize = params.chunkSize ?? 256;
|
|
529
|
+
if (params.positionIds.length === 0) return [];
|
|
530
|
+
|
|
531
|
+
const calls = params.positionIds.flatMap((pid) => [
|
|
532
|
+
{
|
|
533
|
+
address: params.oracle.address,
|
|
534
|
+
abi: abis.VARLAORACLE_ABI,
|
|
535
|
+
functionName: "getEarlyClosureWindow" as const,
|
|
536
|
+
args: [pid] as const,
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
address: params.oracle.address,
|
|
540
|
+
abi: abis.VARLAORACLE_ABI,
|
|
541
|
+
functionName: "getEarlyClosureFactor" as const,
|
|
542
|
+
args: [pid] as const,
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
address: params.oracle.address,
|
|
546
|
+
abi: abis.VARLAORACLE_ABI,
|
|
547
|
+
functionName: "lastRecoveryFromStale" as const,
|
|
548
|
+
args: [pid] as const,
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
address: params.oracle.address,
|
|
552
|
+
abi: abis.VARLAORACLE_ABI,
|
|
553
|
+
functionName: "getLastUpdated" as const,
|
|
554
|
+
args: [pid] as const,
|
|
555
|
+
},
|
|
556
|
+
]);
|
|
557
|
+
|
|
558
|
+
const res = await multicallChunks({
|
|
559
|
+
client: params.client as any,
|
|
560
|
+
contracts: calls as any,
|
|
561
|
+
chunkSize,
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
const out: ReadOracleTiming[] = [];
|
|
565
|
+
const stride = 4;
|
|
566
|
+
for (let i = 0; i < params.positionIds.length; i++) {
|
|
567
|
+
const base = i * stride;
|
|
568
|
+
const r0: any = (res as any[])[base + 0];
|
|
569
|
+
const r1: any = (res as any[])[base + 1];
|
|
570
|
+
const r2: any = (res as any[])[base + 2];
|
|
571
|
+
const r3: any = (res as any[])[base + 3];
|
|
572
|
+
if (
|
|
573
|
+
r0.status !== "success" ||
|
|
574
|
+
r1.status !== "success" ||
|
|
575
|
+
r2.status !== "success" ||
|
|
576
|
+
r3.status !== "success"
|
|
577
|
+
) {
|
|
578
|
+
throw new Error("Oracle timing multicall failed");
|
|
579
|
+
}
|
|
580
|
+
out.push({
|
|
581
|
+
positionId: params.positionIds[i]!,
|
|
582
|
+
earlyClosureWindow: r0.result as bigint,
|
|
583
|
+
earlyClosureFactorWad: r1.result as bigint,
|
|
584
|
+
lastRecoveryFromStale: r2.result as bigint,
|
|
585
|
+
lastUpdated: r3.result as bigint,
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
return out;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Multicall-chunked tryGetPrice hydration for many positions.
|
|
593
|
+
*/
|
|
594
|
+
// wraps: VarlaOracle.tryGetPrice
|
|
595
|
+
export async function readManyTryGetPrice(params: {
|
|
596
|
+
oracle: { address: Address };
|
|
597
|
+
client: { multicall: (args: any) => Promise<any> };
|
|
598
|
+
positionIds: readonly bigint[];
|
|
599
|
+
chunkSize?: number;
|
|
600
|
+
}): Promise<ReadTryGetPrice[]> {
|
|
601
|
+
const chunkSize = params.chunkSize ?? 256;
|
|
602
|
+
if (params.positionIds.length === 0) return [];
|
|
603
|
+
|
|
604
|
+
const calls = params.positionIds.map((pid) => ({
|
|
605
|
+
address: params.oracle.address,
|
|
606
|
+
abi: abis.VARLAORACLE_ABI,
|
|
607
|
+
functionName: "tryGetPrice" as const,
|
|
608
|
+
args: [pid] as const,
|
|
609
|
+
}));
|
|
610
|
+
|
|
611
|
+
const res = await multicallChunks({
|
|
612
|
+
client: params.client as any,
|
|
613
|
+
contracts: calls as any,
|
|
614
|
+
chunkSize,
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
const out: ReadTryGetPrice[] = [];
|
|
618
|
+
for (let i = 0; i < res.length; i++) {
|
|
619
|
+
const r: any = (res as any[])[i];
|
|
620
|
+
if (r.status !== "success") {
|
|
621
|
+
throw new Error(`Oracle tryGetPrice multicall failed: ${String(r.error ?? "unknown")}`);
|
|
622
|
+
}
|
|
623
|
+
out.push(
|
|
624
|
+
await readTryGetPrice({
|
|
625
|
+
oracle: {
|
|
626
|
+
read: {
|
|
627
|
+
tryGetPrice: async () => r.result,
|
|
628
|
+
},
|
|
629
|
+
} as any,
|
|
630
|
+
positionId: params.positionIds[i]!,
|
|
631
|
+
}),
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
return out;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Multicall-chunked price data hydration for many positions.
|
|
639
|
+
*/
|
|
640
|
+
// wraps: VarlaOracle.getPriceData
|
|
641
|
+
export async function readManyOraclePriceData(params: {
|
|
642
|
+
oracle: { address: Address };
|
|
643
|
+
client: { multicall: (args: any) => Promise<any> };
|
|
644
|
+
positionIds: readonly bigint[];
|
|
645
|
+
chunkSize?: number;
|
|
646
|
+
}): Promise<ReadOraclePriceData[]> {
|
|
647
|
+
const chunkSize = params.chunkSize ?? 256;
|
|
648
|
+
if (params.positionIds.length === 0) return [];
|
|
649
|
+
|
|
650
|
+
const calls = params.positionIds.map((pid) => ({
|
|
651
|
+
address: params.oracle.address,
|
|
652
|
+
abi: abis.VARLAORACLE_ABI,
|
|
653
|
+
functionName: "getPriceData" as const,
|
|
654
|
+
args: [pid] as const,
|
|
655
|
+
}));
|
|
656
|
+
|
|
657
|
+
const res = await multicallChunks({
|
|
658
|
+
client: params.client as any,
|
|
659
|
+
contracts: calls as any,
|
|
660
|
+
chunkSize,
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
const out: ReadOraclePriceData[] = [];
|
|
664
|
+
for (let i = 0; i < res.length; i++) {
|
|
665
|
+
const r: any = (res as any[])[i];
|
|
666
|
+
if (r.status !== "success") {
|
|
667
|
+
throw new Error(`Oracle getPriceData multicall failed: ${String(r.error ?? "unknown")}`);
|
|
668
|
+
}
|
|
669
|
+
out.push(
|
|
670
|
+
await readOraclePriceData({
|
|
671
|
+
oracle: {
|
|
672
|
+
read: {
|
|
673
|
+
getPriceData: async () => r.result,
|
|
674
|
+
},
|
|
675
|
+
} as any,
|
|
676
|
+
positionId: params.positionIds[i]!,
|
|
677
|
+
}),
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
return out;
|
|
681
|
+
}
|
|
682
|
+
|
|
371
683
|
// wraps: VarlaOracle.getConfiguredPositions
|
|
372
684
|
export async function readConfiguredPositionIds(params: {
|
|
373
685
|
oracle: {
|
|
@@ -457,7 +769,7 @@ function normalizePositionSnapshot(raw: unknown, positionId: bigint): ReadPositi
|
|
|
457
769
|
const priceE8 = r.priceE8 ?? r[1];
|
|
458
770
|
const manuallyInvalidated = r.manuallyInvalidated ?? r[2];
|
|
459
771
|
const riskTier = r.riskTier ?? r[3];
|
|
460
|
-
const earlyClosureFactorWad = r.earlyClosureFactorWad ?? r[4];
|
|
772
|
+
const earlyClosureFactorWad = r.earlyClosureFactorWad ?? r.ltvAdjustmentFactorWad ?? r[4];
|
|
461
773
|
const lastRecoveryFromStale = r.lastRecoveryFromStale_ ?? r.lastRecoveryFromStale ?? r[5];
|
|
462
774
|
const isFinalized = r.isFinalized_ ?? r.isFinalized ?? r[6];
|
|
463
775
|
|
|
@@ -741,3 +1053,78 @@ export async function hydrateOraclePositionIds(params: {
|
|
|
741
1053
|
]);
|
|
742
1054
|
return { positionIds: [...params.positionIds], snapshots, meta };
|
|
743
1055
|
}
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Aggregate reader for the admin Oracle page.
|
|
1059
|
+
*/
|
|
1060
|
+
// wraps: VarlaOracle.maxStaleness,VarlaOracle.liquidationGracePeriod,VarlaOracle.defaultEarlyClosureWindow,VarlaOracle.updater,VarlaOracle.collateralDecimals,VarlaOracle.getConfiguredPositions,VarlaOracle.getPositionSnapshot,VarlaOracle.getConditionId,VarlaOracle.getResolutionTime,VarlaOracle.getOppositePositionId,VarlaOracle.isNegRisk,VarlaOracle.getNegRiskMarketId,VarlaOracle.isManuallyInvalidated,VarlaOracle.isConfigured,VarlaOracle.isResolved,VarlaOracle.isDepositAllowed,VarlaOracle.isValidCollateral,VarlaOracle.isPriceStale,VarlaOracle.getEarlyClosureWindow,VarlaOracle.getEarlyClosureFactor,VarlaOracle.lastRecoveryFromStale,VarlaOracle.getLastUpdated,VarlaOracle.tryGetPrice,VarlaOracle.getPriceData
|
|
1061
|
+
export async function readOracleDashboard(params: {
|
|
1062
|
+
oracle: {
|
|
1063
|
+
address: Address;
|
|
1064
|
+
read: {
|
|
1065
|
+
maxStaleness: () => Promise<bigint>;
|
|
1066
|
+
liquidationGracePeriod: () => Promise<bigint>;
|
|
1067
|
+
defaultEarlyClosureWindow: () => Promise<bigint>;
|
|
1068
|
+
updater: () => Promise<Address>;
|
|
1069
|
+
collateralDecimals: () => Promise<number | bigint>;
|
|
1070
|
+
getConfiguredPositions: () => Promise<readonly bigint[]>;
|
|
1071
|
+
};
|
|
1072
|
+
};
|
|
1073
|
+
client: { multicall: (args: any) => Promise<any> };
|
|
1074
|
+
chunkSize?: number;
|
|
1075
|
+
}): Promise<ReadOracleDashboard> {
|
|
1076
|
+
const chunkSize = params.chunkSize ?? 256;
|
|
1077
|
+
const [config, basics, positionIds] = await Promise.all([
|
|
1078
|
+
readOracleConfig({ oracle: params.oracle }),
|
|
1079
|
+
readOracleBasics({ oracle: params.oracle }),
|
|
1080
|
+
readConfiguredPositionIds({ oracle: params.oracle }),
|
|
1081
|
+
]);
|
|
1082
|
+
|
|
1083
|
+
if (positionIds.length === 0) {
|
|
1084
|
+
return { config, basics, positionIds: [], rows: [] };
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
const [snapshots, meta, statusFlags, priceData] = await Promise.all([
|
|
1088
|
+
readManyPositionSnapshots({
|
|
1089
|
+
oracle: { address: params.oracle.address },
|
|
1090
|
+
client: params.client,
|
|
1091
|
+
positionIds,
|
|
1092
|
+
chunkSize,
|
|
1093
|
+
}),
|
|
1094
|
+
readManyOraclePositionMeta({
|
|
1095
|
+
oracle: { address: params.oracle.address },
|
|
1096
|
+
client: params.client,
|
|
1097
|
+
positionIds,
|
|
1098
|
+
chunkSize,
|
|
1099
|
+
}),
|
|
1100
|
+
readManyOracleStatusFlags({
|
|
1101
|
+
oracle: { address: params.oracle.address },
|
|
1102
|
+
client: params.client,
|
|
1103
|
+
positionIds,
|
|
1104
|
+
chunkSize,
|
|
1105
|
+
}),
|
|
1106
|
+
readManyOraclePriceData({
|
|
1107
|
+
oracle: { address: params.oracle.address },
|
|
1108
|
+
client: params.client,
|
|
1109
|
+
positionIds,
|
|
1110
|
+
chunkSize,
|
|
1111
|
+
}),
|
|
1112
|
+
]);
|
|
1113
|
+
|
|
1114
|
+
const rows = positionIds.map((positionId, i) => ({
|
|
1115
|
+
positionId,
|
|
1116
|
+
snapshot: snapshots[i]!,
|
|
1117
|
+
meta: meta[i]!,
|
|
1118
|
+
resolvedStatus: {
|
|
1119
|
+
positionId,
|
|
1120
|
+
isResolved: statusFlags[i]!.isResolved,
|
|
1121
|
+
},
|
|
1122
|
+
staleStatus: {
|
|
1123
|
+
positionId,
|
|
1124
|
+
isPriceStale: statusFlags[i]!.isPriceStale,
|
|
1125
|
+
},
|
|
1126
|
+
priceData: priceData[i]!,
|
|
1127
|
+
}));
|
|
1128
|
+
|
|
1129
|
+
return { config, basics, positionIds, rows };
|
|
1130
|
+
}
|
package/src/views/pool.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Note: explicit .js extension is required for Node ESM resolution.
|
|
2
2
|
|
|
3
3
|
import type { Address } from "viem";
|
|
4
|
+
import { multicallChunks } from "../batch.js";
|
|
5
|
+
import { abis } from "../generated.js";
|
|
4
6
|
|
|
5
7
|
export type ReadPoolSnapshot = {
|
|
6
8
|
totalAssets: bigint;
|
|
@@ -154,6 +156,16 @@ export type ReadPoolHealthScore =
|
|
|
154
156
|
kind: "no-liquidity";
|
|
155
157
|
};
|
|
156
158
|
|
|
159
|
+
export type ReadPoolDashboard = {
|
|
160
|
+
snapshot: ReadPoolSnapshot;
|
|
161
|
+
caps: ReadPoolCaps;
|
|
162
|
+
accounting: ReadPoolAccounting;
|
|
163
|
+
rates: ReadPoolRates;
|
|
164
|
+
sharePrice: ReadPoolSharePrice;
|
|
165
|
+
healthScore: ReadPoolHealthScore;
|
|
166
|
+
debtState: ReadPoolDebtState;
|
|
167
|
+
};
|
|
168
|
+
|
|
157
169
|
/**
|
|
158
170
|
* Reads pool “rates” and near-term capacity in one convenience call.
|
|
159
171
|
*/
|
|
@@ -275,3 +287,144 @@ export async function readPoolCoreAddress(params: {
|
|
|
275
287
|
}): Promise<Address> {
|
|
276
288
|
return params.pool.read.varlaCore();
|
|
277
289
|
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Multicall-backed aggregate reader for pool-heavy UIs.
|
|
293
|
+
*
|
|
294
|
+
* Deduplicates the overlapping primitives used across snapshot/caps/accounting/rates/share price
|
|
295
|
+
* so frontends can hydrate the full pool page with one batched request group.
|
|
296
|
+
*/
|
|
297
|
+
// wraps: VarlaPool.getPoolStats,VarlaPool.depositCap,VarlaPool.borrowCap,VarlaPool.reserveBalance,VarlaPool.scaledTotalBorrowed,VarlaPool.lastUpdateTimestamp,VarlaPool.totalSupply,VarlaPool.maxBorrow,VarlaPool.getCurrentBorrowIndex
|
|
298
|
+
export async function readPoolDashboard(params: {
|
|
299
|
+
pool: { address: Address };
|
|
300
|
+
client: { multicall: (args: any) => Promise<any> };
|
|
301
|
+
chunkSize?: number;
|
|
302
|
+
}): Promise<ReadPoolDashboard> {
|
|
303
|
+
const chunkSize = params.chunkSize ?? 256;
|
|
304
|
+
|
|
305
|
+
const calls = [
|
|
306
|
+
{
|
|
307
|
+
address: params.pool.address,
|
|
308
|
+
abi: abis.VARLAPOOL_ABI,
|
|
309
|
+
functionName: "getPoolStats" as const,
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
address: params.pool.address,
|
|
313
|
+
abi: abis.VARLAPOOL_ABI,
|
|
314
|
+
functionName: "depositCap" as const,
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
address: params.pool.address,
|
|
318
|
+
abi: abis.VARLAPOOL_ABI,
|
|
319
|
+
functionName: "borrowCap" as const,
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
address: params.pool.address,
|
|
323
|
+
abi: abis.VARLAPOOL_ABI,
|
|
324
|
+
functionName: "reserveBalance" as const,
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
address: params.pool.address,
|
|
328
|
+
abi: abis.VARLAPOOL_ABI,
|
|
329
|
+
functionName: "scaledTotalBorrowed" as const,
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
address: params.pool.address,
|
|
333
|
+
abi: abis.VARLAPOOL_ABI,
|
|
334
|
+
functionName: "lastUpdateTimestamp" as const,
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
address: params.pool.address,
|
|
338
|
+
abi: abis.VARLAPOOL_ABI,
|
|
339
|
+
functionName: "totalSupply" as const,
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
address: params.pool.address,
|
|
343
|
+
abi: abis.VARLAPOOL_ABI,
|
|
344
|
+
functionName: "maxBorrow" as const,
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
address: params.pool.address,
|
|
348
|
+
abi: abis.VARLAPOOL_ABI,
|
|
349
|
+
functionName: "getCurrentBorrowIndex" as const,
|
|
350
|
+
},
|
|
351
|
+
];
|
|
352
|
+
|
|
353
|
+
const res = await multicallChunks({
|
|
354
|
+
client: params.client as any,
|
|
355
|
+
contracts: calls as any,
|
|
356
|
+
chunkSize,
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
for (const r of res as any[]) {
|
|
360
|
+
if (r.status !== "success") {
|
|
361
|
+
throw new Error(`Pool dashboard multicall failed: ${String(r.error ?? "unknown")}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const snapshot = await readPoolSnapshot({
|
|
366
|
+
pool: {
|
|
367
|
+
read: {
|
|
368
|
+
getPoolStats: async () => (res as any[])[0]!.result,
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
const depositCap = (res as any[])[1]!.result as bigint;
|
|
374
|
+
const borrowCap = (res as any[])[2]!.result as bigint;
|
|
375
|
+
const reserveBalance = (res as any[])[3]!.result as bigint;
|
|
376
|
+
const scaledTotalBorrowed = (res as any[])[4]!.result as bigint;
|
|
377
|
+
const lastUpdateTimestamp = BigInt((res as any[])[5]!.result);
|
|
378
|
+
const totalShares = (res as any[])[6]!.result as bigint;
|
|
379
|
+
const maxBorrow = (res as any[])[7]!.result as bigint;
|
|
380
|
+
const currentBorrowIndex = (res as any[])[8]!.result as bigint;
|
|
381
|
+
|
|
382
|
+
const sharePrice: ReadPoolSharePrice = {
|
|
383
|
+
totalAssets: snapshot.totalAssets,
|
|
384
|
+
totalShares,
|
|
385
|
+
assetsPerShareWad:
|
|
386
|
+
totalShares === 0n ? 0n : (snapshot.totalAssets * 1_000_000_000_000_000_000n) / totalShares,
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
const healthScore: ReadPoolHealthScore =
|
|
390
|
+
snapshot.totalAssets === 0n
|
|
391
|
+
? { kind: "no-liquidity" }
|
|
392
|
+
: {
|
|
393
|
+
kind: "ok",
|
|
394
|
+
utilizationWad: snapshot.utilization,
|
|
395
|
+
scoreBps:
|
|
396
|
+
((1_000_000_000_000_000_000n -
|
|
397
|
+
(snapshot.utilization > 1_000_000_000_000_000_000n
|
|
398
|
+
? 1_000_000_000_000_000_000n
|
|
399
|
+
: snapshot.utilization < 0n
|
|
400
|
+
? 0n
|
|
401
|
+
: snapshot.utilization)) *
|
|
402
|
+
10_000n) /
|
|
403
|
+
1_000_000_000_000_000_000n,
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
return {
|
|
407
|
+
snapshot,
|
|
408
|
+
caps: { depositCap, borrowCap },
|
|
409
|
+
accounting: {
|
|
410
|
+
reserveBalance,
|
|
411
|
+
scaledTotalBorrowed,
|
|
412
|
+
borrowIndex: snapshot.borrowIndex,
|
|
413
|
+
lastUpdateTimestamp,
|
|
414
|
+
},
|
|
415
|
+
rates: {
|
|
416
|
+
utilization: snapshot.utilization,
|
|
417
|
+
borrowRate: snapshot.borrowRate,
|
|
418
|
+
supplyAPY: snapshot.supplyAPY,
|
|
419
|
+
availableLiquidity: snapshot.available,
|
|
420
|
+
maxBorrow,
|
|
421
|
+
},
|
|
422
|
+
sharePrice,
|
|
423
|
+
healthScore,
|
|
424
|
+
debtState: {
|
|
425
|
+
totalBorrowed: snapshot.totalBorrowed,
|
|
426
|
+
currentBorrowIndex,
|
|
427
|
+
borrowRate: snapshot.borrowRate,
|
|
428
|
+
},
|
|
429
|
+
};
|
|
430
|
+
}
|
package/src/views/system.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
// Note: explicit .js extension is required for Node ESM resolution.
|
|
2
2
|
|
|
3
|
-
import type { ReadDefaultLtvConfig, ReadLiquidationConfig } from "./core.js";
|
|
4
|
-
import { readDefaultLtvConfig, readLiquidationConfig } from "./core.js";
|
|
3
|
+
import type { ReadCoreAddresses, ReadDefaultLtvConfig, ReadLiquidationConfig } from "./core.js";
|
|
4
|
+
import { readCoreDashboard, readDefaultLtvConfig, readLiquidationConfig } from "./core.js";
|
|
5
5
|
import type { ReadOracleConfig } from "./oracle.js";
|
|
6
6
|
import { readOracleConfig } from "./oracle.js";
|
|
7
|
-
import type {
|
|
8
|
-
|
|
7
|
+
import type {
|
|
8
|
+
ReadPoolAccounting,
|
|
9
|
+
ReadPoolCaps,
|
|
10
|
+
ReadPoolHealthScore,
|
|
11
|
+
ReadPoolSharePrice,
|
|
12
|
+
ReadPoolSnapshot,
|
|
13
|
+
} from "./pool.js";
|
|
14
|
+
import { readPoolAccounting, readPoolCaps, readPoolDashboard, readPoolSnapshot } from "./pool.js";
|
|
9
15
|
|
|
10
16
|
export type ReadSystemSnapshot = {
|
|
11
17
|
pool: ReadPoolSnapshot;
|
|
@@ -16,6 +22,12 @@ export type ReadSystemSnapshot = {
|
|
|
16
22
|
oracle: ReadOracleConfig;
|
|
17
23
|
};
|
|
18
24
|
|
|
25
|
+
export type ReadSystemDashboardSnapshot = ReadSystemSnapshot & {
|
|
26
|
+
poolSharePrice: ReadPoolSharePrice;
|
|
27
|
+
poolHealthScore: ReadPoolHealthScore;
|
|
28
|
+
coreAddresses: ReadCoreAddresses;
|
|
29
|
+
};
|
|
30
|
+
|
|
19
31
|
/**
|
|
20
32
|
* A lightweight “global protocol state” read for dashboards.
|
|
21
33
|
*
|
|
@@ -40,3 +52,41 @@ export async function readSystemSnapshot(params: {
|
|
|
40
52
|
|
|
41
53
|
return { pool, poolCaps, poolAccounting, coreLtv, coreLiquidation, oracle };
|
|
42
54
|
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Multicall-backed system snapshot used by dashboards.
|
|
58
|
+
*/
|
|
59
|
+
export async function readSystemDashboardSnapshot(params: {
|
|
60
|
+
pool: { address: `0x${string}` };
|
|
61
|
+
core: { address: `0x${string}` };
|
|
62
|
+
oracle: any;
|
|
63
|
+
client: { multicall: (args: any) => Promise<any> };
|
|
64
|
+
}): Promise<ReadSystemDashboardSnapshot> {
|
|
65
|
+
const [poolDashboard, coreDashboard, oracle] = await Promise.all([
|
|
66
|
+
readPoolDashboard({
|
|
67
|
+
pool: { address: params.pool.address },
|
|
68
|
+
client: params.client,
|
|
69
|
+
}),
|
|
70
|
+
readCoreDashboard({
|
|
71
|
+
core: { address: params.core.address },
|
|
72
|
+
client: params.client,
|
|
73
|
+
}),
|
|
74
|
+
readOracleConfig({ oracle: params.oracle }),
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
pool: poolDashboard.snapshot,
|
|
79
|
+
poolCaps: poolDashboard.caps,
|
|
80
|
+
poolAccounting: poolDashboard.accounting,
|
|
81
|
+
coreLtv: {
|
|
82
|
+
conservative: coreDashboard.ltvConfig.tier0,
|
|
83
|
+
moderate: coreDashboard.ltvConfig.tier1,
|
|
84
|
+
risk: coreDashboard.ltvConfig.tier2,
|
|
85
|
+
},
|
|
86
|
+
coreLiquidation: coreDashboard.liqConfig,
|
|
87
|
+
oracle,
|
|
88
|
+
poolSharePrice: poolDashboard.sharePrice,
|
|
89
|
+
poolHealthScore: poolDashboard.healthScore,
|
|
90
|
+
coreAddresses: coreDashboard.coreAddresses,
|
|
91
|
+
};
|
|
92
|
+
}
|