@varla/sdk 4.0.0 → 4.1.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.
@@ -492,6 +492,17 @@ export const VARLACORE_ABI = [
492
492
  "name": "TooManyPositions",
493
493
  "type": "error"
494
494
  },
495
+ {
496
+ "inputs": [
497
+ {
498
+ "internalType": "address",
499
+ "name": "token",
500
+ "type": "address"
501
+ }
502
+ ],
503
+ "name": "UnsupportedPositionsToken",
504
+ "type": "error"
505
+ },
495
506
  {
496
507
  "inputs": [],
497
508
  "name": "WouldBeUndercollateralized",
@@ -1168,34 +1179,6 @@ export const VARLACORE_ABI = [
1168
1179
  "stateMutability": "nonpayable",
1169
1180
  "type": "function"
1170
1181
  },
1171
- {
1172
- "inputs": [
1173
- {
1174
- "internalType": "uint256[]",
1175
- "name": "positionIds",
1176
- "type": "uint256[]"
1177
- },
1178
- {
1179
- "internalType": "uint256[]",
1180
- "name": "amounts",
1181
- "type": "uint256[]"
1182
- },
1183
- {
1184
- "internalType": "uint256",
1185
- "name": "borrowAmount",
1186
- "type": "uint256"
1187
- },
1188
- {
1189
- "internalType": "address",
1190
- "name": "outputAsset",
1191
- "type": "address"
1192
- }
1193
- ],
1194
- "name": "depositAndBorrow",
1195
- "outputs": [],
1196
- "stateMutability": "nonpayable",
1197
- "type": "function"
1198
- },
1199
1182
  {
1200
1183
  "inputs": [
1201
1184
  {
@@ -1280,25 +1263,6 @@ export const VARLACORE_ABI = [
1280
1263
  "stateMutability": "view",
1281
1264
  "type": "function"
1282
1265
  },
1283
- {
1284
- "inputs": [
1285
- {
1286
- "internalType": "address",
1287
- "name": "user",
1288
- "type": "address"
1289
- }
1290
- ],
1291
- "name": "getCollateralValue",
1292
- "outputs": [
1293
- {
1294
- "internalType": "uint256",
1295
- "name": "",
1296
- "type": "uint256"
1297
- }
1298
- ],
1299
- "stateMutability": "view",
1300
- "type": "function"
1301
- },
1302
1266
  {
1303
1267
  "inputs": [
1304
1268
  {
@@ -1546,25 +1510,6 @@ export const VARLACORE_ABI = [
1546
1510
  "stateMutability": "view",
1547
1511
  "type": "function"
1548
1512
  },
1549
- {
1550
- "inputs": [
1551
- {
1552
- "internalType": "address",
1553
- "name": "user",
1554
- "type": "address"
1555
- }
1556
- ],
1557
- "name": "getPortfolioValue",
1558
- "outputs": [
1559
- {
1560
- "internalType": "uint256",
1561
- "name": "",
1562
- "type": "uint256"
1563
- }
1564
- ],
1565
- "stateMutability": "view",
1566
- "type": "function"
1567
- },
1568
1513
  {
1569
1514
  "inputs": [
1570
1515
  {
@@ -1924,17 +1869,17 @@ export const VARLACORE_ABI = [
1924
1869
  },
1925
1870
  {
1926
1871
  "internalType": "address",
1927
- "name": "",
1872
+ "name": "from",
1928
1873
  "type": "address"
1929
1874
  },
1930
1875
  {
1931
1876
  "internalType": "uint256[]",
1932
- "name": "",
1877
+ "name": "ids",
1933
1878
  "type": "uint256[]"
1934
1879
  },
1935
1880
  {
1936
1881
  "internalType": "uint256[]",
1937
- "name": "",
1882
+ "name": "values",
1938
1883
  "type": "uint256[]"
1939
1884
  },
1940
1885
  {
@@ -1963,17 +1908,17 @@ export const VARLACORE_ABI = [
1963
1908
  },
1964
1909
  {
1965
1910
  "internalType": "address",
1966
- "name": "",
1911
+ "name": "from",
1967
1912
  "type": "address"
1968
1913
  },
1969
1914
  {
1970
1915
  "internalType": "uint256",
1971
- "name": "",
1916
+ "name": "id",
1972
1917
  "type": "uint256"
1973
1918
  },
1974
1919
  {
1975
1920
  "internalType": "uint256",
1976
- "name": "",
1921
+ "name": "value",
1977
1922
  "type": "uint256"
1978
1923
  },
1979
1924
  {
@@ -2371,6 +2316,29 @@ export const VARLACORE_ABI = [
2371
2316
  "stateMutability": "view",
2372
2317
  "type": "function"
2373
2318
  },
2319
+ {
2320
+ "inputs": [
2321
+ {
2322
+ "internalType": "uint256[]",
2323
+ "name": "positionIds",
2324
+ "type": "uint256[]"
2325
+ },
2326
+ {
2327
+ "internalType": "uint256[]",
2328
+ "name": "amounts",
2329
+ "type": "uint256[]"
2330
+ },
2331
+ {
2332
+ "internalType": "address",
2333
+ "name": "destination",
2334
+ "type": "address"
2335
+ }
2336
+ ],
2337
+ "name": "withdraw",
2338
+ "outputs": [],
2339
+ "stateMutability": "nonpayable",
2340
+ "type": "function"
2341
+ },
2374
2342
  {
2375
2343
  "inputs": [
2376
2344
  {
@@ -513,7 +513,7 @@ export const VARLALIQUIDATOR_ABI = [
513
513
  },
514
514
  {
515
515
  "internalType": "uint256",
516
- "name": "collateralValue",
516
+ "name": "portfolioValue",
517
517
  "type": "uint256"
518
518
  },
519
519
  {
@@ -23,18 +23,50 @@ export async function prepareCoreDeposit(params: {
23
23
  } as any)) as any;
24
24
  }
25
25
 
26
+ /**
27
+ * Withdraw deposited ERC1155 collateral from VarlaCore back to a wallet.
28
+ *
29
+ * Two call paths:
30
+ * - **No `recipient`** (default): calls `withdraw(ids, amounts)` — tokens sent to `msg.sender`.
31
+ * - **With `recipient`**: calls `withdraw(ids, amounts, destination)` — tokens sent to the
32
+ * specified address instead of the caller. Useful for Safe / proxy wallets or any flow
33
+ * where the signer and the token recipient differ.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * // Withdraw to self (default)
38
+ * const tx = await prepareCoreWithdraw({ publicClient, coreAddress, account, positionIds, amounts });
39
+ *
40
+ * // Withdraw to a different address
41
+ * const tx = await prepareCoreWithdraw({
42
+ * publicClient, coreAddress, account,
43
+ * positionIds, amounts,
44
+ * recipient: "0xAbc...",
45
+ * });
46
+ * ```
47
+ */
26
48
  export async function prepareCoreWithdraw(params: {
27
49
  publicClient: Pick<PublicClient, "simulateContract">;
28
50
  coreAddress: Address;
29
51
  account: Address;
30
52
  positionIds: readonly bigint[];
31
53
  amounts: readonly bigint[];
54
+ /**
55
+ * Optional destination address for the withdrawn ERC1155 tokens.
56
+ *
57
+ * When provided, calls `withdraw(positionIds, amounts, destination)`.
58
+ * When omitted, calls `withdraw(positionIds, amounts)` (tokens go to `msg.sender`).
59
+ */
60
+ recipient?: Address;
32
61
  }): Promise<SimulatedTx> {
33
62
  return (await params.publicClient.simulateContract({
34
63
  address: params.coreAddress,
35
64
  abi: abis.VARLACORE_ABI,
36
65
  functionName: "withdraw",
37
- args: [params.positionIds, params.amounts],
66
+ args:
67
+ params.recipient !== undefined
68
+ ? [params.positionIds, params.amounts, params.recipient]
69
+ : [params.positionIds, params.amounts],
38
70
  account: params.account,
39
71
  } as any)) as any;
40
72
  }
@@ -20,3 +20,99 @@ export async function prepareErc1155SetApprovalForAll(params: {
20
20
  account: params.account,
21
21
  } as any)) as any;
22
22
  }
23
+
24
+ /**
25
+ * Deposit a single ERC1155 position into VarlaCore by directly calling
26
+ * `ctf.safeTransferFrom(user, core, id, amount, "")`.
27
+ *
28
+ * This triggers VarlaCore's `onERC1155Received` hook which credits the
29
+ * sender (`from`) with the deposited amount — no prior `setApprovalForAll`
30
+ * to Core is required since the caller is initiating the transfer themselves.
31
+ *
32
+ * Use this as a drop-in alternative to `prepareCoreDeposit` when the user
33
+ * prefers the ERC1155-push pattern (e.g. in single-token flows or when
34
+ * building atomic Safe multisend batches where approval is undesirable).
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * import { prepareCoreDepositViaSafeTransfer } from "@varla/sdk/actions";
39
+ *
40
+ * const tx = await prepareCoreDepositViaSafeTransfer({
41
+ * publicClient,
42
+ * ctfAddress,
43
+ * coreAddress,
44
+ * account: userAddress,
45
+ * positionId: BigInt(posId),
46
+ * amount: 100_000_000n, // 100 USDC (6 decimals)
47
+ * });
48
+ * await walletClient.writeContract(tx.request);
49
+ * ```
50
+ */
51
+ export async function prepareCoreDepositViaSafeTransfer(params: {
52
+ publicClient: Pick<PublicClient, "simulateContract">;
53
+ /** Address of the ERC1155 positions token (Polymarket CTF). */
54
+ ctfAddress: Address;
55
+ /** Address of VarlaCore (the transfer recipient). */
56
+ coreAddress: Address;
57
+ account: Address;
58
+ positionId: bigint;
59
+ amount: bigint;
60
+ }): Promise<SimulatedTx> {
61
+ return (await params.publicClient.simulateContract({
62
+ address: params.ctfAddress,
63
+ abi: erc1155Abi,
64
+ functionName: "safeTransferFrom",
65
+ args: [params.account, params.coreAddress, params.positionId, params.amount, "0x"],
66
+ account: params.account,
67
+ } as any)) as any;
68
+ }
69
+
70
+ /**
71
+ * Deposit multiple ERC1155 positions into VarlaCore in a single call by using
72
+ * `ctf.safeBatchTransferFrom(user, core, ids, amounts, "")`.
73
+ *
74
+ * This triggers VarlaCore's `onERC1155BatchReceived` hook which credits the
75
+ * sender (`from`) with each transferred amount. No prior `setApprovalForAll`
76
+ * to Core is needed.
77
+ *
78
+ * Prefer this over multiple `prepareCoreDepositViaSafeTransfer` calls when
79
+ * depositing several positions atomically (single tx, lower gas).
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * import { prepareCoreDepositViaSafeBatchTransfer } from "@varla/sdk/actions";
84
+ *
85
+ * const tx = await prepareCoreDepositViaSafeBatchTransfer({
86
+ * publicClient,
87
+ * ctfAddress,
88
+ * coreAddress,
89
+ * account: userAddress,
90
+ * positionIds: [BigInt(yesId), BigInt(noId)],
91
+ * amounts: [50_000_000n, 50_000_000n],
92
+ * });
93
+ * await walletClient.writeContract(tx.request);
94
+ * ```
95
+ */
96
+ export async function prepareCoreDepositViaSafeBatchTransfer(params: {
97
+ publicClient: Pick<PublicClient, "simulateContract">;
98
+ /** Address of the ERC1155 positions token (Polymarket CTF). */
99
+ ctfAddress: Address;
100
+ /** Address of VarlaCore (the transfer recipient). */
101
+ coreAddress: Address;
102
+ account: Address;
103
+ positionIds: readonly bigint[];
104
+ amounts: readonly bigint[];
105
+ }): Promise<SimulatedTx> {
106
+ if (params.positionIds.length !== params.amounts.length) {
107
+ throw new Error(
108
+ `prepareCoreDepositViaSafeBatchTransfer: positionIds.length (${params.positionIds.length}) must equal amounts.length (${params.amounts.length})`,
109
+ );
110
+ }
111
+ return (await params.publicClient.simulateContract({
112
+ address: params.ctfAddress,
113
+ abi: erc1155Abi,
114
+ functionName: "safeBatchTransferFrom",
115
+ args: [params.account, params.coreAddress, params.positionIds, params.amounts, "0x"],
116
+ account: params.account,
117
+ } as any)) as any;
118
+ }
@@ -10,9 +10,9 @@
10
10
  "OracleUpdaterRouter": "0x3E1e6B54626D486b844C94e2385773b018fEB891",
11
11
  "VarlaInterestRateStrategy": "0x3Ae3a0B358a53aF835A924F4799c91943206e3d1",
12
12
  "VarlaProxyAdmin": "0x084aBfA2f32A53741DDd12D3166dA1318e7d73f7",
13
- "VarlaLiquidator": "0x0f031BFbfFB08C3f844b8e59BAd9975CBec194b5",
14
- "VarlaMergeLiquidator": "0x573A7bD3117c9D8EA1913c2Ccbdbf29E86EE4621",
15
- "VarlaConvertLiquidator": "0xc1ba05218Fb56b5e31D34b3bb772fa57F1eDC7e4",
13
+ "VarlaLiquidator": "0xB03baF8dA8608966C85b41Ef8ac6E8046E5A51e2",
14
+ "VarlaMergeLiquidator": "0xd7d3F588eE96bC4D8a4970762397fff22f05a768",
15
+ "VarlaConvertLiquidator": "0xA62aE4c47271afE15E2c7750c8Bd6c980657B147",
16
16
  "PolymarketCtfAdapter": "0x86B39800540D2C42eF1E34DF69117CB34F35a341"
17
17
  }
18
18
  }
@@ -9,9 +9,9 @@ export const polygonProxy: AddressBook = {
9
9
  oracleUpdaterRouter: "0x3E1e6B54626D486b844C94e2385773b018fEB891",
10
10
  interestRateStrategy: "0x3Ae3a0B358a53aF835A924F4799c91943206e3d1",
11
11
  proxyAdmin: "0x084aBfA2f32A53741DDd12D3166dA1318e7d73f7",
12
- liquidator: "0x0f031BFbfFB08C3f844b8e59BAd9975CBec194b5",
13
- mergeLiquidator: "0x573A7bD3117c9D8EA1913c2Ccbdbf29E86EE4621",
14
- convertLiquidator: "0xc1ba05218Fb56b5e31D34b3bb772fa57F1eDC7e4",
12
+ liquidator: "0xB03baF8dA8608966C85b41Ef8ac6E8046E5A51e2",
13
+ mergeLiquidator: "0xd7d3F588eE96bC4D8a4970762397fff22f05a768",
14
+ convertLiquidator: "0xA62aE4c47271afE15E2c7750c8Bd6c980657B147",
15
15
  polymarketCtfAdapter: "0x86B39800540D2C42eF1E34DF69117CB34F35a341",
16
16
  };
17
17
 
package/src/views/core.ts CHANGED
@@ -196,6 +196,150 @@ export async function previewCoreDeposit(params: {
196
196
  };
197
197
  }
198
198
 
199
+ // ---------------------------------------------------------------------------
200
+ // Withdraw pre-flight (previewCoreWithdraw)
201
+ // ---------------------------------------------------------------------------
202
+
203
+ /**
204
+ * Reason a collateral withdrawal would be rejected for a specific position.
205
+ *
206
+ * - `"zero-amount"` — caller passed `amount === 0n`.
207
+ * - `"insufficient-balance"` — user's deposited balance is below the requested amount.
208
+ */
209
+ export type WithdrawBlockReason = "zero-amount" | "insufficient-balance";
210
+
211
+ export type PreviewCoreWithdrawItem = {
212
+ positionId: bigint;
213
+ amount: bigint;
214
+ /** Current deposited balance of the user for this position. */
215
+ balance: bigint;
216
+ /** `true` when this position passes the pre-flight balance check. */
217
+ ok: boolean;
218
+ /** Present only when `ok === false`. */
219
+ reason?: WithdrawBlockReason;
220
+ };
221
+
222
+ export type PreviewCoreWithdraw = {
223
+ /**
224
+ * `true` only when every position passes the balance check AND the user either
225
+ * has no outstanding debt or has sufficient health factor to absorb the withdrawal.
226
+ *
227
+ * When `hasDeb === true`, always simulate the on-chain call or check HF separately
228
+ * before submitting — this preview cannot compute the exact post-withdraw HF
229
+ * without oracle price data.
230
+ */
231
+ canWithdraw: boolean;
232
+ /** Per-position results aligned to input order. */
233
+ items: PreviewCoreWithdrawItem[];
234
+ /** `true` when the user has any outstanding debt. Withdrawing while indebted
235
+ * may reduce the health factor below the liquidation threshold. */
236
+ hasDebt: boolean;
237
+ /** Current health factor (WAD). `0` when the user has no debt. */
238
+ healthFactor: bigint;
239
+ };
240
+
241
+ /**
242
+ * Pre-flight check that mirrors VarlaCore.withdraw() balance validation.
243
+ *
244
+ * Checks (per position):
245
+ * 1. `amount > 0`
246
+ * 2. `core.positionBalances(user, id) >= amount`
247
+ *
248
+ * Account-level:
249
+ * - Whether the user currently has debt (`debt > 0`).
250
+ *
251
+ * **Important**: this function cannot predict the post-withdraw health factor
252
+ * without live oracle prices. When `hasDebt === true`, always double-check
253
+ * the HF with `readHealthFactor` or simulate the transaction before submitting.
254
+ *
255
+ * @example
256
+ * ```ts
257
+ * import { previewCoreWithdraw } from "@varla/sdk/views";
258
+ *
259
+ * const preview = await previewCoreWithdraw({
260
+ * core,
261
+ * user: "0x...",
262
+ * positionIds: [yesId],
263
+ * amounts: [50_000_000n],
264
+ * });
265
+ *
266
+ * if (!preview.canWithdraw) {
267
+ * for (const item of preview.items) {
268
+ * if (!item.ok) console.log(`Position ${item.positionId}: ${item.reason}`);
269
+ * }
270
+ * if (preview.hasDebt) console.log("User has debt — check HF before withdrawing");
271
+ * }
272
+ * ```
273
+ */
274
+ // wraps: VarlaCore.positionBalances,VarlaCore.getDebt,VarlaCore.getHealthFactor
275
+ export async function previewCoreWithdraw(params: {
276
+ core: {
277
+ read: {
278
+ positionBalances: (args: readonly [Address, bigint]) => Promise<bigint>;
279
+ getDebt: (args: readonly [Address]) => Promise<bigint>;
280
+ getHealthFactor: (args: readonly [Address]) => Promise<unknown>;
281
+ };
282
+ };
283
+ user: Address;
284
+ positionIds: readonly bigint[];
285
+ amounts: readonly bigint[];
286
+ }): Promise<PreviewCoreWithdraw> {
287
+ const { core, user, positionIds, amounts } = params;
288
+
289
+ if (positionIds.length !== amounts.length) {
290
+ throw new Error("previewCoreWithdraw: positionIds and amounts must have the same length");
291
+ }
292
+
293
+ // Fetch all balances and account debt in parallel.
294
+ const [balances, debt, hfRaw] = await Promise.all([
295
+ Promise.all(positionIds.map((pid) => core.read.positionBalances([user, pid]))),
296
+ core.read.getDebt([user]),
297
+ core.read.getHealthFactor([user]),
298
+ ]);
299
+
300
+ // Extract health factor from the tuple returned by VarlaCore.getHealthFactor.
301
+ const hfAny = hfRaw as any;
302
+ const healthFactor: bigint =
303
+ typeof hfAny === "bigint"
304
+ ? hfAny
305
+ : typeof hfAny?.healthFactor === "bigint"
306
+ ? hfAny.healthFactor
307
+ : (hfAny?.[0] ?? 0n);
308
+
309
+ // Per-position checks.
310
+ const items: PreviewCoreWithdrawItem[] = [];
311
+ let allItemsOk = true;
312
+
313
+ for (let i = 0; i < positionIds.length; i++) {
314
+ const pid = positionIds[i]!;
315
+ const amount = amounts[i]!;
316
+ const balance = balances[i]!;
317
+
318
+ let ok = true;
319
+ let reason: WithdrawBlockReason | undefined;
320
+
321
+ if (amount === 0n) {
322
+ ok = false;
323
+ reason = "zero-amount";
324
+ } else if (balance < amount) {
325
+ ok = false;
326
+ reason = "insufficient-balance";
327
+ }
328
+
329
+ if (!ok) allItemsOk = false;
330
+ items.push(
331
+ reason !== undefined
332
+ ? { positionId: pid, amount, balance, ok, reason }
333
+ : { positionId: pid, amount, balance, ok },
334
+ );
335
+ }
336
+
337
+ const hasDebt = debt > 0n;
338
+ const canWithdraw = allItemsOk;
339
+
340
+ return { canWithdraw, items, hasDebt, healthFactor };
341
+ }
342
+
199
343
  export type ReadAccountSnapshot = {
200
344
  portfolioValue: bigint;
201
345
  collateralValue: bigint;
@@ -513,12 +657,18 @@ export async function readBorrowerState(params: {
513
657
  return { user: params.user, scaledDebt, isBorrower, isLiquidatable };
514
658
  }
515
659
 
516
- // wraps: VarlaCore.getPortfolioValue
660
+ // wraps: VarlaCore.getAccountSummary
517
661
  export async function readPortfolioValue(params: {
518
- core: { read: { getPortfolioValue: (args: readonly [Address]) => Promise<bigint> } };
662
+ core: {
663
+ read: {
664
+ getAccountSummary: (
665
+ args: readonly [Address],
666
+ ) => Promise<readonly [bigint, bigint, bigint, bigint, bigint]>;
667
+ };
668
+ };
519
669
  user: Address;
520
670
  }): Promise<ReadPortfolioValue> {
521
- const portfolioValue = await params.core.read.getPortfolioValue([params.user]);
671
+ const [portfolioValue] = await params.core.read.getAccountSummary([params.user]);
522
672
  return { user: params.user, portfolioValue };
523
673
  }
524
674