@owney/sdk 0.6.6-beta.1 → 0.6.6-beta.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/dist/index.cjs CHANGED
@@ -3,9 +3,6 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __esm = (fn, res) => function __init() {
7
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
- };
9
6
  var __export = (target, all) => {
10
7
  for (var name in all)
11
8
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -20,486 +17,9 @@ var __copyProps = (to, from, except, desc) => {
20
17
  };
21
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
19
 
23
- // src/errors.ts
24
- var OwneyError, AgentNotFoundError, NotConnectedError, AgentChainIncompatibleError;
25
- var init_errors = __esm({
26
- "src/errors.ts"() {
27
- "use strict";
28
- OwneyError = class extends Error {
29
- code;
30
- details;
31
- agentId;
32
- constructor(code, message, details, agentId) {
33
- const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
34
- super(`${prefix} ${message}`);
35
- this.name = "OwneyError";
36
- this.code = code;
37
- this.details = details;
38
- this.agentId = agentId;
39
- }
40
- };
41
- AgentNotFoundError = class extends OwneyError {
42
- constructor(agentId, available) {
43
- super(
44
- "AGENT_NOT_FOUND",
45
- `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
46
- { agentId, available },
47
- agentId
48
- );
49
- this.name = "AgentNotFoundError";
50
- }
51
- };
52
- NotConnectedError = class extends OwneyError {
53
- constructor() {
54
- super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
55
- this.name = "NotConnectedError";
56
- }
57
- };
58
- AgentChainIncompatibleError = class extends OwneyError {
59
- incompatibleAgents;
60
- connectedChainId;
61
- constructor(incompatibleAgents, connectedChainId) {
62
- const details = incompatibleAgents.map(
63
- ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
64
- ).join("; ");
65
- super(
66
- "AGENT_CHAIN_INCOMPATIBLE",
67
- `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
68
- { incompatibleAgents, connectedChainId }
69
- );
70
- this.name = "AgentChainIncompatibleError";
71
- this.incompatibleAgents = incompatibleAgents;
72
- this.connectedChainId = connectedChainId;
73
- }
74
- };
75
- }
76
- });
77
-
78
- // src/agents/surfliquid/surfliquid.constants.ts
79
- var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_USDC_DECIMALS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
80
- var init_surfliquid_constants = __esm({
81
- "src/agents/surfliquid/surfliquid.constants.ts"() {
82
- "use strict";
83
- SURFLIQUID_CHAIN_ID = 8453;
84
- SURFLIQUID_CHAIN_NAME = "BASE";
85
- SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
86
- SURFLIQUID_USDC_DECIMALS = 6;
87
- SURFLIQUID_MIN_DEPOSIT = "0";
88
- SURFLIQUID_SUPPORTED_ASSETS = [
89
- {
90
- chainId: SURFLIQUID_CHAIN_ID,
91
- chain: SURFLIQUID_CHAIN_NAME,
92
- assets: [{ symbol: "USDC", minDepositAmount: SURFLIQUID_MIN_DEPOSIT }]
93
- }
94
- ];
95
- SURFLIQUID_ACTION_MAP = {
96
- // INITIAL_DEPOSIT is the user's real first deposit, so surface it like any
97
- // other funding ("Top up"). The mini-app intentionally hides the "Deposit"
98
- // action (it marks Zyfai's smart-account-creation event), which would
99
- // otherwise drop a SurfLiquid user's only history row.
100
- INITIAL_DEPOSIT: "Top up",
101
- DEPOSIT: "Top up",
102
- USER_DEPOSIT: "Top up",
103
- WITHDRAWAL: "Withdraw",
104
- USER_WITHDRAWAL: "Withdraw",
105
- REBALANCE: "Rebalance",
106
- REBALANCE_COMPLETED: "Rebalance",
107
- CROSS_CHAIN_REBALANCE: "Rebalance",
108
- MERKL_CLAIM: "Earned"
109
- };
110
- }
111
- });
112
-
113
- // src/agents/surfliquid/surfliquid.mapper.ts
114
- function mapMessage(message) {
115
- const action = SURFLIQUID_ACTION_MAP[message.transactionType];
116
- if (!action)
117
- return null;
118
- return {
119
- agent: "surfliquid",
120
- action,
121
- date: message.timestamp,
122
- oldApy: message.apyBefore != null ? String(message.apyBefore) : null,
123
- newApy: message.apyAfter != null ? String(message.apyAfter) : null,
124
- transactions: [
125
- {
126
- txHashes: [message.txHash],
127
- chainId: message.chainId,
128
- tokenSymbol: message.token ?? void 0,
129
- amount: message.amount != null ? String(message.amount) : void 0
130
- }
131
- ],
132
- rebalanceLog: []
133
- };
134
- }
135
- function mapHistory(result, _chainId) {
136
- const data = result.messages.map(mapMessage).filter((entry) => entry !== null);
137
- const hasMore = result.page < result.pages;
138
- return {
139
- data,
140
- hasMore,
141
- nextCursor: hasMore ? String(result.page + 1) : void 0
142
- };
143
- }
144
- function mapBalances2(vault, chainId, morphoStats) {
145
- const assets = (vault.assets ?? []).filter(
146
- (asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId
147
- );
148
- const tokens = assets.map((asset) => ({
149
- chain: SURFLIQUID_CHAIN_NAME,
150
- chainId: SURFLIQUID_CHAIN_ID,
151
- asset: "USDC",
152
- amount: String(asset.currentValueUSD)
153
- }));
154
- const positions = assets.map((asset) => {
155
- const stats = morphoStats?.get(asset.morphoVaultAddress?.toLowerCase() ?? "");
156
- return {
157
- chain: SURFLIQUID_CHAIN_NAME,
158
- protocol: "Morpho",
159
- // The specific MetaMorpho vault (e.g. "Gauntlet USDC Frontier"), read from
160
- // Morpho — renders as "Morpho <vault>" alongside zyfai's vault detail.
161
- pool: stats?.name ?? void 0,
162
- asset: "USDC",
163
- amount: String(asset.currentValueUSD),
164
- apy: asset.currentAPY,
165
- // TVL + liquidity come straight from Morpho (SurfLiquid's API omits them).
166
- tvl: stats?.tvlUsd,
167
- liquidity: stats?.liquidityUsd
168
- };
169
- });
170
- const total = assets.reduce(
171
- (sum, asset) => sum + asset.currentValueUSD,
172
- 0
173
- );
174
- return {
175
- smartWallet: vault.userVaultAddress ?? void 0,
176
- totalBalance: String(total),
177
- totalBalanceAsset: "usdc",
178
- tokens,
179
- positions
180
- };
181
- }
182
- function mapAccountApy(vault, days) {
183
- const breakdown = vault.apyBreakdown;
184
- const windowed = breakdown ? breakdown[APY_WINDOW_KEY[days]] : void 0;
185
- const apy = windowed != null ? windowed : breakdown?.currentAPY ?? 0;
186
- return {
187
- walletAddress: vault.walletAddress ?? "",
188
- weightedApyAfterFee: apy,
189
- apyByChainAndAsset: { [SURFLIQUID_CHAIN_ID]: { USDC: apy } },
190
- // Parity with Sail: SurfLiquid's core-sdk exposes no daily net-APY series.
191
- history: []
192
- };
193
- }
194
- function mapEarnings2(vault, vaultAddress) {
195
- return {
196
- smartWallet: vaultAddress,
197
- lifetimeEarnings: vault.earned?.totalEarningsUSD ?? 0,
198
- tokens: []
199
- };
200
- }
201
- function mapUserProfile2(vault, address) {
202
- return {
203
- address,
204
- smartWallet: vault.userVaultAddress ?? "",
205
- chains: [SURFLIQUID_CHAIN_ID],
206
- // SurfLiquid uses cookie-based session auth — no session-key concept.
207
- hasActiveSessionKey: false,
208
- protocols: ["SurfLiquid"]
209
- };
210
- }
211
- var APY_WINDOW_KEY;
212
- var init_surfliquid_mapper = __esm({
213
- "src/agents/surfliquid/surfliquid.mapper.ts"() {
214
- "use strict";
215
- init_surfliquid_constants();
216
- APY_WINDOW_KEY = {
217
- "7D": "apy7d",
218
- "14D": "apy14d",
219
- "30D": "apy30d"
220
- };
221
- }
222
- });
223
-
224
- // src/agents/surfliquid/surfliquid.wallet-adapter.ts
225
- var import_core_sdk, OwneyWalletAdapter;
226
- var init_surfliquid_wallet_adapter = __esm({
227
- "src/agents/surfliquid/surfliquid.wallet-adapter.ts"() {
228
- "use strict";
229
- import_core_sdk = require("@surf_liquid/core-sdk");
230
- OwneyWalletAdapter = class extends import_core_sdk.BaseWalletAdapter {
231
- constructor(eip1193Provider) {
232
- super();
233
- this.eip1193Provider = eip1193Provider;
234
- }
235
- name = "owney";
236
- get installed() {
237
- return true;
238
- }
239
- resolveProvider() {
240
- return this.eip1193Provider;
241
- }
242
- };
243
- }
244
- });
245
-
246
- // src/agents/surfliquid/surfliquid.morpho.ts
247
- async function fetchMorphoVaultStats(vaultAddress, chainId) {
248
- try {
249
- const res = await fetch(MORPHO_API_URL, {
250
- method: "POST",
251
- headers: { "Content-Type": "application/json" },
252
- body: JSON.stringify({
253
- query: VAULT_STATS_QUERY,
254
- variables: { address: vaultAddress, chainId }
255
- })
256
- });
257
- if (!res.ok)
258
- return null;
259
- const json = await res.json();
260
- if (json.errors)
261
- return null;
262
- const vault = json.data?.vaultByAddress;
263
- const tvlUsd = vault?.state?.totalAssetsUsd;
264
- const liquidityUsd = vault?.liquidity?.usd;
265
- if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
266
- return null;
267
- }
268
- const name = typeof vault?.name === "string" ? vault.name : null;
269
- return { name, tvlUsd, liquidityUsd };
270
- } catch (error) {
271
- console.warn("surfliquid: Morpho vault stats fetch failed", {
272
- vaultAddress,
273
- chainId,
274
- error
275
- });
276
- return null;
277
- }
278
- }
279
- async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
280
- const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
281
- const entries = await Promise.all(
282
- unique.map(
283
- async (address) => [address, await fetchMorphoVaultStats(address, chainId)]
284
- )
285
- );
286
- const byVault = /* @__PURE__ */ new Map();
287
- for (const [address, stats] of entries) {
288
- if (stats)
289
- byVault.set(address, stats);
290
- }
291
- return byVault;
292
- }
293
- var MORPHO_API_URL, VAULT_STATS_QUERY;
294
- var init_surfliquid_morpho = __esm({
295
- "src/agents/surfliquid/surfliquid.morpho.ts"() {
296
- "use strict";
297
- MORPHO_API_URL = "https://api.morpho.org/graphql";
298
- VAULT_STATS_QUERY = `
299
- query VaultStats($address: String!, $chainId: Int!) {
300
- vaultByAddress(address: $address, chainId: $chainId) {
301
- name
302
- state { totalAssetsUsd }
303
- liquidity { usd }
304
- }
305
- }
306
- `;
307
- }
308
- });
309
-
310
- // src/agents/surfliquid/surfliquid.agent.ts
311
- var surfliquid_agent_exports = {};
312
- __export(surfliquid_agent_exports, {
313
- SurfLiquidAgent: () => SurfLiquidAgent
314
- });
315
- var import_core_sdk2, import_viem4, APY_WINDOW_KEY2, SurfLiquidAgent;
316
- var init_surfliquid_agent = __esm({
317
- "src/agents/surfliquid/surfliquid.agent.ts"() {
318
- "use strict";
319
- import_core_sdk2 = require("@surf_liquid/core-sdk");
320
- import_viem4 = require("viem");
321
- init_errors();
322
- init_surfliquid_constants();
323
- init_surfliquid_mapper();
324
- init_surfliquid_wallet_adapter();
325
- init_surfliquid_morpho();
326
- APY_WINDOW_KEY2 = {
327
- "7D": "apy7d",
328
- "14D": "apy14d",
329
- "30D": "apy30d"
330
- };
331
- SurfLiquidAgent = class {
332
- constructor(config) {
333
- this.config = config;
334
- }
335
- id = "surfliquid";
336
- supportedChainIds = [SURFLIQUID_CHAIN_ID];
337
- supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
338
- surf = null;
339
- connectedAddress = null;
340
- // In-flight connect+auth, shared by concurrent callers to dedupe SIWE.
341
- connectPromise = null;
342
- ensureSurf() {
343
- if (this.surf)
344
- return this.surf;
345
- this.surf = import_core_sdk2.SurfClient.create({
346
- projectName: this.config.projectName,
347
- appId: this.config.appId,
348
- environment: "mainnet",
349
- chainId: SURFLIQUID_CHAIN_ID,
350
- apiBaseUrl: this.config.apiBaseUrl,
351
- rpcUrl: this.config.rpcUrl,
352
- // Let the SDK auto-approve USDC to the vault before depositing.
353
- autoApprove: true
354
- });
355
- return this.surf;
356
- }
357
- /**
358
- * Connects + authenticates the SurfClient against owney's provider. Skips the
359
- * SIWE prompt when already authenticated for this wallet (cookie session).
360
- */
361
- async connect(state) {
362
- const surf = this.ensureSurf();
363
- const sameWallet = this.connectedAddress?.toLowerCase() === state.walletAddress.toLowerCase();
364
- if (sameWallet && surf.getAuthState().authenticated) {
365
- return surf;
366
- }
367
- if (this.connectPromise)
368
- return this.connectPromise;
369
- this.connectPromise = (async () => {
370
- surf.registerWalletAdapter(
371
- "owney",
372
- new OwneyWalletAdapter(state.provider)
373
- );
374
- await surf.connectWallet("owney");
375
- await surf.authenticate();
376
- this.connectedAddress = state.walletAddress;
377
- return surf;
378
- })();
379
- try {
380
- return await this.connectPromise;
381
- } finally {
382
- this.connectPromise = null;
383
- }
384
- }
385
- /**
386
- * Returns the user's vault address, deploying one on first use. SurfLiquid's
387
- * deposit requires the vault to exist, so this must run before depositing.
388
- * Existing vault → returned as-is; otherwise `deployVault()` is sent
389
- * (user-pays) and the freshly deployed address is returned.
390
- */
391
- async resolveVaultAddress(surf, owner) {
392
- const vault = await surf.getVault(owner).catch(() => null);
393
- if (vault?.exists && vault.userVaultAddress) {
394
- return vault.userVaultAddress;
395
- }
396
- const { vaultAddress } = await surf.deployVault();
397
- return vaultAddress;
398
- }
399
- // --- IAgent: lifecycle ---
400
- async disconnect() {
401
- if (this.surf) {
402
- await this.surf.disconnectWallet();
403
- }
404
- this.connectedAddress = null;
405
- }
406
- async activateAgent(state) {
407
- await this.connect(state);
408
- }
409
- // --- IAgent: funds (user-pays; depositCallback intentionally ignored) ---
410
- async deposit(state, _chainId, amount, _depositCallback) {
411
- const surf = await this.connect(state);
412
- const human = (0, import_viem4.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS);
413
- const smartWallet = await this.resolveVaultAddress(
414
- surf,
415
- state.walletAddress
416
- );
417
- const tx = await surf.deposit({
418
- asset: SURFLIQUID_USDC_ADDRESS,
419
- amount: human
420
- });
421
- await tx.wait();
422
- return { txHash: tx.hash, smartWallet, amount };
423
- }
424
- async withdraw(state, _chainId, _token, amount) {
425
- const surf = await this.connect(state);
426
- const human = amount != null ? (0, import_viem4.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS) : void 0;
427
- try {
428
- const tx = await surf.withdraw({
429
- asset: SURFLIQUID_USDC_ADDRESS,
430
- amount: human
431
- });
432
- await tx.wait();
433
- return {
434
- txHash: tx.hash,
435
- type: amount != null ? "partial" : "full",
436
- amount: amount ?? "0"
437
- };
438
- } catch (error) {
439
- throw new OwneyError(
440
- "WITHDRAW_FAILED",
441
- error instanceof Error ? error.message : "SurfLiquid withdraw failed.",
442
- { chainId: SURFLIQUID_CHAIN_ID, amount },
443
- this.id
444
- );
445
- }
446
- }
447
- // --- IAgent: portfolio reads ---
448
- async getBalances(state, chainId) {
449
- const surf = await this.connect(state);
450
- const vault = await surf.getVault(state.walletAddress);
451
- const morphoVaultAddresses = (vault.assets ?? []).filter((asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId).map((asset) => asset.morphoVaultAddress).filter((address) => Boolean(address));
452
- const morphoStats = await fetchMorphoStatsByVault(
453
- morphoVaultAddresses,
454
- chainId
455
- );
456
- return mapBalances2(vault, chainId, morphoStats);
457
- }
458
- async getEarnings(state) {
459
- const surf = await this.connect(state);
460
- const vault = await surf.getVault(state.walletAddress);
461
- return mapEarnings2(vault, vault.userVaultAddress ?? state.walletAddress);
462
- }
463
- async getAccountApy(state, _chainId, days) {
464
- const surf = await this.connect(state);
465
- const vault = await surf.getVault(state.walletAddress);
466
- return mapAccountApy(vault, days);
467
- }
468
- async getHistory(state, chainId, options) {
469
- const surf = await this.connect(state);
470
- const page = options?.cursor ? Number(options.cursor) : 1;
471
- const limit = options?.limit ?? 10;
472
- const result = await surf.getAgentMessages(
473
- state.walletAddress,
474
- page,
475
- limit,
476
- options?.fromDate,
477
- options?.toDate
478
- );
479
- return mapHistory(result, chainId);
480
- }
481
- async getUserProfile(state) {
482
- const surf = await this.connect(state);
483
- const vault = await surf.getVault(state.walletAddress);
484
- return mapUserProfile2(vault, state.walletAddress);
485
- }
486
- // --- IAgent: discovery (no wallet) ---
487
- async getAgentApy(days, _options) {
488
- const surf = this.ensureSurf();
489
- const assets = await surf.getSupportedAssets(SURFLIQUID_CHAIN_ID);
490
- const usdc = assets.find((asset) => asset.assetSymbol === "USDC");
491
- if (!usdc)
492
- return { averageApy: 0 };
493
- const windowed = usdc[APY_WINDOW_KEY2[days]];
494
- return { averageApy: windowed != null ? windowed : usdc.currentAPY };
495
- }
496
- };
497
- }
498
- });
499
-
500
20
  // src/index.ts
501
- var src_exports = {};
502
- __export(src_exports, {
21
+ var index_exports = {};
22
+ __export(index_exports, {
503
23
  AgentChainIncompatibleError: () => AgentChainIncompatibleError,
504
24
  AgentNotFoundError: () => AgentNotFoundError,
505
25
  InvalidHistoryCursorError: () => InvalidHistoryCursorError,
@@ -508,7 +28,7 @@ __export(src_exports, {
508
28
  OwneySDK: () => OwneySDK,
509
29
  createOwneySIWX: () => createOwneySIWX
510
30
  });
511
- module.exports = __toCommonJS(src_exports);
31
+ module.exports = __toCommonJS(index_exports);
512
32
 
513
33
  // src/agents/zyfai/zyfai.agent.ts
514
34
  var import_sdk = require("@zyfai/sdk");
@@ -517,10 +37,10 @@ var import_chains = require("viem/chains");
517
37
 
518
38
  // src/types/config.ts
519
39
  var P_SUPPORTED_CHAINS = {
520
- chainIds: [8453, 42161],
521
- chains: ["BASE", "ARBITRUM"]
40
+ chainIds: [8453, 42161, 1],
41
+ chains: ["BASE", "ARBITRUM", "ETHEREUM"]
522
42
  };
523
- var SUPPORTED_TOKENS = ["USDC", "USDT"];
43
+ var SUPPORTED_TOKENS = ["USDC", "USDT", "WETH"];
524
44
  var SUPPORTED_CHAIN_IDS = P_SUPPORTED_CHAINS.chainIds;
525
45
  var SUPPORTED_CHAINS = P_SUPPORTED_CHAINS.chains;
526
46
  var SupportedAssets = [
@@ -541,11 +61,83 @@ var SupportedAssets = [
541
61
  symbol: "USDT",
542
62
  chainId: 42161,
543
63
  decimals: 6
64
+ },
65
+ {
66
+ address: `0x4200000000000000000000000000000000000006`,
67
+ symbol: "WETH",
68
+ chainId: 8453,
69
+ decimals: 18
70
+ },
71
+ {
72
+ address: `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1`,
73
+ symbol: "WETH",
74
+ chainId: 42161,
75
+ decimals: 18
76
+ },
77
+ {
78
+ address: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`,
79
+ symbol: "USDC",
80
+ chainId: 1,
81
+ decimals: 6
82
+ },
83
+ {
84
+ address: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`,
85
+ symbol: "WETH",
86
+ chainId: 1,
87
+ decimals: 18
544
88
  }
545
89
  ];
546
90
 
91
+ // src/errors.ts
92
+ var OwneyError = class extends Error {
93
+ code;
94
+ details;
95
+ agentId;
96
+ constructor(code, message, details, agentId) {
97
+ const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
98
+ super(`${prefix} ${message}`);
99
+ this.name = "OwneyError";
100
+ this.code = code;
101
+ this.details = details;
102
+ this.agentId = agentId;
103
+ }
104
+ };
105
+ var AgentNotFoundError = class extends OwneyError {
106
+ constructor(agentId, available) {
107
+ super(
108
+ "AGENT_NOT_FOUND",
109
+ `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
110
+ { agentId, available },
111
+ agentId
112
+ );
113
+ this.name = "AgentNotFoundError";
114
+ }
115
+ };
116
+ var NotConnectedError = class extends OwneyError {
117
+ constructor() {
118
+ super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
119
+ this.name = "NotConnectedError";
120
+ }
121
+ };
122
+ var AgentChainIncompatibleError = class extends OwneyError {
123
+ incompatibleAgents;
124
+ connectedChainId;
125
+ constructor(incompatibleAgents, connectedChainId) {
126
+ const details = incompatibleAgents.map(
127
+ ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
128
+ ).join("; ");
129
+ super(
130
+ "AGENT_CHAIN_INCOMPATIBLE",
131
+ `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
132
+ { incompatibleAgents, connectedChainId }
133
+ );
134
+ this.name = "AgentChainIncompatibleError";
135
+ this.incompatibleAgents = incompatibleAgents;
136
+ this.connectedChainId = connectedChainId;
137
+ }
138
+ };
139
+
547
140
  // src/lib/utils.ts
548
- init_errors();
549
141
  var isValidChainId = (chainId) => {
550
142
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
551
143
  throw new OwneyError(
@@ -559,8 +151,7 @@ var isValidChainId = (chainId) => {
559
151
  function hexToDecimal(hex, decimals = 6) {
560
152
  const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
561
153
  const parsed = BigInt(normalized);
562
- if (decimals <= 0)
563
- return Number(parsed);
154
+ if (decimals <= 0) return Number(parsed);
564
155
  const divisor = BigInt(10 ** decimals);
565
156
  const whole = parsed / divisor;
566
157
  const remainder = parsed % divisor;
@@ -573,6 +164,20 @@ var DayFilterMapping = {
573
164
  };
574
165
 
575
166
  // src/agents/zyfai/zyfai.mapper.ts
167
+ var DECIMALS_BY_SYMBOL = {
168
+ usdc: 6,
169
+ usdt: 6,
170
+ weth: 18,
171
+ eth: 18,
172
+ cbeth: 18,
173
+ wbtc: 8,
174
+ cbbtc: 8
175
+ };
176
+ function tokenDecimals(symbol, explicit) {
177
+ if (typeof explicit === "number" && Number.isFinite(explicit))
178
+ return explicit;
179
+ return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
180
+ }
576
181
  function mapDeposit(raw) {
577
182
  return {
578
183
  txHash: raw.txHash,
@@ -589,7 +194,8 @@ function mapWithdraw(raw) {
589
194
  }
590
195
  var CHAIN_ID_TO_NAME = {
591
196
  8453: "BASE",
592
- 42161: "ARBITRUM"
197
+ 42161: "ARBITRUM",
198
+ 1: "ETHEREUM"
593
199
  };
594
200
  var NAME_TO_CHAIN_ID = Object.entries(
595
201
  CHAIN_ID_TO_NAME
@@ -599,54 +205,52 @@ var NAME_TO_CHAIN_ID = Object.entries(
599
205
  }, {});
600
206
  function resolveChainId(chain) {
601
207
  const asNum = Number(chain);
602
- if (Number.isFinite(asNum) && asNum > 0)
603
- return asNum;
208
+ if (Number.isFinite(asNum) && asNum > 0) return asNum;
604
209
  return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
605
210
  }
606
211
  function mapBalances(raw, _chainId, smartWallet) {
607
212
  const portfolio = raw.portfolio;
608
213
  const portfolioByChain = portfolio.portfolioByChain ?? {};
609
- const rawPositions = portfolio.positions ?? [];
610
- const detailByKey = /* @__PURE__ */ new Map();
611
- for (const p of rawPositions) {
612
- const cid = resolveChainId(p.chain ?? "");
613
- const symbol = (p.token_symbol ?? "").toUpperCase();
614
- if (Number.isFinite(cid) && symbol)
615
- detailByKey.set(`${cid}:${symbol}`, p);
616
- }
617
214
  let totalBalance = 0;
618
215
  const tokens = [];
619
- const positions = [];
620
216
  for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
621
217
  const positionChainId = Number(chainIdKey);
622
- const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
623
218
  for (const [symbol, { balance, decimals }] of Object.entries(
624
219
  tokensBySymbol ?? {}
625
220
  )) {
626
221
  const amount = hexToDecimal(balance || "0", decimals);
627
222
  totalBalance += amount;
628
223
  tokens.push({
629
- chain: chainName,
224
+ chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
630
225
  chainId: positionChainId,
631
226
  asset: symbol,
632
227
  amount: String(amount)
633
228
  });
634
- const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
635
- positions.push({
636
- chain: chainName,
637
- protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
638
- protocolId: detail?.protocol_id,
639
- pool: detail?.pool,
640
- asset: symbol,
641
- amount: String(amount),
642
- apy: detail?.pool_apy,
643
- tvl: detail?.pool_tvl,
644
- // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
645
- // structural read keeps it undefined today and auto-populates later.
646
- liquidity: detail?.liquidity
647
- });
648
229
  }
649
230
  }
231
+ const positions = (portfolio.positions ?? []).map((p) => ({
232
+ chain: p.chain ?? "",
233
+ protocol: p.protocol_name ?? p.protocol_id ?? "",
234
+ protocolId: p.protocol_id,
235
+ pool: p.pool,
236
+ asset: p.token_symbol ?? "",
237
+ // Position amount is hex-encoded base units (like the token balances
238
+ // above). `PositionSlot` doesn't type a `decimals` field, but runtime
239
+ // getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
240
+ // when present, otherwise fall back to the per-symbol lookup so
241
+ // non-6-decimal assets like WETH don't render 1e12 too large.
242
+ amount: String(
243
+ hexToDecimal(
244
+ p.amount || "0",
245
+ tokenDecimals(p.token_symbol, p.decimals)
246
+ )
247
+ ),
248
+ apy: p.pool_apy,
249
+ tvl: p.pool_tvl,
250
+ // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
251
+ // structural read keeps it undefined today and auto-populates later.
252
+ liquidity: p.liquidity
253
+ }));
650
254
  return {
651
255
  smartWallet,
652
256
  totalBalance: String(totalBalance),
@@ -685,41 +289,39 @@ function mapEarnings(raw, smartWallet) {
685
289
  };
686
290
  }
687
291
  function mapWeightedApyByChain(raw) {
688
- if (!raw)
689
- return void 0;
292
+ if (!raw) return void 0;
690
293
  const out = {};
691
294
  for (const [chainKey, tokenApy] of Object.entries(raw)) {
692
295
  const chainId = Number(chainKey);
693
- if (!SUPPORTED_CHAIN_IDS.includes(chainId))
694
- continue;
296
+ if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
695
297
  const perAsset = {};
696
298
  for (const [symbol, apy] of Object.entries(tokenApy)) {
697
299
  const token = symbol;
698
- if (!SUPPORTED_TOKENS.includes(token))
699
- continue;
300
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
700
301
  perAsset[token] = apy;
701
302
  }
702
- if (Object.keys(perAsset).length > 0)
703
- out[chainId] = perAsset;
303
+ if (Object.keys(perAsset).length > 0) out[chainId] = perAsset;
704
304
  }
705
305
  return Object.keys(out).length > 0 ? out : void 0;
706
306
  }
707
- function rawPoolApyForChain(entry, chainId) {
307
+ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
708
308
  let weightedSum = 0;
709
309
  let totalBalance = 0;
710
310
  for (const p of entry.positions ?? []) {
711
- if (p.chainId !== chainId)
712
- continue;
311
+ if (p.chainId !== chainId) continue;
312
+ if (tokenSymbol && p.tokenSymbol !== tokenSymbol) continue;
713
313
  const balance = p.balance ?? 0;
714
- if (balance <= 0 || typeof p.apy !== "number")
715
- continue;
314
+ if (balance <= 0 || typeof p.apy !== "number") continue;
716
315
  weightedSum += p.apy * balance;
717
316
  totalBalance += balance;
718
317
  }
719
318
  return totalBalance > 0 ? weightedSum / totalBalance : null;
720
319
  }
721
- function mapApyHistory(raw, chainId) {
722
- 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));
320
+ function mapApyHistory(raw, chainId, tokenSymbol) {
321
+ const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
322
+ date,
323
+ apy: rawPoolApyForChain(entry, chainId, tokenSymbol)
324
+ })).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
723
325
  return {
724
326
  walletAddress: raw.walletAddress,
725
327
  weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
@@ -742,6 +344,7 @@ function mapEntries(rawEntries, chainId) {
742
344
  "Withdraw from protocol": "Withdraw",
743
345
  Rebalance: "Rebalance"
744
346
  };
347
+ void chainId;
745
348
  return rawEntries.map((entry) => {
746
349
  const rawLog = entry.rebalanceLog;
747
350
  const positions = entry.positions ?? [];
@@ -763,7 +366,15 @@ function mapEntries(rawEntries, chainId) {
763
366
  fromPool: from.pool,
764
367
  toPool: to.pool,
765
368
  tokenSymbol: matched?.token_symbol ?? "",
766
- amount: matched ? String(hexToDecimal(matched.amount || "0x")) : "",
369
+ amount: matched ? String(
370
+ hexToDecimal(
371
+ matched.amount || "0x",
372
+ tokenDecimals(
373
+ matched.token_symbol,
374
+ matched.decimals
375
+ )
376
+ )
377
+ ) : "",
767
378
  status: "success"
768
379
  }
769
380
  ];
@@ -782,7 +393,12 @@ function mapEntries(rawEntries, chainId) {
782
393
  txHashes: entry.transactionHash ? [entry.transactionHash] : [],
783
394
  chainId: entry.chainId,
784
395
  tokenSymbol: entry?.positions?.[0]?.token_symbol,
785
- amount: hasAmount ? String(hexToDecimal(rawAmount)) : void 0
396
+ amount: hasAmount ? String(
397
+ hexToDecimal(
398
+ rawAmount,
399
+ tokenDecimals(entry?.positions?.[0]?.token_symbol)
400
+ )
401
+ ) : void 0
786
402
  }
787
403
  ],
788
404
  rebalanceLog
@@ -807,8 +423,7 @@ function mapApyByStrategy(raw) {
807
423
  const supported = SupportedAssets.find(
808
424
  (asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
809
425
  );
810
- if (!supported)
811
- continue;
426
+ if (!supported) continue;
812
427
  const chainKey = supported.chainId;
813
428
  const symbolKey = supported.symbol;
814
429
  const bucket = apyPerAsset[chainKey] ?? {};
@@ -838,10 +453,8 @@ function computeAllocationApy(positions) {
838
453
  totalValue += value;
839
454
  const chainId = resolveChainId(p.chain);
840
455
  const token = p.asset;
841
- if (!SUPPORTED_CHAIN_IDS.includes(chainId))
842
- continue;
843
- if (!SUPPORTED_TOKENS.includes(token))
844
- continue;
456
+ if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
457
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
845
458
  const perAsset = buckets[chainId] ?? {};
846
459
  const cell = perAsset[token] ?? { weightedSum: 0, value: 0 };
847
460
  cell.weightedSum += apy * value;
@@ -858,8 +471,7 @@ function computeAllocationApy(positions) {
858
471
  out[token] = cell.weightedSum / cell.value;
859
472
  }
860
473
  }
861
- if (Object.keys(out).length > 0)
862
- apyByChainAndAsset[chainId] = out;
474
+ if (Object.keys(out).length > 0) apyByChainAndAsset[chainId] = out;
863
475
  }
864
476
  const totalApy = totalValue > 0 ? String(weightedSum / totalValue) : "0";
865
477
  return { totalApy, apyByChainAndAsset };
@@ -876,19 +488,14 @@ function extractWithdrawnAmount(logs, recipient, token, decimals) {
876
488
  let total = 0n;
877
489
  let matched = false;
878
490
  for (const log of logs) {
879
- if (log.address.toLowerCase() !== wantToken)
880
- continue;
881
- if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC)
882
- continue;
883
- if (topicToAddress(log.topics[2]) !== wantRecipient)
884
- continue;
885
- if (!log.data || log.data === "0x")
886
- continue;
491
+ if (log.address.toLowerCase() !== wantToken) continue;
492
+ if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC) continue;
493
+ if (topicToAddress(log.topics[2]) !== wantRecipient) continue;
494
+ if (!log.data || log.data === "0x") continue;
887
495
  total += BigInt(log.data);
888
496
  matched = true;
889
497
  }
890
- if (!matched)
891
- return void 0;
498
+ if (!matched) return void 0;
892
499
  return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
893
500
  }
894
501
 
@@ -904,8 +511,7 @@ function encodeHistoryCursor(payload) {
904
511
  return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
905
512
  }
906
513
  function decodeHistoryCursor(token) {
907
- if (!token)
908
- throw new InvalidHistoryCursorError("Cursor is empty.");
514
+ if (!token) throw new InvalidHistoryCursorError("Cursor is empty.");
909
515
  let parsed;
910
516
  try {
911
517
  const json = Buffer.from(token, "base64").toString("utf8");
@@ -919,14 +525,10 @@ function decodeHistoryCursor(token) {
919
525
  return parsed;
920
526
  }
921
527
 
922
- // src/agents/zyfai/zyfai.agent.ts
923
- init_errors();
924
-
925
528
  // src/agents/zyfai/zyfai.auth-cache.ts
926
529
  var KEY_PREFIX = "owney.zyfai.session";
927
530
  var storage = () => {
928
- if (typeof window === "undefined")
929
- return null;
531
+ if (typeof window === "undefined") return null;
930
532
  try {
931
533
  return window.localStorage;
932
534
  } catch {
@@ -936,15 +538,13 @@ var storage = () => {
936
538
  var buildKey = (address, chainId) => `${KEY_PREFIX}:${address.toLowerCase()}:${chainId}`;
937
539
  var isJwtExpired = (token) => {
938
540
  const parts = token.split(".");
939
- if (parts.length !== 3)
940
- return false;
541
+ if (parts.length !== 3) return false;
941
542
  try {
942
543
  const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
943
544
  const padded = payload + "=".repeat((4 - payload.length % 4) % 4);
944
545
  const decoded = typeof atob === "function" ? atob(padded) : Buffer.from(padded, "base64").toString("utf8");
945
546
  const claims = JSON.parse(decoded);
946
- if (typeof claims.exp !== "number")
947
- return false;
547
+ if (typeof claims.exp !== "number") return false;
948
548
  return Date.now() / 1e3 >= claims.exp - 30;
949
549
  } catch {
950
550
  return false;
@@ -952,11 +552,9 @@ var isJwtExpired = (token) => {
952
552
  };
953
553
  var readSession = (address, chainId) => {
954
554
  const store = storage();
955
- if (!store)
956
- return null;
555
+ if (!store) return null;
957
556
  const raw = store.getItem(buildKey(address, chainId));
958
- if (!raw)
959
- return null;
557
+ if (!raw) return null;
960
558
  try {
961
559
  const parsed = JSON.parse(raw);
962
560
  if (!parsed.token || isJwtExpired(parsed.token)) {
@@ -971,8 +569,7 @@ var readSession = (address, chainId) => {
971
569
  };
972
570
  var writeSession = (address, chainId, session) => {
973
571
  const store = storage();
974
- if (!store)
975
- return;
572
+ if (!store) return;
976
573
  try {
977
574
  store.setItem(buildKey(address, chainId), JSON.stringify(session));
978
575
  } catch {
@@ -980,33 +577,67 @@ var writeSession = (address, chainId, session) => {
980
577
  };
981
578
  var clearSession = (address, chainId) => {
982
579
  const store = storage();
983
- if (!store)
984
- return;
580
+ if (!store) return;
985
581
  try {
986
582
  store.removeItem(buildKey(address, chainId));
987
583
  } catch {
988
584
  }
989
585
  };
990
586
 
587
+ // src/agents/zyfai/autoSelect.ts
588
+ function buildAutoSelectUpdate(current, asset) {
589
+ if (current.autoSelectProtocols === true) return null;
590
+ return {
591
+ asset,
592
+ autoSelectProtocols: true,
593
+ ...current.chains ? { chains: current.chains } : {}
594
+ };
595
+ }
596
+
991
597
  // src/agents/zyfai/zyfai.agent.ts
992
598
  var DEFAULT_ZYFAI_RPC_URLS = {
993
599
  8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
994
- 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
600
+ 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
601
+ 1: "https://eth-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
995
602
  };
996
- var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
603
+ var WETH_ADDRESS_BY_CHAIN = {
604
+ 8453: "0x4200000000000000000000000000000000000006",
605
+ 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
606
+ 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
607
+ };
608
+ var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
997
609
  var ZyfaiAgent = class {
998
610
  id = "zyfai";
999
- supportedChainIds = [8453, 42161];
611
+ supportedChainIds = [8453, 42161, 1];
1000
612
  supportedAssets = [
1001
613
  {
1002
614
  chainId: 8453,
1003
615
  chain: "BASE",
1004
- assets: [{ symbol: "USDC", minDepositAmount: "1500000" }]
616
+ assets: [
617
+ { symbol: "USDC", minDepositAmount: "1500000" },
618
+ { symbol: "WETH", minDepositAmount: "500000000000000" }
619
+ ]
1005
620
  },
1006
621
  {
1007
622
  chainId: 42161,
1008
623
  chain: "ARBITRUM",
1009
- assets: [{ symbol: "USDC", minDepositAmount: "1500000" }]
624
+ assets: [
625
+ { symbol: "USDC", minDepositAmount: "1500000" },
626
+ { symbol: "WETH", minDepositAmount: "500000000000000" }
627
+ ]
628
+ },
629
+ {
630
+ chainId: 1,
631
+ chain: "ETHEREUM",
632
+ // Zyfai enforces per-asset minimum portfolios on Ethereum mainnet, keyed
633
+ // by MIN_PORTFOLIO_BALANCE[1] in @zyfai/sdk. Lowered in @zyfai/sdk@0.2.40.
634
+ // USDC: 100 (100 * 1e6). WETH: 0.005 (5 * 1e15).
635
+ // NOTE: the @zyfai/sdk README claims WETH has no minimum — that's stale;
636
+ // the shipped code enforces 0.005 WETH, so match it or deposits reject on-chain.
637
+ assets: [
638
+ { symbol: "USDC", minDepositAmount: "100000000" },
639
+ { symbol: "WETH", minDepositAmount: "5000000000000000" }
640
+ ]
1010
641
  }
1011
642
  ];
1012
643
  sdk;
@@ -1030,8 +661,7 @@ var ZyfaiAgent = class {
1030
661
  }
1031
662
  getPublicClient(chainId) {
1032
663
  const cached = this.publicClients.get(chainId);
1033
- if (cached)
1034
- return cached;
664
+ if (cached) return cached;
1035
665
  const client = (0, import_viem.createPublicClient)({
1036
666
  chain: VIEM_CHAIN[chainId],
1037
667
  transport: (0, import_viem.http)(this.rpcUrls[chainId])
@@ -1041,33 +671,43 @@ var ZyfaiAgent = class {
1041
671
  }
1042
672
  /**
1043
673
  * Fills in the true withdrawn amount for `Withdraw` entries by decoding the
1044
- * USDC `Transfer` that lands in the user's wallet on-chain. The Zyfai history
674
+ * on-chain `Transfer` that lands in the user's wallet. The Zyfai history
1045
675
  * payload only reports the *remaining* position for a partial withdraw (see
1046
676
  * the note in `mapEntries`), so without this the UI shows the leftover
1047
677
  * balance instead of the amount withdrawn.
1048
678
  *
679
+ * The withdrawn asset varies per entry (USDC or WETH), so it's resolved
680
+ * from `tx.tokenSymbol` (set by `mapEntries` from the entry's own
681
+ * position) rather than assumed to always be USDC. Zyfai sometimes
682
+ * denominates WETH as lowercase "eth" — that's normalized to WETH.
683
+ * Entries with no symbol (older payload shapes) fall back to USDC to
684
+ * preserve prior behavior.
685
+ *
1049
686
  * Mutates `entries` in place. Runs all lookups concurrently and is tolerant
1050
687
  * of RPC failures: an entry whose amount can't be resolved keeps
1051
688
  * `amount: undefined`, which consumers render as a hidden/retryable row
1052
689
  * rather than a wrong number.
1053
690
  */
1054
691
  async resolveWithdrawnAmounts(entries, chainId, recipient) {
1055
- const asset = SupportedAssets.find(
1056
- (a) => a.chainId === chainId && a.symbol === "USDC"
1057
- );
1058
- if (!asset)
1059
- return;
1060
692
  const withdrawals = entries.filter(
1061
693
  (e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
1062
694
  );
1063
- if (withdrawals.length === 0)
1064
- return;
695
+ if (withdrawals.length === 0) return;
1065
696
  const client = this.getPublicClient(chainId);
1066
697
  await Promise.all(
1067
698
  withdrawals.map(async (entry) => {
1068
699
  const tx = entry.transactions[0];
1069
700
  const txHash = tx.txHashes[0];
1070
- const cached = this.withdrawAmountCache.get(txHash);
701
+ const rawSymbol = tx.tokenSymbol;
702
+ const normalizedSymbol = rawSymbol ? rawSymbol.toLowerCase() === "eth" ? "WETH" : rawSymbol.toUpperCase() : "USDC";
703
+ const asset = SupportedAssets.find(
704
+ (a) => a.chainId === chainId && a.symbol === normalizedSymbol
705
+ ) ?? SupportedAssets.find(
706
+ (a) => a.chainId === chainId && a.symbol === "USDC"
707
+ );
708
+ if (!asset) return;
709
+ const cacheKey = `${txHash}:${asset.address}`;
710
+ const cached = this.withdrawAmountCache.get(cacheKey);
1071
711
  if (cached !== void 0) {
1072
712
  tx.amount = cached;
1073
713
  return;
@@ -1083,7 +723,7 @@ var ZyfaiAgent = class {
1083
723
  asset.decimals
1084
724
  );
1085
725
  if (amount !== void 0) {
1086
- this.withdrawAmountCache.set(txHash, amount);
726
+ this.withdrawAmountCache.set(cacheKey, amount);
1087
727
  tx.amount = amount;
1088
728
  }
1089
729
  } catch {
@@ -1102,13 +742,11 @@ var ZyfaiAgent = class {
1102
742
  * for some apps and the patch only matters in the browser anyway.
1103
743
  */
1104
744
  installAuthCache() {
1105
- if (typeof window === "undefined")
1106
- return;
745
+ if (typeof window === "undefined") return;
1107
746
  const internals = this.sdk;
1108
747
  const original = internals.authenticateUser.bind(internals);
1109
748
  internals.authenticateUser = async () => {
1110
- if (internals.authenticatedUserId !== null)
1111
- return;
749
+ if (internals.authenticatedUserId !== null) return;
1112
750
  const address = internals.walletClient?.account?.address;
1113
751
  const chainId = internals.currentChainId;
1114
752
  if (address && chainId) {
@@ -1183,12 +821,10 @@ var ZyfaiAgent = class {
1183
821
  return await this.sdk.connectAccount(provider, chainId);
1184
822
  } catch (error) {
1185
823
  const message = error instanceof Error ? error.message : String(error);
1186
- if (!message.toLowerCase().includes("unauthorized"))
1187
- throw error;
824
+ if (!message.toLowerCase().includes("unauthorized")) throw error;
1188
825
  const internals = this.sdk;
1189
826
  const address = internals.walletClient?.account?.address;
1190
- if (address)
1191
- clearSession(address, chainId);
827
+ if (address) clearSession(address, chainId);
1192
828
  return await this.sdk.connectAccount(provider, chainId);
1193
829
  }
1194
830
  }
@@ -1201,6 +837,22 @@ var ZyfaiAgent = class {
1201
837
  this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
1202
838
  if (!wallet.isDeployed) {
1203
839
  await this.sdk.deploySafe(address, validChainId, "aggressive", true);
840
+ try {
841
+ if (validChainId === 42161) {
842
+ await this.sdk.updateUserProfile({
843
+ asset: "WETH",
844
+ chains: [validChainId],
845
+ protocols: ["c24a33fa-4a87-4376-b756-93bd3957d3ea"],
846
+ // AAVE protocol ID
847
+ autoSelectProtocols: false
848
+ });
849
+ }
850
+ } catch (err) {
851
+ console.warn(
852
+ "Failed to configure AAVE protocol after Safe deployment:",
853
+ err instanceof Error ? err.message : String(err)
854
+ );
855
+ }
1204
856
  }
1205
857
  const user = await this.sdk.getUserDetails();
1206
858
  if (!user.hasActiveSessionKey) {
@@ -1242,7 +894,7 @@ var ZyfaiAgent = class {
1242
894
  throw error;
1243
895
  }
1244
896
  }
1245
- async deposit(state, chainId, amount, depositCallback) {
897
+ async deposit(state, chainId, amount, asset, depositCallback) {
1246
898
  try {
1247
899
  await this.connectFull(state, chainId);
1248
900
  const validChainId = isValidChainId(chainId);
@@ -1256,13 +908,15 @@ var ZyfaiAgent = class {
1256
908
  validChainId,
1257
909
  amount
1258
910
  );
1259
- await this.sdk.logDeposit(validChainId, txHash, amount);
911
+ const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
912
+ await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
1260
913
  return { txHash, smartWallet: wallet.address, amount };
1261
914
  }
1262
915
  const raw = await this.sdk.depositFunds(
1263
916
  this.getAddress(),
1264
917
  validChainId,
1265
- amount
918
+ amount,
919
+ asset
1266
920
  );
1267
921
  return mapDeposit(raw);
1268
922
  } catch (error) {
@@ -1300,10 +954,10 @@ var ZyfaiAgent = class {
1300
954
  const raw = await this.sdk.getOnchainEarnings(smartWallet);
1301
955
  return mapEarnings(raw, smartWallet);
1302
956
  }
1303
- async getAccountApy(state, chainId, days) {
957
+ async getAccountApy(state, chainId, days, tokenSymbol) {
1304
958
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
1305
959
  const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
1306
- return mapApyHistory(raw, chainId);
960
+ return mapApyHistory(raw, chainId, tokenSymbol);
1307
961
  }
1308
962
  async getHistory(state, chainId, options) {
1309
963
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
@@ -1358,6 +1012,20 @@ var ZyfaiAgent = class {
1358
1012
  }
1359
1013
  return mapUserProfile(raw, this.connectedAddress);
1360
1014
  }
1015
+ async ensureAutoSelectProtocols(state, chainId, asset) {
1016
+ await this.connectAuth(state, chainId);
1017
+ const current = await this.sdk.getUserDetails(asset);
1018
+ const update = buildAutoSelectUpdate(
1019
+ {
1020
+ autoSelectProtocols: current.autoSelectProtocols,
1021
+ chains: current.chains
1022
+ },
1023
+ asset
1024
+ );
1025
+ if (!update) return false;
1026
+ await this.sdk.updateUserProfile(update);
1027
+ return true;
1028
+ }
1361
1029
  // --- IAgent: Discovery (no wallet required) ---
1362
1030
  async getAgentApy(days, options) {
1363
1031
  const raw = await this.sdk.getAPYPerStrategy(
@@ -1371,11 +1039,7 @@ var ZyfaiAgent = class {
1371
1039
  }
1372
1040
  };
1373
1041
 
1374
- // src/client.ts
1375
- init_errors();
1376
-
1377
1042
  // src/lib/routing-api.ts
1378
- init_errors();
1379
1043
  var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
1380
1044
  async function fetchAgentKeys(apiKey) {
1381
1045
  const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
@@ -1406,7 +1070,6 @@ async function fetchAgentKeys(apiKey) {
1406
1070
  }
1407
1071
 
1408
1072
  // src/lib/health-report.ts
1409
- init_errors();
1410
1073
  var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
1411
1074
  async function reportAgentFailure(apiKey, agentType, errorCode) {
1412
1075
  try {
@@ -1448,8 +1111,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
1448
1111
  const tokenBalance = agentBalance?.tokens.find(
1449
1112
  (t) => t.chainId === chainId && t.asset.toUpperCase() === target
1450
1113
  );
1451
- if (!tokenBalance)
1452
- return { agent, balance: 0n };
1114
+ if (!tokenBalance) return { agent, balance: 0n };
1453
1115
  return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
1454
1116
  });
1455
1117
  }
@@ -1466,11 +1128,9 @@ function planProportionalShares(balances, requested, totalAvailable) {
1466
1128
  return diff > 0n ? 1 : diff < 0n ? -1 : 0;
1467
1129
  });
1468
1130
  for (const p of byHeadroom) {
1469
- if (remainder === 0n)
1470
- break;
1131
+ if (remainder === 0n) break;
1471
1132
  const headroom = p.balance - p.planned;
1472
- if (headroom <= 0n)
1473
- continue;
1133
+ if (headroom <= 0n) continue;
1474
1134
  const take = headroom < remainder ? headroom : remainder;
1475
1135
  p.planned += take;
1476
1136
  remainder -= take;
@@ -1499,8 +1159,7 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
1499
1159
  (s, c) => s + (c.balance - c.planned),
1500
1160
  0n
1501
1161
  );
1502
- if (totalHeadroom === 0n)
1503
- return;
1162
+ if (totalHeadroom === 0n) return;
1504
1163
  let distributed = 0n;
1505
1164
  for (const c of candidates) {
1506
1165
  const headroom = c.balance - c.planned;
@@ -1511,11 +1170,9 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
1511
1170
  }
1512
1171
  let leftover = amount - distributed;
1513
1172
  for (const c of candidates) {
1514
- if (leftover === 0n)
1515
- break;
1173
+ if (leftover === 0n) break;
1516
1174
  const headroom = c.balance - c.planned;
1517
- if (headroom <= 0n)
1518
- continue;
1175
+ if (headroom <= 0n) continue;
1519
1176
  const take = headroom < leftover ? headroom : leftover;
1520
1177
  c.planned += take;
1521
1178
  leftover -= take;
@@ -1532,16 +1189,13 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1532
1189
  for (const id of Object.keys(agentApys)) {
1533
1190
  const cells = agentApys[id].apyByChainAndAsset;
1534
1191
  const balance = agentBalances[id] ?? 0;
1535
- if (!cells || balance <= 0)
1536
- continue;
1192
+ if (!cells || balance <= 0) continue;
1537
1193
  for (const [chainKey, perAsset] of Object.entries(cells)) {
1538
- if (!perAsset)
1539
- continue;
1194
+ if (!perAsset) continue;
1540
1195
  const chainId = Number(chainKey);
1541
1196
  for (const [asset, apyValue] of Object.entries(perAsset)) {
1542
1197
  const apy = Number(apyValue ?? 0);
1543
- if (apy === 0)
1544
- continue;
1198
+ if (apy === 0) continue;
1545
1199
  sums[chainId] ??= {};
1546
1200
  weights[chainId] ??= {};
1547
1201
  sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
@@ -1555,8 +1209,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1555
1209
  const perAssetOut = {};
1556
1210
  for (const asset of Object.keys(sums[chainId])) {
1557
1211
  const w = weights[chainId][asset];
1558
- if (w > 0)
1559
- perAssetOut[asset] = sums[chainId][asset] / w;
1212
+ if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
1560
1213
  }
1561
1214
  if (Object.keys(perAssetOut).length > 0) {
1562
1215
  out[chainId] = perAssetOut;
@@ -1569,9 +1222,6 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1569
1222
  var import_viem5 = require("viem");
1570
1223
  var import_chains2 = require("viem/chains");
1571
1224
 
1572
- // src/lib/sponsored-deposit.ts
1573
- init_errors();
1574
-
1575
1225
  // src/lib/transfer-auth.ts
1576
1226
  var import_viem3 = require("viem");
1577
1227
  var ERC20_META_ABI = [
@@ -1609,7 +1259,6 @@ function randomAuthNonce() {
1609
1259
  }
1610
1260
 
1611
1261
  // src/lib/sponsor-client.ts
1612
- init_errors();
1613
1262
  var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
1614
1263
  async function postSponsorTransferAuth(input) {
1615
1264
  const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
@@ -1617,7 +1266,10 @@ async function postSponsorTransferAuth(input) {
1617
1266
  try {
1618
1267
  res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
1619
1268
  method: "POST",
1620
- headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
1269
+ headers: {
1270
+ "content-type": "application/json",
1271
+ "x-owney-api-key": input.apiKey
1272
+ },
1621
1273
  body: JSON.stringify(input.body)
1622
1274
  });
1623
1275
  } catch (networkError) {
@@ -1637,11 +1289,91 @@ async function postSponsorTransferAuth(input) {
1637
1289
  throw new OwneyError(
1638
1290
  "SPONSOR_REQUEST_FAILED",
1639
1291
  `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1640
- { statusCode: res.status, responseBody: text.slice(0, 500) }
1292
+ {
1293
+ statusCode: res.status,
1294
+ responseBody: text.slice(0, 500),
1295
+ // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
1296
+ // before broadcast, so it is safe to fall back to a user-paid deposit.
1297
+ safeToFallback: res.status === 503
1298
+ }
1641
1299
  );
1642
1300
  }
1643
1301
  return parsed.data;
1644
1302
  }
1303
+ async function postSponsorPermit2Transfer(input) {
1304
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1305
+ let res;
1306
+ try {
1307
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
1308
+ method: "POST",
1309
+ headers: {
1310
+ "content-type": "application/json",
1311
+ "x-owney-api-key": input.apiKey
1312
+ },
1313
+ body: JSON.stringify(input.body)
1314
+ });
1315
+ } catch (networkError) {
1316
+ throw new OwneyError(
1317
+ "SPONSOR_REQUEST_FAILED",
1318
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
1319
+ { cause: String(networkError), safeToFallback: false }
1320
+ );
1321
+ }
1322
+ const text = await res.text();
1323
+ let parsed = null;
1324
+ try {
1325
+ parsed = JSON.parse(text);
1326
+ } catch {
1327
+ }
1328
+ if (!res.ok || !parsed?.success || !parsed.data) {
1329
+ throw new OwneyError(
1330
+ "SPONSOR_REQUEST_FAILED",
1331
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1332
+ {
1333
+ statusCode: res.status,
1334
+ responseBody: text.slice(0, 500),
1335
+ safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
1336
+ }
1337
+ );
1338
+ }
1339
+ return parsed.data;
1340
+ }
1341
+ async function getSponsorRelayerAddress(input) {
1342
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1343
+ let res;
1344
+ try {
1345
+ res = await fetch(
1346
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
1347
+ {
1348
+ headers: { "x-owney-api-key": input.apiKey }
1349
+ }
1350
+ );
1351
+ } catch (networkError) {
1352
+ throw new OwneyError(
1353
+ "SPONSOR_REQUEST_FAILED",
1354
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
1355
+ { cause: String(networkError), safeToFallback: true }
1356
+ );
1357
+ }
1358
+ const text = await res.text();
1359
+ let parsed = null;
1360
+ try {
1361
+ parsed = JSON.parse(text);
1362
+ } catch {
1363
+ }
1364
+ if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
1365
+ throw new OwneyError(
1366
+ "SPONSOR_REQUEST_FAILED",
1367
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1368
+ {
1369
+ statusCode: res.status,
1370
+ responseBody: text.slice(0, 500),
1371
+ safeToFallback: true
1372
+ }
1373
+ );
1374
+ }
1375
+ return parsed.data.relayer;
1376
+ }
1645
1377
 
1646
1378
  // src/lib/sponsored-deposit.ts
1647
1379
  var AUTH_WINDOW_SECONDS = 15 * 60;
@@ -1693,6 +1425,114 @@ function makeSponsoredDepositCallback(deps) {
1693
1425
  };
1694
1426
  }
1695
1427
 
1428
+ // src/lib/permit2.ts
1429
+ var import_viem4 = require("viem");
1430
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
1431
+ var MAX_UINT256 = 2n ** 256n - 1n;
1432
+ var ERC20_ALLOWANCE_ABI = [
1433
+ {
1434
+ type: "function",
1435
+ name: "allowance",
1436
+ stateMutability: "view",
1437
+ inputs: [{ name: "owner", type: "address" }, { name: "spender", type: "address" }],
1438
+ outputs: [{ name: "", type: "uint256" }]
1439
+ },
1440
+ {
1441
+ type: "function",
1442
+ name: "approve",
1443
+ stateMutability: "nonpayable",
1444
+ inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }],
1445
+ outputs: [{ name: "", type: "bool" }]
1446
+ }
1447
+ ];
1448
+ function buildPermitTransferFromTypedData(input) {
1449
+ return {
1450
+ domain: { name: "Permit2", chainId: input.chainId, verifyingContract: PERMIT2_ADDRESS },
1451
+ types: {
1452
+ PermitTransferFrom: [
1453
+ { name: "permitted", type: "TokenPermissions" },
1454
+ { name: "spender", type: "address" },
1455
+ { name: "nonce", type: "uint256" },
1456
+ { name: "deadline", type: "uint256" }
1457
+ ],
1458
+ TokenPermissions: [
1459
+ { name: "token", type: "address" },
1460
+ { name: "amount", type: "uint256" }
1461
+ ]
1462
+ },
1463
+ primaryType: "PermitTransferFrom",
1464
+ message: input.message
1465
+ };
1466
+ }
1467
+ function randomPermit2Nonce() {
1468
+ const bytes = new Uint8Array(32);
1469
+ globalThis.crypto.getRandomValues(bytes);
1470
+ return BigInt((0, import_viem4.bytesToHex)(bytes));
1471
+ }
1472
+ async function readPermit2Allowance(publicClient, token, owner) {
1473
+ return publicClient.readContract({
1474
+ address: token,
1475
+ abi: ERC20_ALLOWANCE_ABI,
1476
+ functionName: "allowance",
1477
+ args: [owner, PERMIT2_ADDRESS]
1478
+ });
1479
+ }
1480
+
1481
+ // src/lib/sponsored-weth-deposit.ts
1482
+ var PERMIT_WINDOW_SECONDS = 15 * 60;
1483
+ function makeSponsoredWethCallback(deps) {
1484
+ const get = deps.httpGet ?? getSponsorRelayerAddress;
1485
+ const post = deps.httpPost ?? postSponsorPermit2Transfer;
1486
+ return async (smartWallet, chainId, amount) => {
1487
+ const cid = chainId;
1488
+ const token = deps.tokenAddressByChain[cid];
1489
+ if (!token) {
1490
+ throw new OwneyError("CHAIN_UNSUPPORTED", `No sponsored WETH configured for chain ${chainId}`);
1491
+ }
1492
+ const amountWei = BigInt(amount);
1493
+ const pub = deps.getPublicClient(cid);
1494
+ const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
1495
+ if (allowance < amountWei) {
1496
+ throw new OwneyError(
1497
+ "PERMIT2_APPROVAL_REQUIRED",
1498
+ "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
1499
+ { token, chainId: cid, allowance: allowance.toString(), amount }
1500
+ );
1501
+ }
1502
+ const relayer = await get({ baseUrl: deps.baseUrl, apiKey: deps.apiKey, chainId: cid });
1503
+ const nonce = randomPermit2Nonce();
1504
+ const deadline = BigInt(Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS);
1505
+ const typedData = buildPermitTransferFromTypedData({
1506
+ chainId: cid,
1507
+ message: {
1508
+ permitted: { token, amount: amountWei },
1509
+ spender: relayer,
1510
+ nonce,
1511
+ deadline
1512
+ }
1513
+ });
1514
+ const wallet = deps.getWalletClient(cid);
1515
+ const signature = await wallet.signTypedData(
1516
+ { account: deps.ownerAddress, ...typedData }
1517
+ );
1518
+ const result = await post({
1519
+ baseUrl: deps.baseUrl,
1520
+ apiKey: deps.apiKey,
1521
+ body: {
1522
+ chainId: cid,
1523
+ token,
1524
+ from: deps.ownerAddress,
1525
+ to: smartWallet,
1526
+ amount,
1527
+ nonce: nonce.toString(),
1528
+ deadline: deadline.toString(),
1529
+ signature
1530
+ }
1531
+ });
1532
+ return result.txHash;
1533
+ };
1534
+ }
1535
+
1696
1536
  // src/client.ts
1697
1537
  function encodeMultiAgentCursor(map) {
1698
1538
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
@@ -1716,13 +1556,22 @@ function decodeMultiAgentCursor(token) {
1716
1556
  }
1717
1557
  var SPONSORED_USDC_BY_CHAIN = {
1718
1558
  8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1719
- 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
1559
+ 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
1560
+ 1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
1720
1561
  };
1721
1562
  var VIEM_CHAIN2 = {
1722
1563
  8453: import_chains2.base,
1723
- 42161: import_chains2.arbitrum
1564
+ 42161: import_chains2.arbitrum,
1565
+ 1: import_chains2.mainnet
1566
+ };
1567
+ var SPONSORED_WETH_BY_CHAIN = {
1568
+ 8453: "0x4200000000000000000000000000000000000006",
1569
+ 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
1570
+ 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
1724
1571
  };
1725
- var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
1572
+ function shouldFallbackToUserPaid(error, asset, appCallback) {
1573
+ return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
1574
+ }
1726
1575
  var OwneySDK = class {
1727
1576
  agents = /* @__PURE__ */ new Map();
1728
1577
  activeAgents = /* @__PURE__ */ new Set();
@@ -1735,11 +1584,14 @@ var OwneySDK = class {
1735
1584
  state = null;
1736
1585
  apiKey;
1737
1586
  zyfaiRpcUrls;
1587
+ routingApiBaseUrl;
1738
1588
  cachedSponsoredCallback = null;
1589
+ cachedWethSponsoredCallback = null;
1739
1590
  initializingAgentsPromise = null;
1740
1591
  constructor(config) {
1741
1592
  this.apiKey = config.apiKey;
1742
1593
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
1594
+ this.routingApiBaseUrl = config.routingApiBaseUrl;
1743
1595
  }
1744
1596
  /**
1745
1597
  * Establish connection state for all subsequent SDK calls.
@@ -1760,6 +1612,7 @@ var OwneySDK = class {
1760
1612
  }
1761
1613
  this.state = { provider, walletAddress, chainId: null };
1762
1614
  this.cachedSponsoredCallback = null;
1615
+ this.cachedWethSponsoredCallback = null;
1763
1616
  }
1764
1617
  /**
1765
1618
  * Disconnect from all agents and clear connection state.
@@ -1773,6 +1626,7 @@ var OwneySDK = class {
1773
1626
  this.disabledAgents.clear();
1774
1627
  this.state = null;
1775
1628
  this.cachedSponsoredCallback = null;
1629
+ this.cachedWethSponsoredCallback = null;
1776
1630
  }
1777
1631
  isAgentDisabled(agentId) {
1778
1632
  return this.disabledAgents.has(agentId);
@@ -1792,8 +1646,7 @@ var OwneySDK = class {
1792
1646
  return this.state?.chainId ?? null;
1793
1647
  }
1794
1648
  requireState() {
1795
- if (!this.state)
1796
- throw new NotConnectedError();
1649
+ if (!this.state) throw new NotConnectedError();
1797
1650
  return this.state;
1798
1651
  }
1799
1652
  requireChainId() {
@@ -1823,12 +1676,12 @@ var OwneySDK = class {
1823
1676
  * `TransferWithAuthorization`, then POSTs to the sponsor API.
1824
1677
  */
1825
1678
  getDefaultSponsoredCallback() {
1826
- if (this.cachedSponsoredCallback)
1827
- return this.cachedSponsoredCallback;
1679
+ if (this.cachedSponsoredCallback) return this.cachedSponsoredCallback;
1828
1680
  const provider = this.requireConnectedProvider();
1829
1681
  const owner = this.state.walletAddress;
1830
1682
  this.cachedSponsoredCallback = makeSponsoredDepositCallback({
1831
1683
  apiKey: this.apiKey,
1684
+ baseUrl: this.routingApiBaseUrl,
1832
1685
  ownerAddress: owner,
1833
1686
  tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
1834
1687
  // Casts work around viem's chain-narrowed Client vs the generic
@@ -1846,6 +1699,37 @@ var OwneySDK = class {
1846
1699
  });
1847
1700
  return this.cachedSponsoredCallback;
1848
1701
  }
1702
+ /**
1703
+ * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
1704
+ * callback used when the caller omits `depositCallback` for a WETH
1705
+ * deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
1706
+ * `PermitTransferFrom` instead of an EIP-3009 authorization.
1707
+ */
1708
+ getDefaultWethSponsoredCallback() {
1709
+ if (this.cachedWethSponsoredCallback)
1710
+ return this.cachedWethSponsoredCallback;
1711
+ const provider = this.requireConnectedProvider();
1712
+ const owner = this.state.walletAddress;
1713
+ this.cachedWethSponsoredCallback = makeSponsoredWethCallback({
1714
+ apiKey: this.apiKey,
1715
+ baseUrl: this.routingApiBaseUrl,
1716
+ ownerAddress: owner,
1717
+ tokenAddressByChain: SPONSORED_WETH_BY_CHAIN,
1718
+ // Casts work around viem's chain-narrowed Client vs the generic
1719
+ // PublicClient/WalletClient param types — structurally identical at
1720
+ // runtime, but the two share a name TS treats as unrelated.
1721
+ getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
1722
+ chain: VIEM_CHAIN2[cid],
1723
+ transport: (0, import_viem5.custom)(provider)
1724
+ }),
1725
+ getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
1726
+ account: owner,
1727
+ chain: VIEM_CHAIN2[cid],
1728
+ transport: (0, import_viem5.custom)(provider)
1729
+ })
1730
+ });
1731
+ return this.cachedWethSponsoredCallback;
1732
+ }
1849
1733
  getAgent(agentId) {
1850
1734
  const agent = this.agents.get(agentId);
1851
1735
  if (!agent) {
@@ -1857,22 +1741,19 @@ var OwneySDK = class {
1857
1741
  const active = /* @__PURE__ */ new Map();
1858
1742
  for (const id of this.activeAgents) {
1859
1743
  const agent = this.agents.get(id);
1860
- if (agent)
1861
- active.set(id, agent);
1744
+ if (agent) active.set(id, agent);
1862
1745
  }
1863
1746
  return active;
1864
1747
  }
1865
1748
  async ensureAgentsInitialized() {
1866
- if (this.agents.size > 0)
1867
- return;
1749
+ if (this.agents.size > 0) return;
1868
1750
  if (!this.initializingAgentsPromise) {
1869
1751
  this.initializingAgentsPromise = (async () => {
1870
1752
  const agentKeys = await fetchAgentKeys(this.apiKey);
1871
1753
  this.disabledAgents.clear();
1872
- for (const { key, agent_type, project_name, is_enabled } of agentKeys) {
1873
- const agent = await this.createAgent(agent_type, key, project_name);
1874
- if (!agent)
1875
- continue;
1754
+ for (const { key, agent_type, is_enabled } of agentKeys) {
1755
+ const agent = this.createAgent(agent_type, key);
1756
+ if (!agent) continue;
1876
1757
  this.agents.set(agent_type, agent);
1877
1758
  if (is_enabled === false) {
1878
1759
  this.disabledAgents.add(agent_type);
@@ -1892,16 +1773,10 @@ var OwneySDK = class {
1892
1773
  this.initializingAgentsPromise = null;
1893
1774
  }
1894
1775
  }
1895
- async createAgent(agentId, key, projectName) {
1776
+ createAgent(agentId, key) {
1896
1777
  if (agentId === "zyfai") {
1897
1778
  return new ZyfaiAgent(key, this.zyfaiRpcUrls);
1898
1779
  }
1899
- if (agentId === "surfliquid") {
1900
- if (!projectName)
1901
- return null;
1902
- const { SurfLiquidAgent: SurfLiquidAgent2 } = await Promise.resolve().then(() => (init_surfliquid_agent(), surfliquid_agent_exports));
1903
- return new SurfLiquidAgent2({ projectName, appId: key });
1904
- }
1905
1780
  return null;
1906
1781
  }
1907
1782
  // --- Account lifecycle ---
@@ -2005,7 +1880,7 @@ var OwneySDK = class {
2005
1880
  }
2006
1881
  const state = this.requireState();
2007
1882
  const chainId = this.requireChainId();
2008
- const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
1883
+ const effectiveCallback = depositCallback ?? (asset === "WETH" ? this.getDefaultWethSponsoredCallback() : this.getDefaultSponsoredCallback());
2009
1884
  if (agentId) {
2010
1885
  if (this.isAgentDisabled(agentId)) {
2011
1886
  throw new OwneyError(
@@ -2017,10 +1892,14 @@ var OwneySDK = class {
2017
1892
  const agent = this.getAgent(agentId);
2018
1893
  this.validateAssetSupport(agent, chainId, asset);
2019
1894
  await this.validateMinDepositAmount(agent, state, chainId, asset, amount);
2020
- return withFailureReporting(
2021
- this.apiKey,
2022
- agent.id,
2023
- () => agent.deposit(state, chainId, amount, effectiveCallback)
1895
+ return this.depositWithFallback(
1896
+ agent,
1897
+ state,
1898
+ chainId,
1899
+ amount,
1900
+ asset,
1901
+ effectiveCallback,
1902
+ depositCallback
2024
1903
  );
2025
1904
  }
2026
1905
  const totalAmount = BigInt(amount);
@@ -2050,26 +1929,77 @@ var OwneySDK = class {
2050
1929
  );
2051
1930
  }
2052
1931
  const agentResults = {};
2053
- const agentErrors = {};
2054
1932
  for (const { agent, amount: agentAmount } of agentAmounts) {
1933
+ agentResults[agent.id] = await this.depositWithFallback(
1934
+ agent,
1935
+ state,
1936
+ chainId,
1937
+ agentAmount,
1938
+ asset,
1939
+ effectiveCallback,
1940
+ depositCallback
1941
+ );
1942
+ }
1943
+ return { agentResults };
1944
+ }
1945
+ /**
1946
+ * Invokes `agent.deposit` with the resolved sponsored callback, composing
1947
+ * two independent auto-recovery mechanisms:
1948
+ *
1949
+ * 1. Missing Permit2 allowance: when the app did not supply its own
1950
+ * callback and the attempt fails with `PERMIT2_APPROVAL_REQUIRED` on a
1951
+ * WETH deposit, this is the wallet's first gasless WETH deposit. We send
1952
+ * the one-time (user-paid) Permit2 approval via `approvePermit2()` and
1953
+ * retry the SAME sponsored attempt once. Bounded to one approval attempt
1954
+ * per call so a wallet/agent that keeps reporting the allowance as
1955
+ * missing can't loop forever. If `approvePermit2()` itself throws (e.g.
1956
+ * the user rejects the wallet prompt), that error propagates as-is —
1957
+ * the user said no to a transaction, so we must not turn around and ask
1958
+ * them to pay for a different one via the fallback below.
1959
+ * 2. `shouldFallbackToUserPaid`: the SDK's own WETH sponsor path failed at
1960
+ * the infrastructure layer in a provably safe-to-retry way, so we warn
1961
+ * and retry once with `undefined`, falling through to a user-paid
1962
+ * native deposit. This still applies after a successful Permit2
1963
+ * approval retry (the retried sponsored attempt can itself hit a safe
1964
+ * sponsor failure).
1965
+ *
1966
+ * Any other error — an app-supplied callback's own failure in particular —
1967
+ * propagates unchanged. Scoped per agent invocation so one agent's failure
1968
+ * doesn't force a retry of sibling agents in a multi-agent split.
1969
+ */
1970
+ async depositWithFallback(agent, state, chainId, amount, asset, effectiveCallback, appCallback) {
1971
+ const attempt = (callback) => withFailureReporting(
1972
+ this.apiKey,
1973
+ agent.id,
1974
+ () => agent.deposit(
1975
+ state,
1976
+ chainId,
1977
+ amount,
1978
+ asset,
1979
+ callback
1980
+ )
1981
+ );
1982
+ let approvalAttempted = false;
1983
+ for (; ; ) {
2055
1984
  try {
2056
- agentResults[agent.id] = await withFailureReporting(
2057
- this.apiKey,
2058
- agent.id,
2059
- () => agent.deposit(state, chainId, agentAmount, effectiveCallback)
2060
- );
1985
+ return await attempt(effectiveCallback);
2061
1986
  } catch (error) {
2062
- agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
1987
+ if (!approvalAttempted && appCallback === void 0 && asset === "WETH" && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
1988
+ approvalAttempted = true;
1989
+ console.warn(
1990
+ "[owney-sdk] First WETH deposit: sending one-time Permit2 approval..."
1991
+ );
1992
+ await this.approvePermit2();
1993
+ continue;
1994
+ }
1995
+ if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
1996
+ console.warn(
1997
+ `[owney-sdk] ${asset} sponsorship unavailable, falling back to user-paid deposit:`,
1998
+ error
1999
+ );
2000
+ return attempt(void 0);
2063
2001
  }
2064
2002
  }
2065
- if (Object.keys(agentResults).length === 0) {
2066
- throw new OwneyError(
2067
- "DEPOSIT_ALL_FAILED",
2068
- `All ${agentAmounts.length} agent deposit(s) failed.`,
2069
- { agentErrors }
2070
- );
2071
- }
2072
- return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
2073
2003
  }
2074
2004
  getMinDepositAmount(agent, chainId, asset) {
2075
2005
  const chainAssets = agent.supportedAssets.find(
@@ -2079,8 +2009,7 @@ var OwneySDK = class {
2079
2009
  return BigInt(assetEntry?.minDepositAmount ?? "0");
2080
2010
  }
2081
2011
  splitDepositAmount(totalAmount, agents, chainId, asset, exempt = /* @__PURE__ */ new Set()) {
2082
- if (agents.length === 0)
2083
- return [];
2012
+ if (agents.length === 0) return [];
2084
2013
  const perAgent = totalAmount / BigInt(agents.length);
2085
2014
  const remainder = totalAmount % BigInt(agents.length);
2086
2015
  const splits = agents.map((agent, i) => ({
@@ -2104,10 +2033,8 @@ var OwneySDK = class {
2104
2033
  async validateMinDepositAmount(agent, state, chainId, asset, amount) {
2105
2034
  const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
2106
2035
  const parsedAmount = BigInt(amount);
2107
- if (parsedAmount >= minDepositAmount)
2108
- return;
2109
- if (await this.hasExistingBalance(agent, state, chainId, asset))
2110
- return;
2036
+ if (parsedAmount >= minDepositAmount) return;
2037
+ if (await this.hasExistingBalance(agent, state, chainId, asset)) return;
2111
2038
  throw new OwneyError(
2112
2039
  "DEPOSIT_AMOUNT_BELOW_MINIMUM",
2113
2040
  `Amount "${amount}" is below the required minimum deposit "${minDepositAmount.toString()}" for agent "${agent.id}" on chain ${chainId} for asset "${asset}".`,
@@ -2170,34 +2097,6 @@ var OwneySDK = class {
2170
2097
  }
2171
2098
  return eligible;
2172
2099
  }
2173
- /**
2174
- * Agent ids the routing API provisioned for this org that support the given
2175
- * chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
2176
- * surfliquid first). Returns `[]` when the org has no compatible agent — never
2177
- * throws on an empty org. Loads agent keys on first call (apiKey only, no
2178
- * wallet), so the UI can resolve which agent to use before the user connects.
2179
- *
2180
- * This is the source of truth for agent availability: an agent appears here
2181
- * iff the routing API returned its key. No per-app feature flags.
2182
- */
2183
- async getEligibleAgentIds(chainId, asset) {
2184
- try {
2185
- await this.ensureAgentsInitialized();
2186
- } catch (error) {
2187
- if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
2188
- return [];
2189
- }
2190
- throw error;
2191
- }
2192
- return [...this.agents.values()].filter((agent) => {
2193
- const chainAssets = agent.supportedAssets.find(
2194
- (sa) => sa.chainId === chainId
2195
- );
2196
- return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
2197
- }).map((agent) => agent.id).sort(
2198
- (a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
2199
- );
2200
- }
2201
2100
  // --- Fund operations ---
2202
2101
  /**
2203
2102
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
@@ -2233,17 +2132,9 @@ var OwneySDK = class {
2233
2132
  }
2234
2133
  const eligibleAgents = this.getEligibleAgents(chainId, asset);
2235
2134
  if (!amount) {
2236
- const aggregated2 = await this.getBalances();
2237
- const funded = projectAgentBalancesForAsset(
2238
- eligibleAgents,
2239
- aggregated2.agentBalances,
2240
- chainId,
2241
- asset,
2242
- assetInfo.decimals
2243
- ).filter((b) => b.balance > 0n);
2244
2135
  const results2 = {};
2245
2136
  const agentErrors2 = {};
2246
- for (const { agent } of funded) {
2137
+ for (const agent of eligibleAgents) {
2247
2138
  try {
2248
2139
  results2[agent.id] = await agent.withdraw(state, chainId, token);
2249
2140
  } catch (err) {
@@ -2260,10 +2151,9 @@ var OwneySDK = class {
2260
2151
  { asset, agentErrors: agentErrors2 }
2261
2152
  );
2262
2153
  }
2263
- const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
2264
2154
  return {
2265
2155
  agentResult: results2,
2266
- totalWithdrawn: totalWithdrawn.toString()
2156
+ totalWithdrawn: sumWithdrawnAmount(results2).toString()
2267
2157
  };
2268
2158
  }
2269
2159
  const requested = BigInt(amount);
@@ -2308,8 +2198,7 @@ var OwneySDK = class {
2308
2198
  const agentErrors = {};
2309
2199
  for (let i = 0; i < plans.length; i++) {
2310
2200
  const p = plans[i];
2311
- if (p.planned === 0n)
2312
- continue;
2201
+ if (p.planned === 0n) continue;
2313
2202
  try {
2314
2203
  results[p.agent.id] = await p.agent.withdraw(
2315
2204
  state,
@@ -2443,19 +2332,30 @@ var OwneySDK = class {
2443
2332
  */
2444
2333
  async getAccountApy({
2445
2334
  agentId,
2446
- days
2335
+ days,
2336
+ tokenSymbol
2447
2337
  }) {
2448
2338
  const state = this.requireState();
2449
2339
  const chainId = this.requireChainId();
2450
2340
  if (agentId) {
2451
- return this.getAgent(agentId).getAccountApy(state, chainId, days);
2341
+ return this.getAgent(agentId).getAccountApy(
2342
+ state,
2343
+ chainId,
2344
+ days,
2345
+ tokenSymbol
2346
+ );
2452
2347
  }
2453
2348
  const activeAgents = this.getActiveAgents();
2454
2349
  const entries = [...activeAgents.entries()];
2455
2350
  const [apyResults, balanceResults] = await Promise.all([
2456
2351
  Promise.all(
2457
2352
  entries.map(async ([id, agent]) => {
2458
- const apy = await agent.getAccountApy(state, chainId, days);
2353
+ const apy = await agent.getAccountApy(
2354
+ state,
2355
+ chainId,
2356
+ days,
2357
+ tokenSymbol
2358
+ );
2459
2359
  return [id, apy];
2460
2360
  })
2461
2361
  ),
@@ -2478,15 +2378,13 @@ var OwneySDK = class {
2478
2378
  let relevantBalance = 0;
2479
2379
  for (const id of Object.keys(results)) {
2480
2380
  const agentApy = Number(results[id].weightedApyAfterFee ?? 0);
2481
- if (agentApy === 0)
2482
- continue;
2381
+ if (agentApy === 0) continue;
2483
2382
  relevantBalance += balances[id];
2484
2383
  }
2485
2384
  if (relevantBalance > 0) {
2486
2385
  for (const id of Object.keys(results)) {
2487
2386
  const agentApy = Number(results[id].weightedApyAfterFee ?? 0);
2488
- if (agentApy === 0)
2489
- continue;
2387
+ if (agentApy === 0) continue;
2490
2388
  const weight = balances[id] / relevantBalance;
2491
2389
  totalApy += agentApy * weight;
2492
2390
  }
@@ -2541,8 +2439,7 @@ var OwneySDK = class {
2541
2439
  const nextCursorMap = {};
2542
2440
  let hasMore = false;
2543
2441
  for (const { agentId: id, page } of perAgent) {
2544
- if (!page)
2545
- continue;
2442
+ if (!page) continue;
2546
2443
  merged.push(...page.data);
2547
2444
  if (page.hasMore && page.nextCursor) {
2548
2445
  nextCursorMap[id] = page.nextCursor;
@@ -2551,16 +2448,12 @@ var OwneySDK = class {
2551
2448
  }
2552
2449
  merged.sort((a, b) => {
2553
2450
  const dateDiff = new Date(b.date).getTime() - new Date(a.date).getTime();
2554
- if (dateDiff !== 0)
2555
- return dateDiff;
2556
- if (a.agent !== b.agent)
2557
- return a.agent < b.agent ? -1 : 1;
2451
+ if (dateDiff !== 0) return dateDiff;
2452
+ if (a.agent !== b.agent) return a.agent < b.agent ? -1 : 1;
2558
2453
  const aTx = a.transactions?.[0]?.txHashes?.[0] ?? "";
2559
2454
  const bTx = b.transactions?.[0]?.txHashes?.[0] ?? "";
2560
- if (aTx !== bTx)
2561
- return aTx < bTx ? -1 : 1;
2562
- if (a.action !== b.action)
2563
- return a.action < b.action ? -1 : 1;
2455
+ if (aTx !== bTx) return aTx < bTx ? -1 : 1;
2456
+ if (a.action !== b.action) return a.action < b.action ? -1 : 1;
2564
2457
  return 0;
2565
2458
  });
2566
2459
  return {
@@ -2595,6 +2488,67 @@ var OwneySDK = class {
2595
2488
  agentUserProfile: results
2596
2489
  };
2597
2490
  }
2491
+ /**
2492
+ * Ensure the given asset uses backend protocol auto-selection for the active
2493
+ * chain's account. No-op (returns false) for agents that don't support it.
2494
+ * @param asset - "USDC" or "WETH".
2495
+ * @param agentId - Agent to target. Defaults to "zyfai".
2496
+ * @returns whether a profile write occurred.
2497
+ */
2498
+ async ensureAutoSelectProtocols(asset, agentId = "zyfai") {
2499
+ const state = this.requireState();
2500
+ const chainId = this.requireChainId();
2501
+ const agent = this.getAgent(agentId);
2502
+ if (typeof agent.ensureAutoSelectProtocols !== "function") return false;
2503
+ return agent.ensureAutoSelectProtocols(state, chainId, asset);
2504
+ }
2505
+ /**
2506
+ * One-time, user-paid approval of Permit2 on the sponsored WETH token for
2507
+ * the active chain. Required once per wallet per chain before gasless WETH
2508
+ * deposits; afterwards deposit() is signature-only. Resolves only after the
2509
+ * approval transaction is mined (1 confirmation), so a subsequent deposit()
2510
+ * will see the new allowance; throws if the transaction reverted.
2511
+ * @returns the approval transaction hash.
2512
+ */
2513
+ async approvePermit2(asset = "WETH") {
2514
+ void asset;
2515
+ const state = this.requireState();
2516
+ const chainId = this.requireChainId();
2517
+ this.validateAssetSupport(this.getAgent("zyfai"), chainId, "WETH");
2518
+ const token = SPONSORED_WETH_BY_CHAIN[chainId];
2519
+ if (!token) {
2520
+ throw new OwneyError(
2521
+ "CHAIN_UNSUPPORTED",
2522
+ `No sponsored WETH on chain ${chainId}`
2523
+ );
2524
+ }
2525
+ const provider = this.requireConnectedProvider();
2526
+ const wallet = (0, import_viem5.createWalletClient)({
2527
+ account: state.walletAddress,
2528
+ chain: VIEM_CHAIN2[chainId],
2529
+ transport: (0, import_viem5.custom)(provider)
2530
+ });
2531
+ const hash = await wallet.writeContract({
2532
+ address: token,
2533
+ abi: ERC20_ALLOWANCE_ABI,
2534
+ functionName: "approve",
2535
+ args: [PERMIT2_ADDRESS, MAX_UINT256],
2536
+ account: state.walletAddress,
2537
+ chain: VIEM_CHAIN2[chainId]
2538
+ });
2539
+ const publicClient = (0, import_viem5.createPublicClient)({
2540
+ chain: VIEM_CHAIN2[chainId],
2541
+ transport: (0, import_viem5.custom)(provider)
2542
+ });
2543
+ const receipt = await publicClient.waitForTransactionReceipt({
2544
+ hash,
2545
+ confirmations: 1
2546
+ });
2547
+ if (receipt.status !== "success") {
2548
+ throw new Error(`Permit2 approval reverted (tx ${hash})`);
2549
+ }
2550
+ return hash;
2551
+ }
2598
2552
  // --- Discovery (no wallet required) ---
2599
2553
  /**
2600
2554
  * Get the agent's average APY performance over a time period. Does not require a wallet connection.
@@ -2692,9 +2646,6 @@ var OwneySDK = class {
2692
2646
  }
2693
2647
  };
2694
2648
 
2695
- // src/index.ts
2696
- init_errors();
2697
-
2698
2649
  // src/agents/zyfai/zyfai.siwx.ts
2699
2650
  var import_viem6 = require("viem");
2700
2651
  var import_siwe = require("siwe");
@@ -2703,8 +2654,7 @@ var import_sdk2 = require("@zyfai/sdk");
2703
2654
  // src/agents/zyfai/zyfai.siwx-cache.ts
2704
2655
  var KEY_PREFIX2 = "owney.siwx.session";
2705
2656
  var storage2 = () => {
2706
- if (typeof window === "undefined")
2707
- return null;
2657
+ if (typeof window === "undefined") return null;
2708
2658
  try {
2709
2659
  return window.localStorage;
2710
2660
  } catch {
@@ -2714,11 +2664,9 @@ var storage2 = () => {
2714
2664
  var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2715
2665
  var readSiwxSession = (address, chainId) => {
2716
2666
  const store = storage2();
2717
- if (!store)
2718
- return null;
2667
+ if (!store) return null;
2719
2668
  const raw = store.getItem(buildKey2(address, chainId));
2720
- if (!raw)
2721
- return null;
2669
+ if (!raw) return null;
2722
2670
  try {
2723
2671
  return JSON.parse(raw);
2724
2672
  } catch {
@@ -2728,8 +2676,7 @@ var readSiwxSession = (address, chainId) => {
2728
2676
  };
2729
2677
  var writeSiwxSession = (address, chainId, session) => {
2730
2678
  const store = storage2();
2731
- if (!store)
2732
- return;
2679
+ if (!store) return;
2733
2680
  try {
2734
2681
  store.setItem(buildKey2(address, chainId), JSON.stringify(session));
2735
2682
  } catch {
@@ -2737,8 +2684,7 @@ var writeSiwxSession = (address, chainId, session) => {
2737
2684
  };
2738
2685
  var clearSiwxSession = (address, chainId) => {
2739
2686
  const store = storage2();
2740
- if (!store)
2741
- return;
2687
+ if (!store) return;
2742
2688
  try {
2743
2689
  store.removeItem(buildKey2(address, chainId));
2744
2690
  } catch {
@@ -2801,12 +2747,10 @@ function buildSIWXConfig(deps) {
2801
2747
  const jwt = readSession(address, id);
2802
2748
  const stored = readSiwxSession(address, id);
2803
2749
  if (!jwt) {
2804
- if (stored)
2805
- clearSiwxSession(address, id);
2750
+ if (stored) clearSiwxSession(address, id);
2806
2751
  return [];
2807
2752
  }
2808
- if (!stored)
2809
- return [];
2753
+ if (!stored) return [];
2810
2754
  const session = {
2811
2755
  // `stored.data.chainId` is a plain string in the cache (kept AppKit-free);
2812
2756
  // it always holds a valid CaipNetworkId here, so narrow at the boundary.