@varla/sdk 1.11.1 → 1.11.3

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 CHANGED
@@ -19,3 +19,171 @@ Published package: **@varla/sdk**
19
19
  - Actions: `@varla/sdk/actions`
20
20
  - Events/indexer: `@varla/sdk/events`
21
21
  - Utilities: `@varla/sdk/batch`, `@varla/sdk/format`
22
+
23
+ ---
24
+
25
+ ## Frontend-oriented view helpers (quick map)
26
+
27
+ > Tip: prefer **subpath imports** so it’s obvious what you’re using:
28
+ >
29
+ > ```ts
30
+ > import * as views from "@varla/sdk/views";
31
+ > import * as actions from "@varla/sdk/actions";
32
+ > ```
33
+
34
+ ### Lend page (pool / lenders)
35
+
36
+ - **User supplied amount (current value)** + shares + withdrawable
37
+ - `views.readLenderSnapshot({ pool, user })` →
38
+ `{ shares, assets, maxWithdrawAssets, maxRedeemShares }`
39
+ - Notes:
40
+ - `assets` is the **current underlying value** of the user’s ERC4626 shares (principal + interest).
41
+ - `maxWithdrawAssets` is the **available-to-withdraw right now** (liquidity + reserve aware).
42
+
43
+ - **Available-to-withdraw only**
44
+ - `views.readMaxWithdraw({ pool, user })` → `{ maxWithdrawAssets }`
45
+
46
+ - **Pool share price (assets per share)**
47
+ - `views.readPoolSharePrice({ pool })` → `{ assetsPerShareWad }`
48
+
49
+ - **Pool utilization + rates**
50
+ - `views.readPoolSnapshot({ pool })` or `views.readPoolRates({ pool })`
51
+
52
+ - **Pool safety score**
53
+ - `views.readPoolHealthScore({ pool })` →
54
+ - `{ kind: "no-liquidity" }` when the pool has 0 assets (prevents showing a misleading 100)
55
+ - `{ kind: "ok", utilizationWad, scoreBps }` otherwise
56
+
57
+ ### Borrow page (core / borrower risk)
58
+
59
+ - **Account overview (portfolio, debt, HF, max borrow)**
60
+ - `views.readAccountSnapshot({ core, user })`
61
+ - or `views.readBorrowLimits({ core, user })` when you only need limits + HF
62
+
63
+ - **Max LTV vs tier naming (avoid ambiguity)**
64
+ - `views.readTieredLtvConfig({ core })` → `{ tier0, tier1, tier2 }` (maps 1:1 to CONSERVATIVE/MODERATE/RISK)
65
+ - For an actual position, prefer effective LTV:
66
+ - `views.readLtvForPosition({ core, positionId })` → `{ ltvWad }`
67
+
68
+ - **Liquidation threshold / params**
69
+ - `views.readHealthFactor({ core, user })` → `{ healthFactor, canBeLiquidated }`
70
+ - `views.readLiquidationConfig({ core })` and `views.readTierLiquidationConfig({ core, tier })`
71
+
72
+ ### Home page / “Top opportunities” (suggested inputs)
73
+
74
+ The SDK can provide raw primitives; **ranking is app-side**:
75
+ - `views.readPoolRates({ pool })` (supplyAPY, utilization)
76
+ - `views.readPoolCaps({ pool })` (capacity constraints)
77
+ - `views.readPoolHealthScore({ pool })` (simple risk signal)
78
+
79
+ ---
80
+
81
+ ## Not provided by the SDK (by design)
82
+
83
+ - **“Interest accrued / lender earnings” for a user**
84
+ - ERC4626 does not track principal per-user.
85
+ - To show “interest accrued”, you need a cost basis, e.g.:
86
+ - app-side tracking of deposits/withdrawals, or
87
+ - an indexer that reconstructs deposits/withdrawals from events.
88
+
89
+ - **Borrow “net rate”**
90
+ - `borrowRate` and pool `supplyAPY` are available, but “net” is product-specific
91
+ (depends on whether you consider collateral yield, whether user is also a lender, etc.).
92
+
93
+ - **Cooldown period**
94
+ - As of `contracts/VarlaPool.sol` in this repo, there is **no cooldown / withdraw delay** view.
95
+ - If a cooldown is introduced later, we can add `views.readPoolConfig({ pool })`.
96
+
97
+ ---
98
+
99
+ ## All view helpers (generated)
100
+
101
+ <!-- BEGIN GENERATED:VIEW_HELPERS -->
102
+ <!--
103
+ This section is auto-generated by scripts/sdk-generate-docs.ts.
104
+ Do not edit manually.
105
+ -->
106
+
107
+ - `getInterestRateStrategyFromPool`
108
+ - `hydrateOraclePositionIds`
109
+ - `previewBorrow`
110
+ - `previewRepay`
111
+ - `readAccessManagerBasics`
112
+ - `readAccountPositions`
113
+ - `readAccountPositionsFull`
114
+ - `readAccountSnapshot`
115
+ - `readAdapterInfo`
116
+ - `readBadDebtStatus`
117
+ - `readBorrowLimits`
118
+ - `readBorrowerState`
119
+ - `readBorrowers`
120
+ - `readBorrowersPage`
121
+ - `readCalculateLiquidationBonus`
122
+ - `readCanLiquidate`
123
+ - `readConfiguredPositionIds`
124
+ - `readConvertLiquidatorBasics`
125
+ - `readCoreAddresses`
126
+ - `readCoreGlobalDebt`
127
+ - `readDefaultLtvConfig`
128
+ - `readHasRole`
129
+ - `readHealthFactor`
130
+ - `readInterestRateStrategyBasics`
131
+ - `readLenderSnapshot`
132
+ - `readLiquidationBonusBps`
133
+ - `readLiquidationConfig`
134
+ - `readLiquidationParamsForPosition`
135
+ - `readLiquidatorBasics`
136
+ - `readLiquidity`
137
+ - `readLtvForPosition`
138
+ - `readManyAccountSnapshots`
139
+ - `readManyBorrowLimits`
140
+ - `readManyHasRole`
141
+ - `readManyLiquidationBonusBps`
142
+ - `readManyOraclePositionMeta`
143
+ - `readManyPositionSnapshots`
144
+ - `readManyTargetConfigs`
145
+ - `readManyTargetFunctionRoles`
146
+ - `readMaxPositionsConfig`
147
+ - `readMaxRedeem`
148
+ - `readMaxWithdraw`
149
+ - `readMergeLiquidatorBasics`
150
+ - `readNegRiskMarketPositionIds`
151
+ - `readOracleBasics`
152
+ - `readOracleCollateralStatus`
153
+ - `readOracleConfig`
154
+ - `readOracleFinalizationStatus`
155
+ - `readOracleGuardsStatus`
156
+ - `readOraclePositionMeta`
157
+ - `readOraclePriceData`
158
+ - `readOracleRegistry`
159
+ - `readOracleRegistryPage`
160
+ - `readOracleTiming`
161
+ - `readPoolAccounting`
162
+ - `readPoolCaps`
163
+ - `readPoolCoreAddress`
164
+ - `readPoolDebtState`
165
+ - `readPoolHealthScore`
166
+ - `readPoolRates`
167
+ - `readPoolSharePrice`
168
+ - `readPoolSnapshot`
169
+ - `readPortfolioValue`
170
+ - `readPositionBalance`
171
+ - `readPositionBalances`
172
+ - `readPositionCount`
173
+ - `readPositionLiquidationConfigOverride`
174
+ - `readPositionLtvOverride`
175
+ - `readPositionSnapshot`
176
+ - `readPreviewLiquidation`
177
+ - `readPrice`
178
+ - `readProxyAdminPaused`
179
+ - `readRepayTiming`
180
+ - `readRiskTier`
181
+ - `readRoleSummary`
182
+ - `readSpotPrice`
183
+ - `readSystemSnapshot`
184
+ - `readTargetConfig`
185
+ - `readTierLiquidationConfig`
186
+ - `readTieredLtvConfig`
187
+ - `readTryGetPrice`
188
+ - `readTwap`
189
+ <!-- END GENERATED:VIEW_HELPERS -->
package/BACKEND.md CHANGED
@@ -308,3 +308,97 @@ Useful health signals to emit from a backend:
308
308
  - Treat RPC errors as expected: implement retry/backoff and fallbacks.
309
309
  - Keep multicalls bounded (chunking) to avoid RPC provider limits.
310
310
 
311
+ ---
312
+
313
+ ## All view helpers (generated)
314
+
315
+ <!-- BEGIN GENERATED:VIEW_HELPERS -->
316
+ <!--
317
+ This section is auto-generated by scripts/sdk-generate-docs.ts.
318
+ Do not edit manually.
319
+ -->
320
+
321
+ - `getInterestRateStrategyFromPool`
322
+ - `hydrateOraclePositionIds`
323
+ - `previewBorrow`
324
+ - `previewRepay`
325
+ - `readAccessManagerBasics`
326
+ - `readAccountPositions`
327
+ - `readAccountPositionsFull`
328
+ - `readAccountSnapshot`
329
+ - `readAdapterInfo`
330
+ - `readBadDebtStatus`
331
+ - `readBorrowLimits`
332
+ - `readBorrowerState`
333
+ - `readBorrowers`
334
+ - `readBorrowersPage`
335
+ - `readCalculateLiquidationBonus`
336
+ - `readCanLiquidate`
337
+ - `readConfiguredPositionIds`
338
+ - `readConvertLiquidatorBasics`
339
+ - `readCoreAddresses`
340
+ - `readCoreGlobalDebt`
341
+ - `readDefaultLtvConfig`
342
+ - `readHasRole`
343
+ - `readHealthFactor`
344
+ - `readInterestRateStrategyBasics`
345
+ - `readLenderSnapshot`
346
+ - `readLiquidationBonusBps`
347
+ - `readLiquidationConfig`
348
+ - `readLiquidationParamsForPosition`
349
+ - `readLiquidatorBasics`
350
+ - `readLiquidity`
351
+ - `readLtvForPosition`
352
+ - `readManyAccountSnapshots`
353
+ - `readManyBorrowLimits`
354
+ - `readManyHasRole`
355
+ - `readManyLiquidationBonusBps`
356
+ - `readManyOraclePositionMeta`
357
+ - `readManyPositionSnapshots`
358
+ - `readManyTargetConfigs`
359
+ - `readManyTargetFunctionRoles`
360
+ - `readMaxPositionsConfig`
361
+ - `readMaxRedeem`
362
+ - `readMaxWithdraw`
363
+ - `readMergeLiquidatorBasics`
364
+ - `readNegRiskMarketPositionIds`
365
+ - `readOracleBasics`
366
+ - `readOracleCollateralStatus`
367
+ - `readOracleConfig`
368
+ - `readOracleFinalizationStatus`
369
+ - `readOracleGuardsStatus`
370
+ - `readOraclePositionMeta`
371
+ - `readOraclePriceData`
372
+ - `readOracleRegistry`
373
+ - `readOracleRegistryPage`
374
+ - `readOracleTiming`
375
+ - `readPoolAccounting`
376
+ - `readPoolCaps`
377
+ - `readPoolCoreAddress`
378
+ - `readPoolDebtState`
379
+ - `readPoolHealthScore`
380
+ - `readPoolRates`
381
+ - `readPoolSharePrice`
382
+ - `readPoolSnapshot`
383
+ - `readPortfolioValue`
384
+ - `readPositionBalance`
385
+ - `readPositionBalances`
386
+ - `readPositionCount`
387
+ - `readPositionLiquidationConfigOverride`
388
+ - `readPositionLtvOverride`
389
+ - `readPositionSnapshot`
390
+ - `readPreviewLiquidation`
391
+ - `readPrice`
392
+ - `readProxyAdminPaused`
393
+ - `readRepayTiming`
394
+ - `readRiskTier`
395
+ - `readRoleSummary`
396
+ - `readSpotPrice`
397
+ - `readSystemSnapshot`
398
+ - `readTargetConfig`
399
+ - `readTierLiquidationConfig`
400
+ - `readTieredLtvConfig`
401
+ - `readTryGetPrice`
402
+ - `readTwap`
403
+ <!-- END GENERATED:VIEW_HELPERS -->
404
+
package/FRONTEND.md CHANGED
@@ -98,6 +98,144 @@ const snap = await views.readAccountSnapshot({
98
98
 
99
99
  ---
100
100
 
101
+ ## 3.1) Lend page cookbook (pool / lenders)
102
+
103
+ > Recommended imports:
104
+ >
105
+ > ```ts
106
+ > import * as views from "@varla/sdk/views";
107
+ > ```
108
+
109
+ ### User supplied amount (current value)
110
+
111
+ Use `readLenderSnapshot`:
112
+
113
+ ```ts
114
+ const lender = await views.readLenderSnapshot({ pool: c.pool, user: userAddress });
115
+
116
+ // lender.assets is the current underlying value of the user’s ERC4626 shares
117
+ // (principal + interest), *not* a tracked principal amount.
118
+ ```
119
+
120
+ Return shape:
121
+ - `shares`: ERC4626 vault share balance
122
+ - `assets`: `convertToAssets(shares)` (current redeemable underlying)
123
+
124
+ ### Available to withdraw (overview chart)
125
+
126
+ If you only need withdrawable amount:
127
+
128
+ ```ts
129
+ const { maxWithdrawAssets } = await views.readMaxWithdraw({ pool: c.pool, user: userAddress });
130
+ ```
131
+
132
+ Or use `readLenderSnapshot` and read `maxWithdrawAssets`.
133
+
134
+ ### Pool share price (charting)
135
+
136
+ ```ts
137
+ const { assetsPerShareWad } = await views.readPoolSharePrice({ pool: c.pool });
138
+ ```
139
+
140
+ ### Pool rates + utilization
141
+
142
+ ```ts
143
+ const poolRates = await views.readPoolRates({ pool: c.pool });
144
+ // { utilization, borrowRate, supplyAPY, availableLiquidity, maxBorrow }
145
+ ```
146
+
147
+ ### Lender earnings / “interest accrued”
148
+
149
+ The SDK does **not** currently provide `readLenderEarnings(pool, user)`.
150
+
151
+ Reason: ERC4626 does not store a per-user principal (cost basis), so “interest accrued”
152
+ cannot be derived purely from the vault without historical data.
153
+
154
+ Recommended approach:
155
+ - Track deposits/withdrawals in your app (or an indexer) to build a cost basis.
156
+ - Compute earnings as (example):
157
+ - `earnings = currentAssets - (sumDeposits - sumWithdrawals)`
158
+
159
+ ---
160
+
161
+ ## 3.2) Borrow page cookbook (core / borrower risk)
162
+
163
+ ### Account overview
164
+
165
+ ```ts
166
+ const snap = await views.readAccountSnapshot({ core: c.core, user: userAddress });
167
+ // { portfolioValue, collateralValue, debt, healthFactor, maxBorrow }
168
+ ```
169
+
170
+ ### Max LTV clarification (defaults vs effective)
171
+
172
+ The protocol exposes **default LTV per risk tier**:
173
+
174
+ ```ts
175
+ const tiers = await views.readTieredLtvConfig({ core: c.core });
176
+ // { tier0, tier1, tier2 } == { conservative, moderate, risk }
177
+ ```
178
+
179
+ Important: `tier2`/`risk` is **not universally “the max LTV”**; it’s the default
180
+ for the tier-2 risk category.
181
+
182
+ For a specific collateral position, prefer the **effective** LTV:
183
+
184
+ ```ts
185
+ const { ltvWad } = await views.readLtvForPosition({ core: c.core, positionId });
186
+ ```
187
+
188
+ ### Liquidation threshold
189
+
190
+ Liquidation eligibility is best represented by health factor:
191
+
192
+ ```ts
193
+ const hf = await views.readHealthFactor({ core: c.core, user: userAddress });
194
+ // { healthFactor, canBeLiquidated }
195
+ ```
196
+
197
+ For parameters behind liquidation incentives/fees:
198
+
199
+ ```ts
200
+ const liq = await views.readLiquidationConfig({ core: c.core });
201
+ const liqTier0 = await views.readTierLiquidationConfig({ core: c.core, tier: 0 });
202
+ ```
203
+
204
+ ---
205
+
206
+ ## 3.3) Pool safety score (lend page)
207
+
208
+ If your UI currently does:
209
+ `(1 - utilization) * 100`, it will misleadingly show **100** when the pool has no liquidity.
210
+
211
+ Prefer the SDK helper:
212
+
213
+ ```ts
214
+ const score = await views.readPoolHealthScore({ pool: c.pool });
215
+
216
+ if (score.kind === "no-liquidity") {
217
+ // show "N/A" or "—"
218
+ } else {
219
+ // score.scoreBps is 0..10_000
220
+ }
221
+ ```
222
+
223
+ Current formula used by the SDK:
224
+ - if `totalAssets == 0` → `{ kind: "no-liquidity" }`
225
+ - else `scoreBps = (1 - utilizationWad) * 10_000` (clamped to [0..10_000])
226
+
227
+ ---
228
+
229
+ ## 3.4) Home page “top opportunities”
230
+
231
+ The SDK provides primitives, but **ranking is app-side**:
232
+
233
+ - `views.readPoolRates({ pool })` (supply APY, utilization)
234
+ - `views.readPoolCaps({ pool })` (capacity constraints)
235
+ - `views.readPoolHealthScore({ pool })` (simple risk signal)
236
+
237
+ ---
238
+
101
239
  ## 4) Writes (simulate-first) with wagmi
102
240
 
103
241
  The SDK write helpers return simulated requests; **you send them with your wallet client**.
@@ -250,3 +388,97 @@ This keeps UI components clean, and gives you one place to wire:
250
388
  - analytics
251
389
  - receipt confirmations
252
390
  - error mapping
391
+
392
+ ---
393
+
394
+ ## All view helpers (generated)
395
+
396
+ <!-- BEGIN GENERATED:VIEW_HELPERS -->
397
+ <!--
398
+ This section is auto-generated by scripts/sdk-generate-docs.ts.
399
+ Do not edit manually.
400
+ -->
401
+
402
+ - `getInterestRateStrategyFromPool`
403
+ - `hydrateOraclePositionIds`
404
+ - `previewBorrow`
405
+ - `previewRepay`
406
+ - `readAccessManagerBasics`
407
+ - `readAccountPositions`
408
+ - `readAccountPositionsFull`
409
+ - `readAccountSnapshot`
410
+ - `readAdapterInfo`
411
+ - `readBadDebtStatus`
412
+ - `readBorrowLimits`
413
+ - `readBorrowerState`
414
+ - `readBorrowers`
415
+ - `readBorrowersPage`
416
+ - `readCalculateLiquidationBonus`
417
+ - `readCanLiquidate`
418
+ - `readConfiguredPositionIds`
419
+ - `readConvertLiquidatorBasics`
420
+ - `readCoreAddresses`
421
+ - `readCoreGlobalDebt`
422
+ - `readDefaultLtvConfig`
423
+ - `readHasRole`
424
+ - `readHealthFactor`
425
+ - `readInterestRateStrategyBasics`
426
+ - `readLenderSnapshot`
427
+ - `readLiquidationBonusBps`
428
+ - `readLiquidationConfig`
429
+ - `readLiquidationParamsForPosition`
430
+ - `readLiquidatorBasics`
431
+ - `readLiquidity`
432
+ - `readLtvForPosition`
433
+ - `readManyAccountSnapshots`
434
+ - `readManyBorrowLimits`
435
+ - `readManyHasRole`
436
+ - `readManyLiquidationBonusBps`
437
+ - `readManyOraclePositionMeta`
438
+ - `readManyPositionSnapshots`
439
+ - `readManyTargetConfigs`
440
+ - `readManyTargetFunctionRoles`
441
+ - `readMaxPositionsConfig`
442
+ - `readMaxRedeem`
443
+ - `readMaxWithdraw`
444
+ - `readMergeLiquidatorBasics`
445
+ - `readNegRiskMarketPositionIds`
446
+ - `readOracleBasics`
447
+ - `readOracleCollateralStatus`
448
+ - `readOracleConfig`
449
+ - `readOracleFinalizationStatus`
450
+ - `readOracleGuardsStatus`
451
+ - `readOraclePositionMeta`
452
+ - `readOraclePriceData`
453
+ - `readOracleRegistry`
454
+ - `readOracleRegistryPage`
455
+ - `readOracleTiming`
456
+ - `readPoolAccounting`
457
+ - `readPoolCaps`
458
+ - `readPoolCoreAddress`
459
+ - `readPoolDebtState`
460
+ - `readPoolHealthScore`
461
+ - `readPoolRates`
462
+ - `readPoolSharePrice`
463
+ - `readPoolSnapshot`
464
+ - `readPortfolioValue`
465
+ - `readPositionBalance`
466
+ - `readPositionBalances`
467
+ - `readPositionCount`
468
+ - `readPositionLiquidationConfigOverride`
469
+ - `readPositionLtvOverride`
470
+ - `readPositionSnapshot`
471
+ - `readPreviewLiquidation`
472
+ - `readPrice`
473
+ - `readProxyAdminPaused`
474
+ - `readRepayTiming`
475
+ - `readRiskTier`
476
+ - `readRoleSummary`
477
+ - `readSpotPrice`
478
+ - `readSystemSnapshot`
479
+ - `readTargetConfig`
480
+ - `readTierLiquidationConfig`
481
+ - `readTieredLtvConfig`
482
+ - `readTryGetPrice`
483
+ - `readTwap`
484
+ <!-- END GENERATED:VIEW_HELPERS -->
@@ -1,4 +1,4 @@
1
- import type { Address, Hash } from "viem";
1
+ import type { Address, Hash, Hex } from "viem";
2
2
  /**
3
3
  * EIP-712 payload builder for OracleUpdaterRouter.
4
4
  *
@@ -51,6 +51,16 @@ export declare const ORACLE_UPDATER_ROUTER_TYPES: {
51
51
  readonly type: "bytes32";
52
52
  }];
53
53
  };
54
+ /**
55
+ * Hardcoded UPDATE_TYPEHASH from the deployed OracleUpdaterRouter contract.
56
+ *
57
+ * Computed from:
58
+ * keccak256("Update(address oracle,uint256 chainId,address publisher,uint256 nonce,uint256 deadline,bytes32 positionIdsHash,bytes32 priceListHash,bytes32 twapListHash,bytes32 liquidityListHash)")
59
+ *
60
+ * IMPORTANT: This must match the contract's hardcoded UPDATE_TYPEHASH exactly.
61
+ * If the contract is redeployed with a different type hash, this must be updated.
62
+ */
63
+ export declare const UPDATE_TYPEHASH: Hash;
54
64
  /**
55
65
  * Convert an update with dynamic arrays into the typed-data "message" shape expected by the router.
56
66
  */
@@ -65,9 +75,21 @@ export declare function toOracleUpdaterRouterTypedMessage(u: OracleUpdaterRouter
65
75
  readonly twapListHash: `0x${string}`;
66
76
  readonly liquidityListHash: `0x${string}`;
67
77
  };
78
+ /**
79
+ * Compute the EIP-712 digest that should be signed.
80
+ * This manually computes the digest to ensure exact match with the contract's hashUpdate().
81
+ */
82
+ export declare function computeOracleUpdaterDigest(params: {
83
+ routerAddress: Address;
84
+ update: OracleUpdaterRouterUpdate;
85
+ }): Hash;
68
86
  export declare function signOracleUpdaterRouterUpdate(params: {
69
87
  walletClient: {
70
- signTypedData: (args: any) => Promise<Hash>;
88
+ signMessage: (args: {
89
+ message: {
90
+ raw: Hex;
91
+ };
92
+ }) => Promise<Hash>;
71
93
  };
72
94
  routerAddress: Address;
73
95
  update: OracleUpdaterRouterUpdate;
@@ -1 +1 @@
1
- {"version":3,"file":"oracleUpdaterRouter.d.ts","sourceRoot":"","sources":["../../src/actions/oracleUpdaterRouter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK1C;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B;;;CAG/B,CAAC;AAEX,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY9B,CAAC;AAUX;;GAEG;AACH,wBAAgB,iCAAiC,CAAC,CAAC,EAAE,yBAAyB;;;;;;;;;;EAY7E;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,YAAY,EAAE;QACZ,aAAa,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAC7C,CAAC;IACF,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,yBAAyB,CAAC;CACnC,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhB;AAED,wBAAsB,6CAA6C,CAAC,MAAM,EAAE;IAC1E,YAAY,EAAE;QAAE,gBAAgB,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;KAAE,CAAC;IAChE,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,yBAAyB,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC;CACjB,GAAG,OAAO,CAAC,GAAG,CAAC,CAqBf"}
1
+ {"version":3,"file":"oracleUpdaterRouter.d.ts","sourceRoot":"","sources":["../../src/actions/oracleUpdaterRouter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAK/C;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B;;;CAG/B,CAAC;AAEX,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY9B,CAAC;AAEX;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,EAAE,IACwC,CAAC;AAuBvE;;GAEG;AACH,wBAAgB,iCAAiC,CAAC,CAAC,EAAE,yBAAyB;;;;;;;;;;EAY7E;AA+DD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,yBAAyB,CAAC;CACnC,GAAG,IAAI,CAMP;AAED,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,YAAY,EAAE;QACZ,WAAW,EAAE,CAAC,IAAI,EAAE;YAAE,OAAO,EAAE;gBAAE,GAAG,EAAE,GAAG,CAAA;aAAE,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACjE,CAAC;IACF,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,yBAAyB,CAAC;CACnC,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhB;AAED,wBAAsB,6CAA6C,CAAC,MAAM,EAAE;IAC1E,YAAY,EAAE;QAAE,gBAAgB,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;KAAE,CAAC;IAChE,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,yBAAyB,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC;CACjB,GAAG,OAAO,CAAC,GAAG,CAAC,CAqBf"}
@@ -1,5 +1,5 @@
1
1
  // Note: explicit .js extension is required for Node ESM resolution.
2
- import { encodeAbiParameters, keccak256 } from "viem";
2
+ import { concat, encodeAbiParameters, encodePacked, keccak256, toHex } from "viem";
3
3
  import { abis } from "../generated.js";
4
4
  /**
5
5
  * EIP-712 payload builder for OracleUpdaterRouter.
@@ -25,13 +25,31 @@ export const ORACLE_UPDATER_ROUTER_TYPES = {
25
25
  { name: "liquidityListHash", type: "bytes32" },
26
26
  ],
27
27
  };
28
+ /**
29
+ * Hardcoded UPDATE_TYPEHASH from the deployed OracleUpdaterRouter contract.
30
+ *
31
+ * Computed from:
32
+ * keccak256("Update(address oracle,uint256 chainId,address publisher,uint256 nonce,uint256 deadline,bytes32 positionIdsHash,bytes32 priceListHash,bytes32 twapListHash,bytes32 liquidityListHash)")
33
+ *
34
+ * IMPORTANT: This must match the contract's hardcoded UPDATE_TYPEHASH exactly.
35
+ * If the contract is redeployed with a different type hash, this must be updated.
36
+ */
37
+ export const UPDATE_TYPEHASH = "0xfb5c9ee2f30c92eeb6fe0049d8ba63d98fcbb57cccd2761e2fd7275ac1bd9bd0";
38
+ /**
39
+ * Hardcoded EIP712Domain type hash.
40
+ * keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
41
+ */
42
+ const EIP712_DOMAIN_TYPEHASH = "0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f";
43
+ /**
44
+ * Hash a uint256[] array using Solidity's abi.encodePacked semantics.
45
+ * Matches: keccak256(abi.encodePacked(uint256[]))
46
+ */
28
47
  function hashU256Array(xs) {
29
- // Solidity uses keccak256(abi.encodePacked(uint256[])) for the struct hash.
30
- // abi.encodePacked(uint256[]) is just tight packing of each uint256 as 32 bytes.
31
48
  if (xs.length === 0)
32
49
  return keccak256(new Uint8Array([]));
33
- const bytes = encodeAbiParameters(Array(xs.length).fill({ type: "uint256" }), xs);
34
- return keccak256(bytes);
50
+ // abi.encodePacked(uint256[]) is just tight packing of each uint256 as 32 bytes
51
+ const packed = encodePacked(xs.map(() => "uint256"), xs);
52
+ return keccak256(packed);
35
53
  }
36
54
  /**
37
55
  * Convert an update with dynamic arrays into the typed-data "message" shape expected by the router.
@@ -49,18 +67,74 @@ export function toOracleUpdaterRouterTypedMessage(u) {
49
67
  liquidityListHash: hashU256Array(u.liquidityList),
50
68
  };
51
69
  }
70
+ /**
71
+ * Compute the EIP-712 domain separator for the OracleUpdaterRouter.
72
+ */
73
+ function computeDomainSeparator(chainId, routerAddress) {
74
+ return keccak256(encodeAbiParameters([
75
+ { type: "bytes32" },
76
+ { type: "bytes32" },
77
+ { type: "bytes32" },
78
+ { type: "uint256" },
79
+ { type: "address" },
80
+ ], [
81
+ EIP712_DOMAIN_TYPEHASH,
82
+ keccak256(toHex(ORACLE_UPDATER_ROUTER_EIP712.name)),
83
+ keccak256(toHex(ORACLE_UPDATER_ROUTER_EIP712.version)),
84
+ chainId,
85
+ routerAddress,
86
+ ]));
87
+ }
88
+ /**
89
+ * Compute the struct hash for an Update using the contract's exact UPDATE_TYPEHASH.
90
+ * This bypasses viem's automatic type hash computation to ensure exact match with the contract.
91
+ */
92
+ function computeStructHash(update) {
93
+ const msg = toOracleUpdaterRouterTypedMessage(update);
94
+ return keccak256(encodeAbiParameters([
95
+ { type: "bytes32" }, // UPDATE_TYPEHASH
96
+ { type: "address" }, // oracle
97
+ { type: "uint256" }, // chainId
98
+ { type: "address" }, // publisher
99
+ { type: "uint256" }, // nonce
100
+ { type: "uint256" }, // deadline
101
+ { type: "bytes32" }, // positionIdsHash
102
+ { type: "bytes32" }, // priceListHash
103
+ { type: "bytes32" }, // twapListHash
104
+ { type: "bytes32" }, // liquidityListHash
105
+ ], [
106
+ UPDATE_TYPEHASH,
107
+ msg.oracle,
108
+ msg.chainId,
109
+ msg.publisher,
110
+ msg.nonce,
111
+ msg.deadline,
112
+ msg.positionIdsHash,
113
+ msg.priceListHash,
114
+ msg.twapListHash,
115
+ msg.liquidityListHash,
116
+ ]));
117
+ }
118
+ /**
119
+ * Compute the EIP-712 digest that should be signed.
120
+ * This manually computes the digest to ensure exact match with the contract's hashUpdate().
121
+ */
122
+ export function computeOracleUpdaterDigest(params) {
123
+ const domainSeparator = computeDomainSeparator(params.update.chainId, params.routerAddress);
124
+ const structHash = computeStructHash(params.update);
125
+ // EIP-712: "\x19\x01" ++ domainSeparator ++ structHash
126
+ return keccak256(concat(["0x1901", domainSeparator, structHash]));
127
+ }
52
128
  export async function signOracleUpdaterRouterUpdate(params) {
53
- return (await params.walletClient.signTypedData({
54
- domain: {
55
- name: ORACLE_UPDATER_ROUTER_EIP712.name,
56
- version: ORACLE_UPDATER_ROUTER_EIP712.version,
57
- chainId: params.update.chainId,
58
- verifyingContract: params.routerAddress,
59
- },
60
- primaryType: "Update",
61
- types: ORACLE_UPDATER_ROUTER_TYPES,
62
- message: toOracleUpdaterRouterTypedMessage(params.update),
63
- }));
129
+ // Manually compute the EIP-712 digest to ensure exact match with contract
130
+ const digest = computeOracleUpdaterDigest({
131
+ routerAddress: params.routerAddress,
132
+ update: params.update,
133
+ });
134
+ // Sign the raw digest (not a personal_sign, just the raw hash)
135
+ return params.walletClient.signMessage({
136
+ message: { raw: digest },
137
+ });
64
138
  }
65
139
  export async function prepareOracleUpdaterRouterUpdatePricesWithSig(params) {
66
140
  return await params.publicClient.simulateContract({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@varla/sdk",
3
- "version": "1.11.1",
3
+ "version": "1.11.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,