@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/src/views/core.ts CHANGED
@@ -891,6 +891,40 @@ export type ReadTierLiquidationConfig = {
891
891
  liquidationFeeBps: bigint;
892
892
  };
893
893
 
894
+ export type ReadCoreDashboard = {
895
+ globalDebt: ReadCoreGlobalDebt;
896
+ coreAddresses: ReadCoreAddresses;
897
+ maxPositions: ReadMaxPositionsConfig;
898
+ ltvConfig: ReadTieredLtvConfig;
899
+ liqConfig: ReadLiquidationConfig;
900
+ tierLiq: readonly [
901
+ ReadTierLiquidationConfig | null,
902
+ ReadTierLiquidationConfig | null,
903
+ ReadTierLiquidationConfig | null,
904
+ ];
905
+ };
906
+
907
+ export type ReadConfiguredPositionDepositRow = {
908
+ positionId: bigint;
909
+ conditionId: `0x${string}`;
910
+ depositedBalance: bigint;
911
+ priceOk: boolean;
912
+ spotPriceE8: bigint;
913
+ twapPriceE8: bigint;
914
+ priceE8: bigint;
915
+ effectivePriceE8: bigint;
916
+ usedFallbackPrice: boolean;
917
+ depositValue: bigint;
918
+ };
919
+
920
+ export type ReadConfiguredPositionDepositsSummary = {
921
+ configuredCount: number;
922
+ pricedCount: number;
923
+ totalDepositedBalance: bigint;
924
+ totalDepositedValue: bigint;
925
+ rows: ReadConfiguredPositionDepositRow[];
926
+ };
927
+
894
928
  /**
895
929
  * Normalized wrapper over `VarlaCore.getTierLiquidationConfig(tier)`.
896
930
  */
@@ -915,6 +949,314 @@ export async function readTierLiquidationConfig(params: {
915
949
  return { tier: params.tier, maxLiquidationBonusBps, liquidationFeeBps };
916
950
  }
917
951
 
952
+ /**
953
+ * Multicall-backed aggregate reader for the admin Core page.
954
+ */
955
+ // wraps: VarlaCore.totalScaledDebt,VarlaCore.collateralToken,VarlaCore.positionsToken,VarlaCore.pool,VarlaCore.oracle,VarlaCore.collateralDecimals,VarlaCore.maxPositions,VarlaCore.minMaxPositions,VarlaCore.maxMaxPositions,VarlaCore.getDefaultLtvConfig,VarlaCore.getLiquidationConfig,VarlaCore.getTierLiquidationConfig
956
+ export async function readCoreDashboard(params: {
957
+ core: { address: Address };
958
+ client: { multicall: (args: any) => Promise<any> };
959
+ chunkSize?: number;
960
+ }): Promise<ReadCoreDashboard> {
961
+ const chunkSize = params.chunkSize ?? 256;
962
+
963
+ const calls = [
964
+ {
965
+ address: params.core.address,
966
+ abi: abis.VARLACORE_ABI,
967
+ functionName: "totalScaledDebt" as const,
968
+ },
969
+ {
970
+ address: params.core.address,
971
+ abi: abis.VARLACORE_ABI,
972
+ functionName: "collateralToken" as const,
973
+ },
974
+ {
975
+ address: params.core.address,
976
+ abi: abis.VARLACORE_ABI,
977
+ functionName: "positionsToken" as const,
978
+ },
979
+ {
980
+ address: params.core.address,
981
+ abi: abis.VARLACORE_ABI,
982
+ functionName: "pool" as const,
983
+ },
984
+ {
985
+ address: params.core.address,
986
+ abi: abis.VARLACORE_ABI,
987
+ functionName: "oracle" as const,
988
+ },
989
+ {
990
+ address: params.core.address,
991
+ abi: abis.VARLACORE_ABI,
992
+ functionName: "collateralDecimals" as const,
993
+ },
994
+ {
995
+ address: params.core.address,
996
+ abi: abis.VARLACORE_ABI,
997
+ functionName: "maxPositions" as const,
998
+ },
999
+ {
1000
+ address: params.core.address,
1001
+ abi: abis.VARLACORE_ABI,
1002
+ functionName: "minMaxPositions" as const,
1003
+ },
1004
+ {
1005
+ address: params.core.address,
1006
+ abi: abis.VARLACORE_ABI,
1007
+ functionName: "maxMaxPositions" as const,
1008
+ },
1009
+ {
1010
+ address: params.core.address,
1011
+ abi: abis.VARLACORE_ABI,
1012
+ functionName: "getDefaultLtvConfig" as const,
1013
+ },
1014
+ {
1015
+ address: params.core.address,
1016
+ abi: abis.VARLACORE_ABI,
1017
+ functionName: "getLiquidationConfig" as const,
1018
+ },
1019
+ {
1020
+ address: params.core.address,
1021
+ abi: abis.VARLACORE_ABI,
1022
+ functionName: "getTierLiquidationConfig" as const,
1023
+ args: [0] as const,
1024
+ },
1025
+ {
1026
+ address: params.core.address,
1027
+ abi: abis.VARLACORE_ABI,
1028
+ functionName: "getTierLiquidationConfig" as const,
1029
+ args: [1] as const,
1030
+ },
1031
+ {
1032
+ address: params.core.address,
1033
+ abi: abis.VARLACORE_ABI,
1034
+ functionName: "getTierLiquidationConfig" as const,
1035
+ args: [2] as const,
1036
+ },
1037
+ ];
1038
+
1039
+ const res = await multicallChunks({
1040
+ client: params.client as any,
1041
+ contracts: calls as any,
1042
+ chunkSize,
1043
+ });
1044
+
1045
+ const ensureSuccess = (r: any, label: string) => {
1046
+ if (r.status !== "success") {
1047
+ throw new Error(`Core dashboard ${label} multicall failed: ${String(r.error ?? "unknown")}`);
1048
+ }
1049
+ return r.result;
1050
+ };
1051
+
1052
+ const totalScaledDebt = ensureSuccess((res as any[])[0], "totalScaledDebt") as bigint;
1053
+ const collateralToken = ensureSuccess((res as any[])[1], "collateralToken") as Address;
1054
+ const positionsToken = ensureSuccess((res as any[])[2], "positionsToken") as Address;
1055
+ const pool = ensureSuccess((res as any[])[3], "pool") as Address;
1056
+ const oracle = ensureSuccess((res as any[])[4], "oracle") as Address;
1057
+ const collateralDecimalsRaw = ensureSuccess((res as any[])[5], "collateralDecimals") as
1058
+ | bigint
1059
+ | number;
1060
+ const maxPositions = ensureSuccess((res as any[])[6], "maxPositions") as bigint;
1061
+ const minMaxPositions = ensureSuccess((res as any[])[7], "minMaxPositions") as bigint;
1062
+ const maxMaxPositions = ensureSuccess((res as any[])[8], "maxMaxPositions") as bigint;
1063
+ const defaultLtvRaw = ensureSuccess((res as any[])[9], "getDefaultLtvConfig");
1064
+ const liqRaw = ensureSuccess((res as any[])[10], "getLiquidationConfig");
1065
+ const tier0Raw = ensureSuccess((res as any[])[11], "getTierLiquidationConfig(0)");
1066
+ const tier1Raw = ensureSuccess((res as any[])[12], "getTierLiquidationConfig(1)");
1067
+ const tier2Raw = ensureSuccess((res as any[])[13], "getTierLiquidationConfig(2)");
1068
+
1069
+ const coreLike = {
1070
+ read: {
1071
+ getDefaultLtvConfig: async () => defaultLtvRaw,
1072
+ getLiquidationConfig: async () => liqRaw,
1073
+ getTierLiquidationConfig: async (args: readonly [number]) => {
1074
+ if (args[0] === 0) return tier0Raw;
1075
+ if (args[0] === 1) return tier1Raw;
1076
+ return tier2Raw;
1077
+ },
1078
+ },
1079
+ } as any;
1080
+
1081
+ const collateralDecimals =
1082
+ typeof collateralDecimalsRaw === "bigint"
1083
+ ? Number(collateralDecimalsRaw)
1084
+ : collateralDecimalsRaw;
1085
+
1086
+ return {
1087
+ globalDebt: { totalScaledDebt },
1088
+ coreAddresses: { collateralToken, positionsToken, pool, oracle, collateralDecimals },
1089
+ maxPositions: { maxPositions, minMaxPositions, maxMaxPositions },
1090
+ ltvConfig: await readTieredLtvConfig({ core: coreLike }),
1091
+ liqConfig: await readLiquidationConfig({ core: coreLike }),
1092
+ tierLiq: [
1093
+ await readTierLiquidationConfig({ core: coreLike, tier: 0 }),
1094
+ await readTierLiquidationConfig({ core: coreLike, tier: 1 }),
1095
+ await readTierLiquidationConfig({ core: coreLike, tier: 2 }),
1096
+ ] as const,
1097
+ };
1098
+ }
1099
+
1100
+ /**
1101
+ * Reads deposited balances for all oracle-configured positions.
1102
+ *
1103
+ * Uses:
1104
+ * - `oracle.getConfiguredPositions()`
1105
+ * - `positionsToken.balanceOf(core, positionId)`
1106
+ * - `oracle.getPositionSnapshot(positionId)` for pricing
1107
+ * - `oracle.getPriceData(positionId)` for fallback pricing
1108
+ * - `oracle.getConditionId(positionId)` for market mapping
1109
+ */
1110
+ // wraps: VarlaOracle.getConfiguredPositions,ERC1155.balanceOf,VarlaOracle.getPositionSnapshot,VarlaOracle.getPriceData,VarlaOracle.getConditionId
1111
+ export async function readConfiguredPositionDepositsSummary(params: {
1112
+ core: { address: Address };
1113
+ oracle: { address: Address };
1114
+ positionsToken: { address: Address };
1115
+ client: { multicall: (args: any) => Promise<any> };
1116
+ chunkSize?: number;
1117
+ }): Promise<ReadConfiguredPositionDepositsSummary> {
1118
+ const chunkSize = params.chunkSize ?? 256;
1119
+
1120
+ const cfgRes = await multicallChunks({
1121
+ client: params.client as any,
1122
+ contracts: [
1123
+ {
1124
+ address: params.oracle.address,
1125
+ abi: abis.VARLAORACLE_ABI,
1126
+ functionName: "getConfiguredPositions" as const,
1127
+ },
1128
+ ] as any,
1129
+ chunkSize,
1130
+ });
1131
+
1132
+ const cfg0: any = (cfgRes as any[])[0];
1133
+ if (!cfg0 || cfg0.status !== "success" || !Array.isArray(cfg0.result)) {
1134
+ throw new Error(`Configured positions read failed: ${String(cfg0?.error ?? "unknown")}`);
1135
+ }
1136
+
1137
+ const positionIds = [...(cfg0.result as readonly bigint[])];
1138
+ if (positionIds.length === 0) {
1139
+ return {
1140
+ configuredCount: 0,
1141
+ pricedCount: 0,
1142
+ totalDepositedBalance: 0n,
1143
+ totalDepositedValue: 0n,
1144
+ rows: [],
1145
+ };
1146
+ }
1147
+
1148
+ const calls = positionIds.flatMap((pid) => [
1149
+ {
1150
+ address: params.positionsToken.address,
1151
+ abi: erc1155Abi,
1152
+ functionName: "balanceOf" as const,
1153
+ args: [params.core.address, pid] as const,
1154
+ },
1155
+ {
1156
+ address: params.oracle.address,
1157
+ abi: abis.VARLAORACLE_ABI,
1158
+ functionName: "getPositionSnapshot" as const,
1159
+ args: [pid] as const,
1160
+ },
1161
+ {
1162
+ address: params.oracle.address,
1163
+ abi: abis.VARLAORACLE_ABI,
1164
+ functionName: "getPriceData" as const,
1165
+ args: [pid] as const,
1166
+ },
1167
+ {
1168
+ address: params.oracle.address,
1169
+ abi: abis.VARLAORACLE_ABI,
1170
+ functionName: "getConditionId" as const,
1171
+ args: [pid] as const,
1172
+ },
1173
+ ]);
1174
+
1175
+ const res = await multicallChunks({
1176
+ client: params.client as any,
1177
+ contracts: calls as any,
1178
+ chunkSize,
1179
+ });
1180
+
1181
+ const rows: ReadConfiguredPositionDepositRow[] = [];
1182
+ let totalDepositedBalance = 0n;
1183
+ let totalDepositedValue = 0n;
1184
+ let pricedCount = 0;
1185
+
1186
+ for (let i = 0; i < positionIds.length; i++) {
1187
+ const balR: any = (res as any[])[i * 4];
1188
+ const snapR: any = (res as any[])[i * 4 + 1];
1189
+ const priceR: any = (res as any[])[i * 4 + 2];
1190
+ const condR: any = (res as any[])[i * 4 + 3];
1191
+ const pid = positionIds[i]!;
1192
+
1193
+ if (balR?.status !== "success") {
1194
+ throw new Error(
1195
+ `Configured position balance read failed: ${String(balR?.error ?? "unknown")}`,
1196
+ );
1197
+ }
1198
+ if (snapR?.status !== "success") {
1199
+ throw new Error(
1200
+ `Configured position snapshot read failed: ${String(snapR?.error ?? "unknown")}`,
1201
+ );
1202
+ }
1203
+ if (priceR?.status !== "success") {
1204
+ throw new Error(
1205
+ `Configured position priceData read failed: ${String(priceR?.error ?? "unknown")}`,
1206
+ );
1207
+ }
1208
+ if (condR?.status !== "success") {
1209
+ throw new Error(
1210
+ `Configured position condition read failed: ${String(condR?.error ?? "unknown")}`,
1211
+ );
1212
+ }
1213
+
1214
+ const depositedBalance = balR.result as bigint;
1215
+ if (typeof depositedBalance !== "bigint") {
1216
+ throw new Error("Unexpected ERC1155.balanceOf return type");
1217
+ }
1218
+
1219
+ const snap = _normalizeOraclePositionSnapshot(snapR.result, pid);
1220
+ const priceData = _normalizeOraclePriceData(priceR.result, pid);
1221
+ const conditionId = condR.result as `0x${string}`;
1222
+ if (typeof conditionId !== "string" || !conditionId.startsWith("0x")) {
1223
+ throw new Error("Unexpected getConditionId() return shape");
1224
+ }
1225
+
1226
+ const fallbackPriceE8 = _minPositive(priceData.priceE8, priceData.twapE8);
1227
+ const hasSnapshotPrice = snap.priceOk && snap.priceE8 > 0n;
1228
+ const effectivePriceE8 = hasSnapshotPrice ? snap.priceE8 : fallbackPriceE8;
1229
+ const priced = effectivePriceE8 > 0n;
1230
+ const usedFallbackPrice = !hasSnapshotPrice && priced;
1231
+ const depositValue = priced ? (depositedBalance * effectivePriceE8) / _E8 : 0n;
1232
+
1233
+ totalDepositedBalance += depositedBalance;
1234
+ totalDepositedValue += depositValue;
1235
+ if (priced) pricedCount += 1;
1236
+
1237
+ rows.push({
1238
+ positionId: pid,
1239
+ conditionId,
1240
+ depositedBalance,
1241
+ priceOk: snap.priceOk,
1242
+ spotPriceE8: priceData.priceE8,
1243
+ twapPriceE8: priceData.twapE8,
1244
+ priceE8: snap.priceE8,
1245
+ effectivePriceE8,
1246
+ usedFallbackPrice,
1247
+ depositValue,
1248
+ });
1249
+ }
1250
+
1251
+ return {
1252
+ configuredCount: positionIds.length,
1253
+ pricedCount,
1254
+ totalDepositedBalance,
1255
+ totalDepositedValue,
1256
+ rows,
1257
+ };
1258
+ }
1259
+
918
1260
  export type ReadLiquidationParamsForPosition = {
919
1261
  positionId: bigint;
920
1262
  maxLiquidationBonusBps: bigint;
@@ -1429,6 +1771,12 @@ type _OraclePositionSnapshot = {
1429
1771
  earlyClosureFactorWad: bigint;
1430
1772
  };
1431
1773
 
1774
+ type _OraclePriceData = {
1775
+ positionId: bigint;
1776
+ priceE8: bigint;
1777
+ twapE8: bigint;
1778
+ };
1779
+
1432
1780
  function _normalizeOraclePositionSnapshot(
1433
1781
  raw: unknown,
1434
1782
  positionId: bigint,
@@ -1460,6 +1808,31 @@ function _normalizeOraclePositionSnapshot(
1460
1808
  };
1461
1809
  }
1462
1810
 
1811
+ function _normalizeOraclePriceData(raw: unknown, positionId: bigint): _OraclePriceData {
1812
+ const r: any = raw as any;
1813
+ const priceE8 = r.price ?? r[0];
1814
+ const twapE8 = r.twap ?? r[1];
1815
+
1816
+ if (typeof priceE8 !== "bigint" || typeof twapE8 !== "bigint") {
1817
+ throw new Error("Unexpected getPriceData() return shape");
1818
+ }
1819
+
1820
+ return {
1821
+ positionId,
1822
+ priceE8,
1823
+ twapE8,
1824
+ };
1825
+ }
1826
+
1827
+ function _minPositive(a: bigint, b: bigint): bigint {
1828
+ const aOk = a > 0n;
1829
+ const bOk = b > 0n;
1830
+ if (aOk && bOk) return a < b ? a : b;
1831
+ if (aOk) return a;
1832
+ if (bOk) return b;
1833
+ return 0n;
1834
+ }
1835
+
1463
1836
  function _tierDefaultLtv(defaultLtv: ReadDefaultLtvConfig, riskTier: number): bigint {
1464
1837
  if (riskTier === 0) return defaultLtv.conservative;
1465
1838
  if (riskTier === 1) return defaultLtv.moderate;
@@ -2,6 +2,8 @@
2
2
 
3
3
  import type { Address, PublicClient } from "viem";
4
4
 
5
+ import { multicallChunks } from "../batch.js";
6
+ import { abis } from "../generated.js";
5
7
  import { readAccountPositionsFull } from "./core.js";
6
8
  import { type ReadPositionSnapshot, readManyPositionSnapshots } from "./oracle.js";
7
9
 
@@ -51,17 +53,8 @@ export type ReadCanLiquidate = {
51
53
  currentBonus: bigint;
52
54
  };
53
55
 
54
- /**
55
- * Normalized wrapper over `*.canLiquidate(user)`.
56
- */
57
- // wraps: VarlaLiquidator.canLiquidate,VarlaMergeLiquidator.canLiquidate,VarlaConvertLiquidator.canLiquidate
58
- export async function readCanLiquidate(params: {
59
- liquidator: CanLiquidateLike;
60
- user: Address;
61
- }): Promise<ReadCanLiquidate> {
62
- const raw = await params.liquidator.read.canLiquidate([params.user]);
56
+ function normalizeCanLiquidate(raw: unknown, user: Address): ReadCanLiquidate {
63
57
  const r: any = raw as any;
64
-
65
58
  const canLiquidate = r.canLiquidate_ ?? r.canLiquidate ?? r[0];
66
59
  const healthFactor = r.healthFactor ?? r[1];
67
60
  const currentBonus = r.currentBonus ?? r[2];
@@ -74,7 +67,56 @@ export async function readCanLiquidate(params: {
74
67
  throw new Error("Unexpected canLiquidate() return shape");
75
68
  }
76
69
 
77
- return { user: params.user, canLiquidate, healthFactor, currentBonus };
70
+ return { user, canLiquidate, healthFactor, currentBonus };
71
+ }
72
+
73
+ /**
74
+ * Normalized wrapper over `*.canLiquidate(user)`.
75
+ */
76
+ // wraps: VarlaLiquidator.canLiquidate,VarlaMergeLiquidator.canLiquidate,VarlaConvertLiquidator.canLiquidate
77
+ export async function readCanLiquidate(params: {
78
+ liquidator: CanLiquidateLike;
79
+ user: Address;
80
+ }): Promise<ReadCanLiquidate> {
81
+ const raw = await params.liquidator.read.canLiquidate([params.user]);
82
+ return normalizeCanLiquidate(raw, params.user);
83
+ }
84
+
85
+ /**
86
+ * Multicall-chunked version of `readCanLiquidate`.
87
+ */
88
+ // wraps: VarlaLiquidator.canLiquidate,VarlaMergeLiquidator.canLiquidate,VarlaConvertLiquidator.canLiquidate
89
+ export async function readManyCanLiquidate(params: {
90
+ liquidator: { address: Address };
91
+ client: { multicall: (args: any) => Promise<any> };
92
+ users: readonly Address[];
93
+ chunkSize?: number;
94
+ }): Promise<ReadCanLiquidate[]> {
95
+ const chunkSize = params.chunkSize ?? 256;
96
+ if (params.users.length === 0) return [];
97
+
98
+ const calls = params.users.map((user) => ({
99
+ address: params.liquidator.address,
100
+ abi: abis.VARLALIQUIDATOR_ABI,
101
+ functionName: "canLiquidate" as const,
102
+ args: [user] as const,
103
+ }));
104
+
105
+ const res = await multicallChunks({
106
+ client: params.client as any,
107
+ contracts: calls as any,
108
+ chunkSize,
109
+ });
110
+
111
+ const out: ReadCanLiquidate[] = [];
112
+ for (let i = 0; i < res.length; i++) {
113
+ const r: any = (res as any[])[i];
114
+ if (r.status !== "success") {
115
+ throw new Error(`Liquidator canLiquidate multicall failed: ${String(r.error ?? "unknown")}`);
116
+ }
117
+ out.push(normalizeCanLiquidate(r.result, params.users[i]!));
118
+ }
119
+ return out;
78
120
  }
79
121
 
80
122
  type PreviewLiquidationLike = {
@@ -171,15 +213,7 @@ export type ReadBadDebtStatus = {
171
213
  shortfall: bigint;
172
214
  };
173
215
 
174
- /**
175
- * Normalized wrapper over `VarlaLiquidator.checkBadDebt(user)`.
176
- */
177
- // wraps: VarlaLiquidator.checkBadDebt
178
- export async function readBadDebtStatus(params: {
179
- liquidator: CheckBadDebtLike;
180
- user: Address;
181
- }): Promise<ReadBadDebtStatus> {
182
- const raw = await params.liquidator.read.checkBadDebt([params.user]);
216
+ function normalizeBadDebtStatus(raw: unknown, user: Address): ReadBadDebtStatus {
183
217
  const r: any = raw as any;
184
218
 
185
219
  const hasBadDebt = r.hasBadDebt ?? r[0];
@@ -196,7 +230,56 @@ export async function readBadDebtStatus(params: {
196
230
  throw new Error("Unexpected checkBadDebt() return shape");
197
231
  }
198
232
 
199
- return { user: params.user, hasBadDebt, collateralValue, debtValue, shortfall };
233
+ return { user, hasBadDebt, collateralValue, debtValue, shortfall };
234
+ }
235
+
236
+ /**
237
+ * Normalized wrapper over `VarlaLiquidator.checkBadDebt(user)`.
238
+ */
239
+ // wraps: VarlaLiquidator.checkBadDebt
240
+ export async function readBadDebtStatus(params: {
241
+ liquidator: CheckBadDebtLike;
242
+ user: Address;
243
+ }): Promise<ReadBadDebtStatus> {
244
+ const raw = await params.liquidator.read.checkBadDebt([params.user]);
245
+ return normalizeBadDebtStatus(raw, params.user);
246
+ }
247
+
248
+ /**
249
+ * Multicall-chunked version of `readBadDebtStatus`.
250
+ */
251
+ // wraps: VarlaLiquidator.checkBadDebt
252
+ export async function readManyBadDebtStatus(params: {
253
+ liquidator: { address: Address };
254
+ client: { multicall: (args: any) => Promise<any> };
255
+ users: readonly Address[];
256
+ chunkSize?: number;
257
+ }): Promise<ReadBadDebtStatus[]> {
258
+ const chunkSize = params.chunkSize ?? 256;
259
+ if (params.users.length === 0) return [];
260
+
261
+ const calls = params.users.map((user) => ({
262
+ address: params.liquidator.address,
263
+ abi: abis.VARLALIQUIDATOR_ABI,
264
+ functionName: "checkBadDebt" as const,
265
+ args: [user] as const,
266
+ }));
267
+
268
+ const res = await multicallChunks({
269
+ client: params.client as any,
270
+ contracts: calls as any,
271
+ chunkSize,
272
+ });
273
+
274
+ const out: ReadBadDebtStatus[] = [];
275
+ for (let i = 0; i < res.length; i++) {
276
+ const r: any = (res as any[])[i];
277
+ if (r.status !== "success") {
278
+ throw new Error(`Liquidator checkBadDebt multicall failed: ${String(r.error ?? "unknown")}`);
279
+ }
280
+ out.push(normalizeBadDebtStatus(r.result, params.users[i]!));
281
+ }
282
+ return out;
200
283
  }
201
284
 
202
285
  type MergeLiquidatorLike = LiquidatorLike & {