@owney/sdk 0.6.5 → 0.6.6-beta.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.
package/dist/index.js CHANGED
@@ -1,14 +1,21 @@
1
+ import {
2
+ AgentChainIncompatibleError,
3
+ AgentNotFoundError,
4
+ NotConnectedError,
5
+ OwneyError
6
+ } from "./chunk-GMNQBWUB.js";
7
+
1
8
  // src/agents/zyfai/zyfai.agent.ts
2
9
  import { ZyfaiSDK } from "@zyfai/sdk";
3
10
  import { createPublicClient, http } from "viem";
4
- import { base, arbitrum, mainnet } from "viem/chains";
11
+ import { base, arbitrum } from "viem/chains";
5
12
 
6
13
  // src/types/config.ts
7
14
  var P_SUPPORTED_CHAINS = {
8
- chainIds: [8453, 42161, 1],
9
- chains: ["BASE", "ARBITRUM", "ETHEREUM"]
15
+ chainIds: [8453, 42161],
16
+ chains: ["BASE", "ARBITRUM"]
10
17
  };
11
- var SUPPORTED_TOKENS = ["USDC", "USDT", "WETH"];
18
+ var SUPPORTED_TOKENS = ["USDC", "USDT"];
12
19
  var SUPPORTED_CHAIN_IDS = P_SUPPORTED_CHAINS.chainIds;
13
20
  var SUPPORTED_CHAINS = P_SUPPORTED_CHAINS.chains;
14
21
  var SupportedAssets = [
@@ -29,82 +36,9 @@ var SupportedAssets = [
29
36
  symbol: "USDT",
30
37
  chainId: 42161,
31
38
  decimals: 6
32
- },
33
- {
34
- address: `0x4200000000000000000000000000000000000006`,
35
- symbol: "WETH",
36
- chainId: 8453,
37
- decimals: 18
38
- },
39
- {
40
- address: `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1`,
41
- symbol: "WETH",
42
- chainId: 42161,
43
- decimals: 18
44
- },
45
- {
46
- address: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`,
47
- symbol: "USDC",
48
- chainId: 1,
49
- decimals: 6
50
- },
51
- {
52
- address: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`,
53
- symbol: "WETH",
54
- chainId: 1,
55
- decimals: 18
56
39
  }
57
40
  ];
58
41
 
59
- // src/errors.ts
60
- var OwneyError = class extends Error {
61
- code;
62
- details;
63
- agentId;
64
- constructor(code, message, details, agentId) {
65
- const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
66
- super(`${prefix} ${message}`);
67
- this.name = "OwneyError";
68
- this.code = code;
69
- this.details = details;
70
- this.agentId = agentId;
71
- }
72
- };
73
- var AgentNotFoundError = class extends OwneyError {
74
- constructor(agentId, available) {
75
- super(
76
- "AGENT_NOT_FOUND",
77
- `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
78
- { agentId, available },
79
- agentId
80
- );
81
- this.name = "AgentNotFoundError";
82
- }
83
- };
84
- var NotConnectedError = class extends OwneyError {
85
- constructor() {
86
- super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
87
- this.name = "NotConnectedError";
88
- }
89
- };
90
- var AgentChainIncompatibleError = class extends OwneyError {
91
- incompatibleAgents;
92
- connectedChainId;
93
- constructor(incompatibleAgents, connectedChainId) {
94
- const details = incompatibleAgents.map(
95
- ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
96
- ).join("; ");
97
- super(
98
- "AGENT_CHAIN_INCOMPATIBLE",
99
- `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
100
- { incompatibleAgents, connectedChainId }
101
- );
102
- this.name = "AgentChainIncompatibleError";
103
- this.incompatibleAgents = incompatibleAgents;
104
- this.connectedChainId = connectedChainId;
105
- }
106
- };
107
-
108
42
  // src/lib/utils.ts
109
43
  var isValidChainId = (chainId) => {
110
44
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
@@ -119,7 +53,8 @@ var isValidChainId = (chainId) => {
119
53
  function hexToDecimal(hex, decimals = 6) {
120
54
  const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
121
55
  const parsed = BigInt(normalized);
122
- if (decimals <= 0) return Number(parsed);
56
+ if (decimals <= 0)
57
+ return Number(parsed);
123
58
  const divisor = BigInt(10 ** decimals);
124
59
  const whole = parsed / divisor;
125
60
  const remainder = parsed % divisor;
@@ -132,20 +67,6 @@ var DayFilterMapping = {
132
67
  };
133
68
 
134
69
  // src/agents/zyfai/zyfai.mapper.ts
135
- var DECIMALS_BY_SYMBOL = {
136
- usdc: 6,
137
- usdt: 6,
138
- weth: 18,
139
- eth: 18,
140
- cbeth: 18,
141
- wbtc: 8,
142
- cbbtc: 8
143
- };
144
- function tokenDecimals(symbol, explicit) {
145
- if (typeof explicit === "number" && Number.isFinite(explicit))
146
- return explicit;
147
- return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
148
- }
149
70
  function mapDeposit(raw) {
150
71
  return {
151
72
  txHash: raw.txHash,
@@ -162,8 +83,7 @@ function mapWithdraw(raw) {
162
83
  }
163
84
  var CHAIN_ID_TO_NAME = {
164
85
  8453: "BASE",
165
- 42161: "ARBITRUM",
166
- 1: "ETHEREUM"
86
+ 42161: "ARBITRUM"
167
87
  };
168
88
  var NAME_TO_CHAIN_ID = Object.entries(
169
89
  CHAIN_ID_TO_NAME
@@ -173,52 +93,54 @@ var NAME_TO_CHAIN_ID = Object.entries(
173
93
  }, {});
174
94
  function resolveChainId(chain) {
175
95
  const asNum = Number(chain);
176
- if (Number.isFinite(asNum) && asNum > 0) return asNum;
96
+ if (Number.isFinite(asNum) && asNum > 0)
97
+ return asNum;
177
98
  return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
178
99
  }
179
100
  function mapBalances(raw, _chainId, smartWallet) {
180
101
  const portfolio = raw.portfolio;
181
102
  const portfolioByChain = portfolio.portfolioByChain ?? {};
103
+ const rawPositions = portfolio.positions ?? [];
104
+ const detailByKey = /* @__PURE__ */ new Map();
105
+ for (const p of rawPositions) {
106
+ const cid = resolveChainId(p.chain ?? "");
107
+ const symbol = (p.token_symbol ?? "").toUpperCase();
108
+ if (Number.isFinite(cid) && symbol)
109
+ detailByKey.set(`${cid}:${symbol}`, p);
110
+ }
182
111
  let totalBalance = 0;
183
112
  const tokens = [];
113
+ const positions = [];
184
114
  for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
185
115
  const positionChainId = Number(chainIdKey);
116
+ const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
186
117
  for (const [symbol, { balance, decimals }] of Object.entries(
187
118
  tokensBySymbol ?? {}
188
119
  )) {
189
120
  const amount = hexToDecimal(balance || "0", decimals);
190
121
  totalBalance += amount;
191
122
  tokens.push({
192
- chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
123
+ chain: chainName,
193
124
  chainId: positionChainId,
194
125
  asset: symbol,
195
126
  amount: String(amount)
196
127
  });
128
+ const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
129
+ positions.push({
130
+ chain: chainName,
131
+ protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
132
+ protocolId: detail?.protocol_id,
133
+ pool: detail?.pool,
134
+ asset: symbol,
135
+ amount: String(amount),
136
+ apy: detail?.pool_apy,
137
+ tvl: detail?.pool_tvl,
138
+ // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
139
+ // structural read keeps it undefined today and auto-populates later.
140
+ liquidity: detail?.liquidity
141
+ });
197
142
  }
198
143
  }
199
- const positions = (portfolio.positions ?? []).map((p) => ({
200
- chain: p.chain ?? "",
201
- protocol: p.protocol_name ?? p.protocol_id ?? "",
202
- protocolId: p.protocol_id,
203
- pool: p.pool,
204
- asset: p.token_symbol ?? "",
205
- // Position amount is hex-encoded base units (like the token balances
206
- // above). `PositionSlot` doesn't type a `decimals` field, but runtime
207
- // getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
208
- // when present, otherwise fall back to the per-symbol lookup so
209
- // non-6-decimal assets like WETH don't render 1e12 too large.
210
- amount: String(
211
- hexToDecimal(
212
- p.amount || "0",
213
- tokenDecimals(p.token_symbol, p.decimals)
214
- )
215
- ),
216
- apy: p.pool_apy,
217
- tvl: p.pool_tvl,
218
- // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
219
- // structural read keeps it undefined today and auto-populates later.
220
- liquidity: p.liquidity
221
- }));
222
144
  return {
223
145
  smartWallet,
224
146
  totalBalance: String(totalBalance),
@@ -257,39 +179,41 @@ function mapEarnings(raw, smartWallet) {
257
179
  };
258
180
  }
259
181
  function mapWeightedApyByChain(raw) {
260
- if (!raw) return void 0;
182
+ if (!raw)
183
+ return void 0;
261
184
  const out = {};
262
185
  for (const [chainKey, tokenApy] of Object.entries(raw)) {
263
186
  const chainId = Number(chainKey);
264
- if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
187
+ if (!SUPPORTED_CHAIN_IDS.includes(chainId))
188
+ continue;
265
189
  const perAsset = {};
266
190
  for (const [symbol, apy] of Object.entries(tokenApy)) {
267
191
  const token = symbol;
268
- if (!SUPPORTED_TOKENS.includes(token)) continue;
192
+ if (!SUPPORTED_TOKENS.includes(token))
193
+ continue;
269
194
  perAsset[token] = apy;
270
195
  }
271
- if (Object.keys(perAsset).length > 0) out[chainId] = perAsset;
196
+ if (Object.keys(perAsset).length > 0)
197
+ out[chainId] = perAsset;
272
198
  }
273
199
  return Object.keys(out).length > 0 ? out : void 0;
274
200
  }
275
- function rawPoolApyForChain(entry, chainId, tokenSymbol) {
201
+ function rawPoolApyForChain(entry, chainId) {
276
202
  let weightedSum = 0;
277
203
  let totalBalance = 0;
278
204
  for (const p of entry.positions ?? []) {
279
- if (p.chainId !== chainId) continue;
280
- if (tokenSymbol && p.tokenSymbol !== tokenSymbol) continue;
205
+ if (p.chainId !== chainId)
206
+ continue;
281
207
  const balance = p.balance ?? 0;
282
- if (balance <= 0 || typeof p.apy !== "number") continue;
208
+ if (balance <= 0 || typeof p.apy !== "number")
209
+ continue;
283
210
  weightedSum += p.apy * balance;
284
211
  totalBalance += balance;
285
212
  }
286
213
  return totalBalance > 0 ? weightedSum / totalBalance : null;
287
214
  }
288
- function mapApyHistory(raw, chainId, tokenSymbol) {
289
- const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
290
- date,
291
- apy: rawPoolApyForChain(entry, chainId, tokenSymbol)
292
- })).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
215
+ function mapApyHistory(raw, chainId) {
216
+ const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({ date, apy: rawPoolApyForChain(entry, chainId) })).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
293
217
  return {
294
218
  walletAddress: raw.walletAddress,
295
219
  weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
@@ -312,7 +236,6 @@ function mapEntries(rawEntries, chainId) {
312
236
  "Withdraw from protocol": "Withdraw",
313
237
  Rebalance: "Rebalance"
314
238
  };
315
- void chainId;
316
239
  return rawEntries.map((entry) => {
317
240
  const rawLog = entry.rebalanceLog;
318
241
  const positions = entry.positions ?? [];
@@ -334,15 +257,7 @@ function mapEntries(rawEntries, chainId) {
334
257
  fromPool: from.pool,
335
258
  toPool: to.pool,
336
259
  tokenSymbol: matched?.token_symbol ?? "",
337
- amount: matched ? String(
338
- hexToDecimal(
339
- matched.amount || "0x",
340
- tokenDecimals(
341
- matched.token_symbol,
342
- matched.decimals
343
- )
344
- )
345
- ) : "",
260
+ amount: matched ? String(hexToDecimal(matched.amount || "0x")) : "",
346
261
  status: "success"
347
262
  }
348
263
  ];
@@ -361,12 +276,7 @@ function mapEntries(rawEntries, chainId) {
361
276
  txHashes: entry.transactionHash ? [entry.transactionHash] : [],
362
277
  chainId: entry.chainId,
363
278
  tokenSymbol: entry?.positions?.[0]?.token_symbol,
364
- amount: hasAmount ? String(
365
- hexToDecimal(
366
- rawAmount,
367
- tokenDecimals(entry?.positions?.[0]?.token_symbol)
368
- )
369
- ) : void 0
279
+ amount: hasAmount ? String(hexToDecimal(rawAmount)) : void 0
370
280
  }
371
281
  ],
372
282
  rebalanceLog
@@ -391,7 +301,8 @@ function mapApyByStrategy(raw) {
391
301
  const supported = SupportedAssets.find(
392
302
  (asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
393
303
  );
394
- if (!supported) continue;
304
+ if (!supported)
305
+ continue;
395
306
  const chainKey = supported.chainId;
396
307
  const symbolKey = supported.symbol;
397
308
  const bucket = apyPerAsset[chainKey] ?? {};
@@ -421,8 +332,10 @@ function computeAllocationApy(positions) {
421
332
  totalValue += value;
422
333
  const chainId = resolveChainId(p.chain);
423
334
  const token = p.asset;
424
- if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
425
- if (!SUPPORTED_TOKENS.includes(token)) continue;
335
+ if (!SUPPORTED_CHAIN_IDS.includes(chainId))
336
+ continue;
337
+ if (!SUPPORTED_TOKENS.includes(token))
338
+ continue;
426
339
  const perAsset = buckets[chainId] ?? {};
427
340
  const cell = perAsset[token] ?? { weightedSum: 0, value: 0 };
428
341
  cell.weightedSum += apy * value;
@@ -439,7 +352,8 @@ function computeAllocationApy(positions) {
439
352
  out[token] = cell.weightedSum / cell.value;
440
353
  }
441
354
  }
442
- if (Object.keys(out).length > 0) apyByChainAndAsset[chainId] = out;
355
+ if (Object.keys(out).length > 0)
356
+ apyByChainAndAsset[chainId] = out;
443
357
  }
444
358
  const totalApy = totalValue > 0 ? String(weightedSum / totalValue) : "0";
445
359
  return { totalApy, apyByChainAndAsset };
@@ -456,14 +370,19 @@ function extractWithdrawnAmount(logs, recipient, token, decimals) {
456
370
  let total = 0n;
457
371
  let matched = false;
458
372
  for (const log of logs) {
459
- if (log.address.toLowerCase() !== wantToken) continue;
460
- if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC) continue;
461
- if (topicToAddress(log.topics[2]) !== wantRecipient) continue;
462
- if (!log.data || log.data === "0x") continue;
373
+ if (log.address.toLowerCase() !== wantToken)
374
+ continue;
375
+ if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC)
376
+ continue;
377
+ if (topicToAddress(log.topics[2]) !== wantRecipient)
378
+ continue;
379
+ if (!log.data || log.data === "0x")
380
+ continue;
463
381
  total += BigInt(log.data);
464
382
  matched = true;
465
383
  }
466
- if (!matched) return void 0;
384
+ if (!matched)
385
+ return void 0;
467
386
  return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
468
387
  }
469
388
 
@@ -479,7 +398,8 @@ function encodeHistoryCursor(payload) {
479
398
  return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
480
399
  }
481
400
  function decodeHistoryCursor(token) {
482
- if (!token) throw new InvalidHistoryCursorError("Cursor is empty.");
401
+ if (!token)
402
+ throw new InvalidHistoryCursorError("Cursor is empty.");
483
403
  let parsed;
484
404
  try {
485
405
  const json = Buffer.from(token, "base64").toString("utf8");
@@ -496,7 +416,8 @@ function decodeHistoryCursor(token) {
496
416
  // src/agents/zyfai/zyfai.auth-cache.ts
497
417
  var KEY_PREFIX = "owney.zyfai.session";
498
418
  var storage = () => {
499
- if (typeof window === "undefined") return null;
419
+ if (typeof window === "undefined")
420
+ return null;
500
421
  try {
501
422
  return window.localStorage;
502
423
  } catch {
@@ -506,13 +427,15 @@ var storage = () => {
506
427
  var buildKey = (address, chainId) => `${KEY_PREFIX}:${address.toLowerCase()}:${chainId}`;
507
428
  var isJwtExpired = (token) => {
508
429
  const parts = token.split(".");
509
- if (parts.length !== 3) return false;
430
+ if (parts.length !== 3)
431
+ return false;
510
432
  try {
511
433
  const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
512
434
  const padded = payload + "=".repeat((4 - payload.length % 4) % 4);
513
435
  const decoded = typeof atob === "function" ? atob(padded) : Buffer.from(padded, "base64").toString("utf8");
514
436
  const claims = JSON.parse(decoded);
515
- if (typeof claims.exp !== "number") return false;
437
+ if (typeof claims.exp !== "number")
438
+ return false;
516
439
  return Date.now() / 1e3 >= claims.exp - 30;
517
440
  } catch {
518
441
  return false;
@@ -520,9 +443,11 @@ var isJwtExpired = (token) => {
520
443
  };
521
444
  var readSession = (address, chainId) => {
522
445
  const store = storage();
523
- if (!store) return null;
446
+ if (!store)
447
+ return null;
524
448
  const raw = store.getItem(buildKey(address, chainId));
525
- if (!raw) return null;
449
+ if (!raw)
450
+ return null;
526
451
  try {
527
452
  const parsed = JSON.parse(raw);
528
453
  if (!parsed.token || isJwtExpired(parsed.token)) {
@@ -537,7 +462,8 @@ var readSession = (address, chainId) => {
537
462
  };
538
463
  var writeSession = (address, chainId, session) => {
539
464
  const store = storage();
540
- if (!store) return;
465
+ if (!store)
466
+ return;
541
467
  try {
542
468
  store.setItem(buildKey(address, chainId), JSON.stringify(session));
543
469
  } catch {
@@ -545,67 +471,33 @@ var writeSession = (address, chainId, session) => {
545
471
  };
546
472
  var clearSession = (address, chainId) => {
547
473
  const store = storage();
548
- if (!store) return;
474
+ if (!store)
475
+ return;
549
476
  try {
550
477
  store.removeItem(buildKey(address, chainId));
551
478
  } catch {
552
479
  }
553
480
  };
554
481
 
555
- // src/agents/zyfai/autoSelect.ts
556
- function buildAutoSelectUpdate(current, asset) {
557
- if (current.autoSelectProtocols === true) return null;
558
- return {
559
- asset,
560
- autoSelectProtocols: true,
561
- ...current.chains ? { chains: current.chains } : {}
562
- };
563
- }
564
-
565
482
  // src/agents/zyfai/zyfai.agent.ts
566
483
  var DEFAULT_ZYFAI_RPC_URLS = {
567
484
  8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
568
- 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
569
- 1: "https://eth-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
570
- };
571
- var WETH_ADDRESS_BY_CHAIN = {
572
- 8453: "0x4200000000000000000000000000000000000006",
573
- 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
574
- 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
485
+ 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
575
486
  };
576
- var VIEM_CHAIN = { 8453: base, 42161: arbitrum, 1: mainnet };
487
+ var VIEM_CHAIN = { 8453: base, 42161: arbitrum };
577
488
  var ZyfaiAgent = class {
578
489
  id = "zyfai";
579
- supportedChainIds = [8453, 42161, 1];
490
+ supportedChainIds = [8453, 42161];
580
491
  supportedAssets = [
581
492
  {
582
493
  chainId: 8453,
583
494
  chain: "BASE",
584
- assets: [
585
- { symbol: "USDC", minDepositAmount: "1500000" },
586
- { symbol: "WETH", minDepositAmount: "500000000000000" }
587
- ]
495
+ assets: [{ symbol: "USDC", minDepositAmount: "1500000" }]
588
496
  },
589
497
  {
590
498
  chainId: 42161,
591
499
  chain: "ARBITRUM",
592
- assets: [
593
- { symbol: "USDC", minDepositAmount: "1500000" },
594
- { symbol: "WETH", minDepositAmount: "500000000000000" }
595
- ]
596
- },
597
- {
598
- chainId: 1,
599
- chain: "ETHEREUM",
600
- // Zyfai enforces per-asset minimum portfolios on Ethereum mainnet, keyed
601
- // by MIN_PORTFOLIO_BALANCE[1] in @zyfai/sdk (mainnet gas only pays off on
602
- // large positions). USDC: 10,000 (10_000 * 1e6). WETH: 5 (5 * 1e18).
603
- // NOTE: the @zyfai/sdk README claims WETH has no minimum — that's stale;
604
- // the shipped code enforces 5 WETH, so match it or deposits reject on-chain.
605
- assets: [
606
- { symbol: "USDC", minDepositAmount: "10000000000" },
607
- { symbol: "WETH", minDepositAmount: "5000000000000000000" }
608
- ]
500
+ assets: [{ symbol: "USDC", minDepositAmount: "1500000" }]
609
501
  }
610
502
  ];
611
503
  sdk;
@@ -629,7 +521,8 @@ var ZyfaiAgent = class {
629
521
  }
630
522
  getPublicClient(chainId) {
631
523
  const cached = this.publicClients.get(chainId);
632
- if (cached) return cached;
524
+ if (cached)
525
+ return cached;
633
526
  const client = createPublicClient({
634
527
  chain: VIEM_CHAIN[chainId],
635
528
  transport: http(this.rpcUrls[chainId])
@@ -639,43 +532,33 @@ var ZyfaiAgent = class {
639
532
  }
640
533
  /**
641
534
  * Fills in the true withdrawn amount for `Withdraw` entries by decoding the
642
- * on-chain `Transfer` that lands in the user's wallet. The Zyfai history
535
+ * USDC `Transfer` that lands in the user's wallet on-chain. The Zyfai history
643
536
  * payload only reports the *remaining* position for a partial withdraw (see
644
537
  * the note in `mapEntries`), so without this the UI shows the leftover
645
538
  * balance instead of the amount withdrawn.
646
539
  *
647
- * The withdrawn asset varies per entry (USDC or WETH), so it's resolved
648
- * from `tx.tokenSymbol` (set by `mapEntries` from the entry's own
649
- * position) rather than assumed to always be USDC. Zyfai sometimes
650
- * denominates WETH as lowercase "eth" — that's normalized to WETH.
651
- * Entries with no symbol (older payload shapes) fall back to USDC to
652
- * preserve prior behavior.
653
- *
654
540
  * Mutates `entries` in place. Runs all lookups concurrently and is tolerant
655
541
  * of RPC failures: an entry whose amount can't be resolved keeps
656
542
  * `amount: undefined`, which consumers render as a hidden/retryable row
657
543
  * rather than a wrong number.
658
544
  */
659
545
  async resolveWithdrawnAmounts(entries, chainId, recipient) {
546
+ const asset = SupportedAssets.find(
547
+ (a) => a.chainId === chainId && a.symbol === "USDC"
548
+ );
549
+ if (!asset)
550
+ return;
660
551
  const withdrawals = entries.filter(
661
552
  (e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
662
553
  );
663
- if (withdrawals.length === 0) return;
554
+ if (withdrawals.length === 0)
555
+ return;
664
556
  const client = this.getPublicClient(chainId);
665
557
  await Promise.all(
666
558
  withdrawals.map(async (entry) => {
667
559
  const tx = entry.transactions[0];
668
560
  const txHash = tx.txHashes[0];
669
- const rawSymbol = tx.tokenSymbol;
670
- const normalizedSymbol = rawSymbol ? rawSymbol.toLowerCase() === "eth" ? "WETH" : rawSymbol.toUpperCase() : "USDC";
671
- const asset = SupportedAssets.find(
672
- (a) => a.chainId === chainId && a.symbol === normalizedSymbol
673
- ) ?? SupportedAssets.find(
674
- (a) => a.chainId === chainId && a.symbol === "USDC"
675
- );
676
- if (!asset) return;
677
- const cacheKey = `${txHash}:${asset.address}`;
678
- const cached = this.withdrawAmountCache.get(cacheKey);
561
+ const cached = this.withdrawAmountCache.get(txHash);
679
562
  if (cached !== void 0) {
680
563
  tx.amount = cached;
681
564
  return;
@@ -691,7 +574,7 @@ var ZyfaiAgent = class {
691
574
  asset.decimals
692
575
  );
693
576
  if (amount !== void 0) {
694
- this.withdrawAmountCache.set(cacheKey, amount);
577
+ this.withdrawAmountCache.set(txHash, amount);
695
578
  tx.amount = amount;
696
579
  }
697
580
  } catch {
@@ -710,11 +593,13 @@ var ZyfaiAgent = class {
710
593
  * for some apps and the patch only matters in the browser anyway.
711
594
  */
712
595
  installAuthCache() {
713
- if (typeof window === "undefined") return;
596
+ if (typeof window === "undefined")
597
+ return;
714
598
  const internals = this.sdk;
715
599
  const original = internals.authenticateUser.bind(internals);
716
600
  internals.authenticateUser = async () => {
717
- if (internals.authenticatedUserId !== null) return;
601
+ if (internals.authenticatedUserId !== null)
602
+ return;
718
603
  const address = internals.walletClient?.account?.address;
719
604
  const chainId = internals.currentChainId;
720
605
  if (address && chainId) {
@@ -789,10 +674,12 @@ var ZyfaiAgent = class {
789
674
  return await this.sdk.connectAccount(provider, chainId);
790
675
  } catch (error) {
791
676
  const message = error instanceof Error ? error.message : String(error);
792
- if (!message.toLowerCase().includes("unauthorized")) throw error;
677
+ if (!message.toLowerCase().includes("unauthorized"))
678
+ throw error;
793
679
  const internals = this.sdk;
794
680
  const address = internals.walletClient?.account?.address;
795
- if (address) clearSession(address, chainId);
681
+ if (address)
682
+ clearSession(address, chainId);
796
683
  return await this.sdk.connectAccount(provider, chainId);
797
684
  }
798
685
  }
@@ -805,22 +692,6 @@ var ZyfaiAgent = class {
805
692
  this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
806
693
  if (!wallet.isDeployed) {
807
694
  await this.sdk.deploySafe(address, validChainId, "aggressive", true);
808
- try {
809
- if (validChainId === 42161) {
810
- await this.sdk.updateUserProfile({
811
- asset: "WETH",
812
- chains: [validChainId],
813
- protocols: ["c24a33fa-4a87-4376-b756-93bd3957d3ea"],
814
- // AAVE protocol ID
815
- autoSelectProtocols: false
816
- });
817
- }
818
- } catch (err) {
819
- console.warn(
820
- "Failed to configure AAVE protocol after Safe deployment:",
821
- err instanceof Error ? err.message : String(err)
822
- );
823
- }
824
695
  }
825
696
  const user = await this.sdk.getUserDetails();
826
697
  if (!user.hasActiveSessionKey) {
@@ -862,7 +733,7 @@ var ZyfaiAgent = class {
862
733
  throw error;
863
734
  }
864
735
  }
865
- async deposit(state, chainId, amount, asset, depositCallback) {
736
+ async deposit(state, chainId, amount, depositCallback) {
866
737
  try {
867
738
  await this.connectFull(state, chainId);
868
739
  const validChainId = isValidChainId(chainId);
@@ -876,15 +747,13 @@ var ZyfaiAgent = class {
876
747
  validChainId,
877
748
  amount
878
749
  );
879
- const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
880
- await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
750
+ await this.sdk.logDeposit(validChainId, txHash, amount);
881
751
  return { txHash, smartWallet: wallet.address, amount };
882
752
  }
883
753
  const raw = await this.sdk.depositFunds(
884
754
  this.getAddress(),
885
755
  validChainId,
886
- amount,
887
- asset
756
+ amount
888
757
  );
889
758
  return mapDeposit(raw);
890
759
  } catch (error) {
@@ -922,10 +791,10 @@ var ZyfaiAgent = class {
922
791
  const raw = await this.sdk.getOnchainEarnings(smartWallet);
923
792
  return mapEarnings(raw, smartWallet);
924
793
  }
925
- async getAccountApy(state, chainId, days, tokenSymbol) {
794
+ async getAccountApy(state, chainId, days) {
926
795
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
927
796
  const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
928
- return mapApyHistory(raw, chainId, tokenSymbol);
797
+ return mapApyHistory(raw, chainId);
929
798
  }
930
799
  async getHistory(state, chainId, options) {
931
800
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
@@ -980,20 +849,6 @@ var ZyfaiAgent = class {
980
849
  }
981
850
  return mapUserProfile(raw, this.connectedAddress);
982
851
  }
983
- async ensureAutoSelectProtocols(state, chainId, asset) {
984
- await this.connectAuth(state, chainId);
985
- const current = await this.sdk.getUserDetails(asset);
986
- const update = buildAutoSelectUpdate(
987
- {
988
- autoSelectProtocols: current.autoSelectProtocols,
989
- chains: current.chains
990
- },
991
- asset
992
- );
993
- if (!update) return false;
994
- await this.sdk.updateUserProfile(update);
995
- return true;
996
- }
997
852
  // --- IAgent: Discovery (no wallet required) ---
998
853
  async getAgentApy(days, options) {
999
854
  const raw = await this.sdk.getAPYPerStrategy(
@@ -1079,7 +934,8 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
1079
934
  const tokenBalance = agentBalance?.tokens.find(
1080
935
  (t) => t.chainId === chainId && t.asset.toUpperCase() === target
1081
936
  );
1082
- if (!tokenBalance) return { agent, balance: 0n };
937
+ if (!tokenBalance)
938
+ return { agent, balance: 0n };
1083
939
  return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
1084
940
  });
1085
941
  }
@@ -1096,9 +952,11 @@ function planProportionalShares(balances, requested, totalAvailable) {
1096
952
  return diff > 0n ? 1 : diff < 0n ? -1 : 0;
1097
953
  });
1098
954
  for (const p of byHeadroom) {
1099
- if (remainder === 0n) break;
955
+ if (remainder === 0n)
956
+ break;
1100
957
  const headroom = p.balance - p.planned;
1101
- if (headroom <= 0n) continue;
958
+ if (headroom <= 0n)
959
+ continue;
1102
960
  const take = headroom < remainder ? headroom : remainder;
1103
961
  p.planned += take;
1104
962
  remainder -= take;
@@ -1127,7 +985,8 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
1127
985
  (s, c) => s + (c.balance - c.planned),
1128
986
  0n
1129
987
  );
1130
- if (totalHeadroom === 0n) return;
988
+ if (totalHeadroom === 0n)
989
+ return;
1131
990
  let distributed = 0n;
1132
991
  for (const c of candidates) {
1133
992
  const headroom = c.balance - c.planned;
@@ -1138,9 +997,11 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
1138
997
  }
1139
998
  let leftover = amount - distributed;
1140
999
  for (const c of candidates) {
1141
- if (leftover === 0n) break;
1000
+ if (leftover === 0n)
1001
+ break;
1142
1002
  const headroom = c.balance - c.planned;
1143
- if (headroom <= 0n) continue;
1003
+ if (headroom <= 0n)
1004
+ continue;
1144
1005
  const take = headroom < leftover ? headroom : leftover;
1145
1006
  c.planned += take;
1146
1007
  leftover -= take;
@@ -1157,13 +1018,16 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1157
1018
  for (const id of Object.keys(agentApys)) {
1158
1019
  const cells = agentApys[id].apyByChainAndAsset;
1159
1020
  const balance = agentBalances[id] ?? 0;
1160
- if (!cells || balance <= 0) continue;
1021
+ if (!cells || balance <= 0)
1022
+ continue;
1161
1023
  for (const [chainKey, perAsset] of Object.entries(cells)) {
1162
- if (!perAsset) continue;
1024
+ if (!perAsset)
1025
+ continue;
1163
1026
  const chainId = Number(chainKey);
1164
1027
  for (const [asset, apyValue] of Object.entries(perAsset)) {
1165
1028
  const apy = Number(apyValue ?? 0);
1166
- if (apy === 0) continue;
1029
+ if (apy === 0)
1030
+ continue;
1167
1031
  sums[chainId] ??= {};
1168
1032
  weights[chainId] ??= {};
1169
1033
  sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
@@ -1177,7 +1041,8 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1177
1041
  const perAssetOut = {};
1178
1042
  for (const asset of Object.keys(sums[chainId])) {
1179
1043
  const w = weights[chainId][asset];
1180
- if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
1044
+ if (w > 0)
1045
+ perAssetOut[asset] = sums[chainId][asset] / w;
1181
1046
  }
1182
1047
  if (Object.keys(perAssetOut).length > 0) {
1183
1048
  out[chainId] = perAssetOut;
@@ -1192,7 +1057,7 @@ import {
1192
1057
  createWalletClient,
1193
1058
  custom
1194
1059
  } from "viem";
1195
- import { base as base2, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
1060
+ import { base as base2, arbitrum as arbitrum2 } from "viem/chains";
1196
1061
 
1197
1062
  // src/lib/transfer-auth.ts
1198
1063
  import { bytesToHex } from "viem";
@@ -1238,10 +1103,7 @@ async function postSponsorTransferAuth(input) {
1238
1103
  try {
1239
1104
  res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
1240
1105
  method: "POST",
1241
- headers: {
1242
- "content-type": "application/json",
1243
- "x-owney-api-key": input.apiKey
1244
- },
1106
+ headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
1245
1107
  body: JSON.stringify(input.body)
1246
1108
  });
1247
1109
  } catch (networkError) {
@@ -1261,91 +1123,11 @@ async function postSponsorTransferAuth(input) {
1261
1123
  throw new OwneyError(
1262
1124
  "SPONSOR_REQUEST_FAILED",
1263
1125
  `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1264
- {
1265
- statusCode: res.status,
1266
- responseBody: text.slice(0, 500),
1267
- // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
1268
- // before broadcast, so it is safe to fall back to a user-paid deposit.
1269
- safeToFallback: res.status === 503
1270
- }
1126
+ { statusCode: res.status, responseBody: text.slice(0, 500) }
1271
1127
  );
1272
1128
  }
1273
1129
  return parsed.data;
1274
1130
  }
1275
- async function postSponsorPermit2Transfer(input) {
1276
- const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1277
- let res;
1278
- try {
1279
- res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
1280
- method: "POST",
1281
- headers: {
1282
- "content-type": "application/json",
1283
- "x-owney-api-key": input.apiKey
1284
- },
1285
- body: JSON.stringify(input.body)
1286
- });
1287
- } catch (networkError) {
1288
- throw new OwneyError(
1289
- "SPONSOR_REQUEST_FAILED",
1290
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
1291
- { cause: String(networkError), safeToFallback: false }
1292
- );
1293
- }
1294
- const text = await res.text();
1295
- let parsed = null;
1296
- try {
1297
- parsed = JSON.parse(text);
1298
- } catch {
1299
- }
1300
- if (!res.ok || !parsed?.success || !parsed.data) {
1301
- throw new OwneyError(
1302
- "SPONSOR_REQUEST_FAILED",
1303
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1304
- {
1305
- statusCode: res.status,
1306
- responseBody: text.slice(0, 500),
1307
- safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
1308
- }
1309
- );
1310
- }
1311
- return parsed.data;
1312
- }
1313
- async function getSponsorRelayerAddress(input) {
1314
- const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1315
- let res;
1316
- try {
1317
- res = await fetch(
1318
- `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
1319
- {
1320
- headers: { "x-owney-api-key": input.apiKey }
1321
- }
1322
- );
1323
- } catch (networkError) {
1324
- throw new OwneyError(
1325
- "SPONSOR_REQUEST_FAILED",
1326
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
1327
- { cause: String(networkError), safeToFallback: true }
1328
- );
1329
- }
1330
- const text = await res.text();
1331
- let parsed = null;
1332
- try {
1333
- parsed = JSON.parse(text);
1334
- } catch {
1335
- }
1336
- if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
1337
- throw new OwneyError(
1338
- "SPONSOR_REQUEST_FAILED",
1339
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1340
- {
1341
- statusCode: res.status,
1342
- responseBody: text.slice(0, 500),
1343
- safeToFallback: true
1344
- }
1345
- );
1346
- }
1347
- return parsed.data.relayer;
1348
- }
1349
1131
 
1350
1132
  // src/lib/sponsored-deposit.ts
1351
1133
  var AUTH_WINDOW_SECONDS = 15 * 60;
@@ -1397,114 +1179,6 @@ function makeSponsoredDepositCallback(deps) {
1397
1179
  };
1398
1180
  }
1399
1181
 
1400
- // src/lib/permit2.ts
1401
- import { bytesToHex as bytesToHex2 } from "viem";
1402
- var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
1403
- var MAX_UINT256 = 2n ** 256n - 1n;
1404
- var ERC20_ALLOWANCE_ABI = [
1405
- {
1406
- type: "function",
1407
- name: "allowance",
1408
- stateMutability: "view",
1409
- inputs: [{ name: "owner", type: "address" }, { name: "spender", type: "address" }],
1410
- outputs: [{ name: "", type: "uint256" }]
1411
- },
1412
- {
1413
- type: "function",
1414
- name: "approve",
1415
- stateMutability: "nonpayable",
1416
- inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }],
1417
- outputs: [{ name: "", type: "bool" }]
1418
- }
1419
- ];
1420
- function buildPermitTransferFromTypedData(input) {
1421
- return {
1422
- domain: { name: "Permit2", chainId: input.chainId, verifyingContract: PERMIT2_ADDRESS },
1423
- types: {
1424
- PermitTransferFrom: [
1425
- { name: "permitted", type: "TokenPermissions" },
1426
- { name: "spender", type: "address" },
1427
- { name: "nonce", type: "uint256" },
1428
- { name: "deadline", type: "uint256" }
1429
- ],
1430
- TokenPermissions: [
1431
- { name: "token", type: "address" },
1432
- { name: "amount", type: "uint256" }
1433
- ]
1434
- },
1435
- primaryType: "PermitTransferFrom",
1436
- message: input.message
1437
- };
1438
- }
1439
- function randomPermit2Nonce() {
1440
- const bytes = new Uint8Array(32);
1441
- globalThis.crypto.getRandomValues(bytes);
1442
- return BigInt(bytesToHex2(bytes));
1443
- }
1444
- async function readPermit2Allowance(publicClient, token, owner) {
1445
- return publicClient.readContract({
1446
- address: token,
1447
- abi: ERC20_ALLOWANCE_ABI,
1448
- functionName: "allowance",
1449
- args: [owner, PERMIT2_ADDRESS]
1450
- });
1451
- }
1452
-
1453
- // src/lib/sponsored-weth-deposit.ts
1454
- var PERMIT_WINDOW_SECONDS = 15 * 60;
1455
- function makeSponsoredWethCallback(deps) {
1456
- const get = deps.httpGet ?? getSponsorRelayerAddress;
1457
- const post = deps.httpPost ?? postSponsorPermit2Transfer;
1458
- return async (smartWallet, chainId, amount) => {
1459
- const cid = chainId;
1460
- const token = deps.tokenAddressByChain[cid];
1461
- if (!token) {
1462
- throw new OwneyError("CHAIN_UNSUPPORTED", `No sponsored WETH configured for chain ${chainId}`);
1463
- }
1464
- const amountWei = BigInt(amount);
1465
- const pub = deps.getPublicClient(cid);
1466
- const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
1467
- if (allowance < amountWei) {
1468
- throw new OwneyError(
1469
- "PERMIT2_APPROVAL_REQUIRED",
1470
- "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
1471
- { token, chainId: cid, allowance: allowance.toString(), amount }
1472
- );
1473
- }
1474
- const relayer = await get({ baseUrl: deps.baseUrl, apiKey: deps.apiKey, chainId: cid });
1475
- const nonce = randomPermit2Nonce();
1476
- const deadline = BigInt(Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS);
1477
- const typedData = buildPermitTransferFromTypedData({
1478
- chainId: cid,
1479
- message: {
1480
- permitted: { token, amount: amountWei },
1481
- spender: relayer,
1482
- nonce,
1483
- deadline
1484
- }
1485
- });
1486
- const wallet = deps.getWalletClient(cid);
1487
- const signature = await wallet.signTypedData(
1488
- { account: deps.ownerAddress, ...typedData }
1489
- );
1490
- const result = await post({
1491
- baseUrl: deps.baseUrl,
1492
- apiKey: deps.apiKey,
1493
- body: {
1494
- chainId: cid,
1495
- token,
1496
- from: deps.ownerAddress,
1497
- to: smartWallet,
1498
- amount,
1499
- nonce: nonce.toString(),
1500
- deadline: deadline.toString(),
1501
- signature
1502
- }
1503
- });
1504
- return result.txHash;
1505
- };
1506
- }
1507
-
1508
1182
  // src/client.ts
1509
1183
  function encodeMultiAgentCursor(map) {
1510
1184
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
@@ -1528,22 +1202,13 @@ function decodeMultiAgentCursor(token) {
1528
1202
  }
1529
1203
  var SPONSORED_USDC_BY_CHAIN = {
1530
1204
  8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1531
- 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
1532
- 1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
1205
+ 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
1533
1206
  };
1534
1207
  var VIEM_CHAIN2 = {
1535
1208
  8453: base2,
1536
- 42161: arbitrum2,
1537
- 1: mainnet2
1538
- };
1539
- var SPONSORED_WETH_BY_CHAIN = {
1540
- 8453: "0x4200000000000000000000000000000000000006",
1541
- 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
1542
- 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
1209
+ 42161: arbitrum2
1543
1210
  };
1544
- function shouldFallbackToUserPaid(error, asset, appCallback) {
1545
- return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
1546
- }
1211
+ var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
1547
1212
  var OwneySDK = class {
1548
1213
  agents = /* @__PURE__ */ new Map();
1549
1214
  activeAgents = /* @__PURE__ */ new Set();
@@ -1556,14 +1221,11 @@ var OwneySDK = class {
1556
1221
  state = null;
1557
1222
  apiKey;
1558
1223
  zyfaiRpcUrls;
1559
- routingApiBaseUrl;
1560
1224
  cachedSponsoredCallback = null;
1561
- cachedWethSponsoredCallback = null;
1562
1225
  initializingAgentsPromise = null;
1563
1226
  constructor(config) {
1564
1227
  this.apiKey = config.apiKey;
1565
1228
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
1566
- this.routingApiBaseUrl = config.routingApiBaseUrl;
1567
1229
  }
1568
1230
  /**
1569
1231
  * Establish connection state for all subsequent SDK calls.
@@ -1584,7 +1246,6 @@ var OwneySDK = class {
1584
1246
  }
1585
1247
  this.state = { provider, walletAddress, chainId: null };
1586
1248
  this.cachedSponsoredCallback = null;
1587
- this.cachedWethSponsoredCallback = null;
1588
1249
  }
1589
1250
  /**
1590
1251
  * Disconnect from all agents and clear connection state.
@@ -1598,7 +1259,6 @@ var OwneySDK = class {
1598
1259
  this.disabledAgents.clear();
1599
1260
  this.state = null;
1600
1261
  this.cachedSponsoredCallback = null;
1601
- this.cachedWethSponsoredCallback = null;
1602
1262
  }
1603
1263
  isAgentDisabled(agentId) {
1604
1264
  return this.disabledAgents.has(agentId);
@@ -1618,7 +1278,8 @@ var OwneySDK = class {
1618
1278
  return this.state?.chainId ?? null;
1619
1279
  }
1620
1280
  requireState() {
1621
- if (!this.state) throw new NotConnectedError();
1281
+ if (!this.state)
1282
+ throw new NotConnectedError();
1622
1283
  return this.state;
1623
1284
  }
1624
1285
  requireChainId() {
@@ -1648,12 +1309,12 @@ var OwneySDK = class {
1648
1309
  * `TransferWithAuthorization`, then POSTs to the sponsor API.
1649
1310
  */
1650
1311
  getDefaultSponsoredCallback() {
1651
- if (this.cachedSponsoredCallback) return this.cachedSponsoredCallback;
1312
+ if (this.cachedSponsoredCallback)
1313
+ return this.cachedSponsoredCallback;
1652
1314
  const provider = this.requireConnectedProvider();
1653
1315
  const owner = this.state.walletAddress;
1654
1316
  this.cachedSponsoredCallback = makeSponsoredDepositCallback({
1655
1317
  apiKey: this.apiKey,
1656
- baseUrl: this.routingApiBaseUrl,
1657
1318
  ownerAddress: owner,
1658
1319
  tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
1659
1320
  // Casts work around viem's chain-narrowed Client vs the generic
@@ -1671,37 +1332,6 @@ var OwneySDK = class {
1671
1332
  });
1672
1333
  return this.cachedSponsoredCallback;
1673
1334
  }
1674
- /**
1675
- * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
1676
- * callback used when the caller omits `depositCallback` for a WETH
1677
- * deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
1678
- * `PermitTransferFrom` instead of an EIP-3009 authorization.
1679
- */
1680
- getDefaultWethSponsoredCallback() {
1681
- if (this.cachedWethSponsoredCallback)
1682
- return this.cachedWethSponsoredCallback;
1683
- const provider = this.requireConnectedProvider();
1684
- const owner = this.state.walletAddress;
1685
- this.cachedWethSponsoredCallback = makeSponsoredWethCallback({
1686
- apiKey: this.apiKey,
1687
- baseUrl: this.routingApiBaseUrl,
1688
- ownerAddress: owner,
1689
- tokenAddressByChain: SPONSORED_WETH_BY_CHAIN,
1690
- // Casts work around viem's chain-narrowed Client vs the generic
1691
- // PublicClient/WalletClient param types — structurally identical at
1692
- // runtime, but the two share a name TS treats as unrelated.
1693
- getPublicClient: (cid) => createPublicClient2({
1694
- chain: VIEM_CHAIN2[cid],
1695
- transport: custom(provider)
1696
- }),
1697
- getWalletClient: (cid) => createWalletClient({
1698
- account: owner,
1699
- chain: VIEM_CHAIN2[cid],
1700
- transport: custom(provider)
1701
- })
1702
- });
1703
- return this.cachedWethSponsoredCallback;
1704
- }
1705
1335
  getAgent(agentId) {
1706
1336
  const agent = this.agents.get(agentId);
1707
1337
  if (!agent) {
@@ -1713,19 +1343,22 @@ var OwneySDK = class {
1713
1343
  const active = /* @__PURE__ */ new Map();
1714
1344
  for (const id of this.activeAgents) {
1715
1345
  const agent = this.agents.get(id);
1716
- if (agent) active.set(id, agent);
1346
+ if (agent)
1347
+ active.set(id, agent);
1717
1348
  }
1718
1349
  return active;
1719
1350
  }
1720
1351
  async ensureAgentsInitialized() {
1721
- if (this.agents.size > 0) return;
1352
+ if (this.agents.size > 0)
1353
+ return;
1722
1354
  if (!this.initializingAgentsPromise) {
1723
1355
  this.initializingAgentsPromise = (async () => {
1724
1356
  const agentKeys = await fetchAgentKeys(this.apiKey);
1725
1357
  this.disabledAgents.clear();
1726
- for (const { key, agent_type, is_enabled } of agentKeys) {
1727
- const agent = this.createAgent(agent_type, key);
1728
- if (!agent) continue;
1358
+ for (const { key, agent_type, project_name, is_enabled } of agentKeys) {
1359
+ const agent = await this.createAgent(agent_type, key, project_name);
1360
+ if (!agent)
1361
+ continue;
1729
1362
  this.agents.set(agent_type, agent);
1730
1363
  if (is_enabled === false) {
1731
1364
  this.disabledAgents.add(agent_type);
@@ -1745,10 +1378,16 @@ var OwneySDK = class {
1745
1378
  this.initializingAgentsPromise = null;
1746
1379
  }
1747
1380
  }
1748
- createAgent(agentId, key) {
1381
+ async createAgent(agentId, key, projectName) {
1749
1382
  if (agentId === "zyfai") {
1750
1383
  return new ZyfaiAgent(key, this.zyfaiRpcUrls);
1751
1384
  }
1385
+ if (agentId === "surfliquid") {
1386
+ if (!projectName)
1387
+ return null;
1388
+ const { SurfLiquidAgent } = await import("./surfliquid.agent-EPFISJPR.js");
1389
+ return new SurfLiquidAgent({ projectName, appId: key });
1390
+ }
1752
1391
  return null;
1753
1392
  }
1754
1393
  // --- Account lifecycle ---
@@ -1852,7 +1491,7 @@ var OwneySDK = class {
1852
1491
  }
1853
1492
  const state = this.requireState();
1854
1493
  const chainId = this.requireChainId();
1855
- const effectiveCallback = depositCallback ?? (asset === "WETH" ? this.getDefaultWethSponsoredCallback() : this.getDefaultSponsoredCallback());
1494
+ const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
1856
1495
  if (agentId) {
1857
1496
  if (this.isAgentDisabled(agentId)) {
1858
1497
  throw new OwneyError(
@@ -1864,14 +1503,10 @@ var OwneySDK = class {
1864
1503
  const agent = this.getAgent(agentId);
1865
1504
  this.validateAssetSupport(agent, chainId, asset);
1866
1505
  await this.validateMinDepositAmount(agent, state, chainId, asset, amount);
1867
- return this.depositWithFallback(
1868
- agent,
1869
- state,
1870
- chainId,
1871
- amount,
1872
- asset,
1873
- effectiveCallback,
1874
- depositCallback
1506
+ return withFailureReporting(
1507
+ this.apiKey,
1508
+ agent.id,
1509
+ () => agent.deposit(state, chainId, amount, effectiveCallback)
1875
1510
  );
1876
1511
  }
1877
1512
  const totalAmount = BigInt(amount);
@@ -1901,77 +1536,26 @@ var OwneySDK = class {
1901
1536
  );
1902
1537
  }
1903
1538
  const agentResults = {};
1539
+ const agentErrors = {};
1904
1540
  for (const { agent, amount: agentAmount } of agentAmounts) {
1905
- agentResults[agent.id] = await this.depositWithFallback(
1906
- agent,
1907
- state,
1908
- chainId,
1909
- agentAmount,
1910
- asset,
1911
- effectiveCallback,
1912
- depositCallback
1913
- );
1914
- }
1915
- return { agentResults };
1916
- }
1917
- /**
1918
- * Invokes `agent.deposit` with the resolved sponsored callback, composing
1919
- * two independent auto-recovery mechanisms:
1920
- *
1921
- * 1. Missing Permit2 allowance: when the app did not supply its own
1922
- * callback and the attempt fails with `PERMIT2_APPROVAL_REQUIRED` on a
1923
- * WETH deposit, this is the wallet's first gasless WETH deposit. We send
1924
- * the one-time (user-paid) Permit2 approval via `approvePermit2()` and
1925
- * retry the SAME sponsored attempt once. Bounded to one approval attempt
1926
- * per call so a wallet/agent that keeps reporting the allowance as
1927
- * missing can't loop forever. If `approvePermit2()` itself throws (e.g.
1928
- * the user rejects the wallet prompt), that error propagates as-is —
1929
- * the user said no to a transaction, so we must not turn around and ask
1930
- * them to pay for a different one via the fallback below.
1931
- * 2. `shouldFallbackToUserPaid`: the SDK's own WETH sponsor path failed at
1932
- * the infrastructure layer in a provably safe-to-retry way, so we warn
1933
- * and retry once with `undefined`, falling through to a user-paid
1934
- * native deposit. This still applies after a successful Permit2
1935
- * approval retry (the retried sponsored attempt can itself hit a safe
1936
- * sponsor failure).
1937
- *
1938
- * Any other error — an app-supplied callback's own failure in particular —
1939
- * propagates unchanged. Scoped per agent invocation so one agent's failure
1940
- * doesn't force a retry of sibling agents in a multi-agent split.
1941
- */
1942
- async depositWithFallback(agent, state, chainId, amount, asset, effectiveCallback, appCallback) {
1943
- const attempt = (callback) => withFailureReporting(
1944
- this.apiKey,
1945
- agent.id,
1946
- () => agent.deposit(
1947
- state,
1948
- chainId,
1949
- amount,
1950
- asset,
1951
- callback
1952
- )
1953
- );
1954
- let approvalAttempted = false;
1955
- for (; ; ) {
1956
1541
  try {
1957
- return await attempt(effectiveCallback);
1958
- } catch (error) {
1959
- if (!approvalAttempted && appCallback === void 0 && asset === "WETH" && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
1960
- approvalAttempted = true;
1961
- console.warn(
1962
- "[owney-sdk] First WETH deposit: sending one-time Permit2 approval..."
1963
- );
1964
- await this.approvePermit2();
1965
- continue;
1966
- }
1967
- if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
1968
- console.warn(
1969
- `[owney-sdk] ${asset} sponsorship unavailable, falling back to user-paid deposit:`,
1970
- error
1542
+ agentResults[agent.id] = await withFailureReporting(
1543
+ this.apiKey,
1544
+ agent.id,
1545
+ () => agent.deposit(state, chainId, agentAmount, effectiveCallback)
1971
1546
  );
1972
- return attempt(void 0);
1547
+ } catch (error) {
1548
+ agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
1973
1549
  }
1974
1550
  }
1551
+ if (Object.keys(agentResults).length === 0) {
1552
+ throw new OwneyError(
1553
+ "DEPOSIT_ALL_FAILED",
1554
+ `All ${agentAmounts.length} agent deposit(s) failed.`,
1555
+ { agentErrors }
1556
+ );
1557
+ }
1558
+ return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
1975
1559
  }
1976
1560
  getMinDepositAmount(agent, chainId, asset) {
1977
1561
  const chainAssets = agent.supportedAssets.find(
@@ -1981,7 +1565,8 @@ var OwneySDK = class {
1981
1565
  return BigInt(assetEntry?.minDepositAmount ?? "0");
1982
1566
  }
1983
1567
  splitDepositAmount(totalAmount, agents, chainId, asset, exempt = /* @__PURE__ */ new Set()) {
1984
- if (agents.length === 0) return [];
1568
+ if (agents.length === 0)
1569
+ return [];
1985
1570
  const perAgent = totalAmount / BigInt(agents.length);
1986
1571
  const remainder = totalAmount % BigInt(agents.length);
1987
1572
  const splits = agents.map((agent, i) => ({
@@ -2005,8 +1590,10 @@ var OwneySDK = class {
2005
1590
  async validateMinDepositAmount(agent, state, chainId, asset, amount) {
2006
1591
  const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
2007
1592
  const parsedAmount = BigInt(amount);
2008
- if (parsedAmount >= minDepositAmount) return;
2009
- if (await this.hasExistingBalance(agent, state, chainId, asset)) return;
1593
+ if (parsedAmount >= minDepositAmount)
1594
+ return;
1595
+ if (await this.hasExistingBalance(agent, state, chainId, asset))
1596
+ return;
2010
1597
  throw new OwneyError(
2011
1598
  "DEPOSIT_AMOUNT_BELOW_MINIMUM",
2012
1599
  `Amount "${amount}" is below the required minimum deposit "${minDepositAmount.toString()}" for agent "${agent.id}" on chain ${chainId} for asset "${asset}".`,
@@ -2069,6 +1656,34 @@ var OwneySDK = class {
2069
1656
  }
2070
1657
  return eligible;
2071
1658
  }
1659
+ /**
1660
+ * Agent ids the routing API provisioned for this org that support the given
1661
+ * chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
1662
+ * surfliquid first). Returns `[]` when the org has no compatible agent — never
1663
+ * throws on an empty org. Loads agent keys on first call (apiKey only, no
1664
+ * wallet), so the UI can resolve which agent to use before the user connects.
1665
+ *
1666
+ * This is the source of truth for agent availability: an agent appears here
1667
+ * iff the routing API returned its key. No per-app feature flags.
1668
+ */
1669
+ async getEligibleAgentIds(chainId, asset) {
1670
+ try {
1671
+ await this.ensureAgentsInitialized();
1672
+ } catch (error) {
1673
+ if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
1674
+ return [];
1675
+ }
1676
+ throw error;
1677
+ }
1678
+ return [...this.agents.values()].filter((agent) => {
1679
+ const chainAssets = agent.supportedAssets.find(
1680
+ (sa) => sa.chainId === chainId
1681
+ );
1682
+ return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
1683
+ }).map((agent) => agent.id).sort(
1684
+ (a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
1685
+ );
1686
+ }
2072
1687
  // --- Fund operations ---
2073
1688
  /**
2074
1689
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
@@ -2104,9 +1719,17 @@ var OwneySDK = class {
2104
1719
  }
2105
1720
  const eligibleAgents = this.getEligibleAgents(chainId, asset);
2106
1721
  if (!amount) {
1722
+ const aggregated2 = await this.getBalances();
1723
+ const funded = projectAgentBalancesForAsset(
1724
+ eligibleAgents,
1725
+ aggregated2.agentBalances,
1726
+ chainId,
1727
+ asset,
1728
+ assetInfo.decimals
1729
+ ).filter((b) => b.balance > 0n);
2107
1730
  const results2 = {};
2108
1731
  const agentErrors2 = {};
2109
- for (const agent of eligibleAgents) {
1732
+ for (const { agent } of funded) {
2110
1733
  try {
2111
1734
  results2[agent.id] = await agent.withdraw(state, chainId, token);
2112
1735
  } catch (err) {
@@ -2123,9 +1746,10 @@ var OwneySDK = class {
2123
1746
  { asset, agentErrors: agentErrors2 }
2124
1747
  );
2125
1748
  }
1749
+ const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
2126
1750
  return {
2127
1751
  agentResult: results2,
2128
- totalWithdrawn: sumWithdrawnAmount(results2).toString()
1752
+ totalWithdrawn: totalWithdrawn.toString()
2129
1753
  };
2130
1754
  }
2131
1755
  const requested = BigInt(amount);
@@ -2170,7 +1794,8 @@ var OwneySDK = class {
2170
1794
  const agentErrors = {};
2171
1795
  for (let i = 0; i < plans.length; i++) {
2172
1796
  const p = plans[i];
2173
- if (p.planned === 0n) continue;
1797
+ if (p.planned === 0n)
1798
+ continue;
2174
1799
  try {
2175
1800
  results[p.agent.id] = await p.agent.withdraw(
2176
1801
  state,
@@ -2304,30 +1929,19 @@ var OwneySDK = class {
2304
1929
  */
2305
1930
  async getAccountApy({
2306
1931
  agentId,
2307
- days,
2308
- tokenSymbol
1932
+ days
2309
1933
  }) {
2310
1934
  const state = this.requireState();
2311
1935
  const chainId = this.requireChainId();
2312
1936
  if (agentId) {
2313
- return this.getAgent(agentId).getAccountApy(
2314
- state,
2315
- chainId,
2316
- days,
2317
- tokenSymbol
2318
- );
1937
+ return this.getAgent(agentId).getAccountApy(state, chainId, days);
2319
1938
  }
2320
1939
  const activeAgents = this.getActiveAgents();
2321
1940
  const entries = [...activeAgents.entries()];
2322
1941
  const [apyResults, balanceResults] = await Promise.all([
2323
1942
  Promise.all(
2324
1943
  entries.map(async ([id, agent]) => {
2325
- const apy = await agent.getAccountApy(
2326
- state,
2327
- chainId,
2328
- days,
2329
- tokenSymbol
2330
- );
1944
+ const apy = await agent.getAccountApy(state, chainId, days);
2331
1945
  return [id, apy];
2332
1946
  })
2333
1947
  ),
@@ -2350,13 +1964,15 @@ var OwneySDK = class {
2350
1964
  let relevantBalance = 0;
2351
1965
  for (const id of Object.keys(results)) {
2352
1966
  const agentApy = Number(results[id].weightedApyAfterFee ?? 0);
2353
- if (agentApy === 0) continue;
1967
+ if (agentApy === 0)
1968
+ continue;
2354
1969
  relevantBalance += balances[id];
2355
1970
  }
2356
1971
  if (relevantBalance > 0) {
2357
1972
  for (const id of Object.keys(results)) {
2358
1973
  const agentApy = Number(results[id].weightedApyAfterFee ?? 0);
2359
- if (agentApy === 0) continue;
1974
+ if (agentApy === 0)
1975
+ continue;
2360
1976
  const weight = balances[id] / relevantBalance;
2361
1977
  totalApy += agentApy * weight;
2362
1978
  }
@@ -2411,7 +2027,8 @@ var OwneySDK = class {
2411
2027
  const nextCursorMap = {};
2412
2028
  let hasMore = false;
2413
2029
  for (const { agentId: id, page } of perAgent) {
2414
- if (!page) continue;
2030
+ if (!page)
2031
+ continue;
2415
2032
  merged.push(...page.data);
2416
2033
  if (page.hasMore && page.nextCursor) {
2417
2034
  nextCursorMap[id] = page.nextCursor;
@@ -2420,12 +2037,16 @@ var OwneySDK = class {
2420
2037
  }
2421
2038
  merged.sort((a, b) => {
2422
2039
  const dateDiff = new Date(b.date).getTime() - new Date(a.date).getTime();
2423
- if (dateDiff !== 0) return dateDiff;
2424
- if (a.agent !== b.agent) return a.agent < b.agent ? -1 : 1;
2040
+ if (dateDiff !== 0)
2041
+ return dateDiff;
2042
+ if (a.agent !== b.agent)
2043
+ return a.agent < b.agent ? -1 : 1;
2425
2044
  const aTx = a.transactions?.[0]?.txHashes?.[0] ?? "";
2426
2045
  const bTx = b.transactions?.[0]?.txHashes?.[0] ?? "";
2427
- if (aTx !== bTx) return aTx < bTx ? -1 : 1;
2428
- if (a.action !== b.action) return a.action < b.action ? -1 : 1;
2046
+ if (aTx !== bTx)
2047
+ return aTx < bTx ? -1 : 1;
2048
+ if (a.action !== b.action)
2049
+ return a.action < b.action ? -1 : 1;
2429
2050
  return 0;
2430
2051
  });
2431
2052
  return {
@@ -2460,67 +2081,6 @@ var OwneySDK = class {
2460
2081
  agentUserProfile: results
2461
2082
  };
2462
2083
  }
2463
- /**
2464
- * Ensure the given asset uses backend protocol auto-selection for the active
2465
- * chain's account. No-op (returns false) for agents that don't support it.
2466
- * @param asset - "USDC" or "WETH".
2467
- * @param agentId - Agent to target. Defaults to "zyfai".
2468
- * @returns whether a profile write occurred.
2469
- */
2470
- async ensureAutoSelectProtocols(asset, agentId = "zyfai") {
2471
- const state = this.requireState();
2472
- const chainId = this.requireChainId();
2473
- const agent = this.getAgent(agentId);
2474
- if (typeof agent.ensureAutoSelectProtocols !== "function") return false;
2475
- return agent.ensureAutoSelectProtocols(state, chainId, asset);
2476
- }
2477
- /**
2478
- * One-time, user-paid approval of Permit2 on the sponsored WETH token for
2479
- * the active chain. Required once per wallet per chain before gasless WETH
2480
- * deposits; afterwards deposit() is signature-only. Resolves only after the
2481
- * approval transaction is mined (1 confirmation), so a subsequent deposit()
2482
- * will see the new allowance; throws if the transaction reverted.
2483
- * @returns the approval transaction hash.
2484
- */
2485
- async approvePermit2(asset = "WETH") {
2486
- void asset;
2487
- const state = this.requireState();
2488
- const chainId = this.requireChainId();
2489
- this.validateAssetSupport(this.getAgent("zyfai"), chainId, "WETH");
2490
- const token = SPONSORED_WETH_BY_CHAIN[chainId];
2491
- if (!token) {
2492
- throw new OwneyError(
2493
- "CHAIN_UNSUPPORTED",
2494
- `No sponsored WETH on chain ${chainId}`
2495
- );
2496
- }
2497
- const provider = this.requireConnectedProvider();
2498
- const wallet = createWalletClient({
2499
- account: state.walletAddress,
2500
- chain: VIEM_CHAIN2[chainId],
2501
- transport: custom(provider)
2502
- });
2503
- const hash = await wallet.writeContract({
2504
- address: token,
2505
- abi: ERC20_ALLOWANCE_ABI,
2506
- functionName: "approve",
2507
- args: [PERMIT2_ADDRESS, MAX_UINT256],
2508
- account: state.walletAddress,
2509
- chain: VIEM_CHAIN2[chainId]
2510
- });
2511
- const publicClient = createPublicClient2({
2512
- chain: VIEM_CHAIN2[chainId],
2513
- transport: custom(provider)
2514
- });
2515
- const receipt = await publicClient.waitForTransactionReceipt({
2516
- hash,
2517
- confirmations: 1
2518
- });
2519
- if (receipt.status !== "success") {
2520
- throw new Error(`Permit2 approval reverted (tx ${hash})`);
2521
- }
2522
- return hash;
2523
- }
2524
2084
  // --- Discovery (no wallet required) ---
2525
2085
  /**
2526
2086
  * Get the agent's average APY performance over a time period. Does not require a wallet connection.
@@ -2626,7 +2186,8 @@ import { ZyfaiSDK as ZyfaiSDK2 } from "@zyfai/sdk";
2626
2186
  // src/agents/zyfai/zyfai.siwx-cache.ts
2627
2187
  var KEY_PREFIX2 = "owney.siwx.session";
2628
2188
  var storage2 = () => {
2629
- if (typeof window === "undefined") return null;
2189
+ if (typeof window === "undefined")
2190
+ return null;
2630
2191
  try {
2631
2192
  return window.localStorage;
2632
2193
  } catch {
@@ -2636,9 +2197,11 @@ var storage2 = () => {
2636
2197
  var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2637
2198
  var readSiwxSession = (address, chainId) => {
2638
2199
  const store = storage2();
2639
- if (!store) return null;
2200
+ if (!store)
2201
+ return null;
2640
2202
  const raw = store.getItem(buildKey2(address, chainId));
2641
- if (!raw) return null;
2203
+ if (!raw)
2204
+ return null;
2642
2205
  try {
2643
2206
  return JSON.parse(raw);
2644
2207
  } catch {
@@ -2648,7 +2211,8 @@ var readSiwxSession = (address, chainId) => {
2648
2211
  };
2649
2212
  var writeSiwxSession = (address, chainId, session) => {
2650
2213
  const store = storage2();
2651
- if (!store) return;
2214
+ if (!store)
2215
+ return;
2652
2216
  try {
2653
2217
  store.setItem(buildKey2(address, chainId), JSON.stringify(session));
2654
2218
  } catch {
@@ -2656,7 +2220,8 @@ var writeSiwxSession = (address, chainId, session) => {
2656
2220
  };
2657
2221
  var clearSiwxSession = (address, chainId) => {
2658
2222
  const store = storage2();
2659
- if (!store) return;
2223
+ if (!store)
2224
+ return;
2660
2225
  try {
2661
2226
  store.removeItem(buildKey2(address, chainId));
2662
2227
  } catch {
@@ -2719,10 +2284,12 @@ function buildSIWXConfig(deps) {
2719
2284
  const jwt = readSession(address, id);
2720
2285
  const stored = readSiwxSession(address, id);
2721
2286
  if (!jwt) {
2722
- if (stored) clearSiwxSession(address, id);
2287
+ if (stored)
2288
+ clearSiwxSession(address, id);
2723
2289
  return [];
2724
2290
  }
2725
- if (!stored) return [];
2291
+ if (!stored)
2292
+ return [];
2726
2293
  const session = {
2727
2294
  // `stored.data.chainId` is a plain string in the cache (kept AppKit-free);
2728
2295
  // it always holds a valid CaipNetworkId here, so narrow at the boundary.