@owney/sdk 0.6.7-beta.1 → 0.6.7-beta.2

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,14 +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, err) => function __init() {
7
- if (err) throw err[0];
8
- try {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
- } catch (e) {
11
- throw err = [e], e;
12
- }
13
- };
14
6
  var __export = (target, all) => {
15
7
  for (var name in all)
16
8
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -25,478 +17,6 @@ var __copyProps = (to, from, except, desc) => {
25
17
  };
26
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
19
 
28
- // src/errors.ts
29
- var OwneyError, AgentNotFoundError, NotConnectedError, AgentChainIncompatibleError;
30
- var init_errors = __esm({
31
- "src/errors.ts"() {
32
- "use strict";
33
- OwneyError = class extends Error {
34
- code;
35
- details;
36
- agentId;
37
- constructor(code, message, details, agentId) {
38
- const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
39
- super(`${prefix} ${message}`);
40
- this.name = "OwneyError";
41
- this.code = code;
42
- this.details = details;
43
- this.agentId = agentId;
44
- }
45
- };
46
- AgentNotFoundError = class extends OwneyError {
47
- constructor(agentId, available) {
48
- super(
49
- "AGENT_NOT_FOUND",
50
- `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
51
- { agentId, available },
52
- agentId
53
- );
54
- this.name = "AgentNotFoundError";
55
- }
56
- };
57
- NotConnectedError = class extends OwneyError {
58
- constructor() {
59
- super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
60
- this.name = "NotConnectedError";
61
- }
62
- };
63
- AgentChainIncompatibleError = class extends OwneyError {
64
- incompatibleAgents;
65
- connectedChainId;
66
- constructor(incompatibleAgents, connectedChainId) {
67
- const details = incompatibleAgents.map(
68
- ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
69
- ).join("; ");
70
- super(
71
- "AGENT_CHAIN_INCOMPATIBLE",
72
- `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
73
- { incompatibleAgents, connectedChainId }
74
- );
75
- this.name = "AgentChainIncompatibleError";
76
- this.incompatibleAgents = incompatibleAgents;
77
- this.connectedChainId = connectedChainId;
78
- }
79
- };
80
- }
81
- });
82
-
83
- // src/agents/surfliquid/surfliquid.constants.ts
84
- var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_USDC_DECIMALS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
85
- var init_surfliquid_constants = __esm({
86
- "src/agents/surfliquid/surfliquid.constants.ts"() {
87
- "use strict";
88
- SURFLIQUID_CHAIN_ID = 8453;
89
- SURFLIQUID_CHAIN_NAME = "BASE";
90
- SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
91
- SURFLIQUID_USDC_DECIMALS = 6;
92
- SURFLIQUID_MIN_DEPOSIT = "0";
93
- SURFLIQUID_SUPPORTED_ASSETS = [
94
- {
95
- chainId: SURFLIQUID_CHAIN_ID,
96
- chain: SURFLIQUID_CHAIN_NAME,
97
- assets: [{ symbol: "USDC", minDepositAmount: SURFLIQUID_MIN_DEPOSIT }]
98
- }
99
- ];
100
- SURFLIQUID_ACTION_MAP = {
101
- // INITIAL_DEPOSIT is the user's real first deposit, so surface it like any
102
- // other funding ("Top up"). The mini-app intentionally hides the "Deposit"
103
- // action (it marks Zyfai's smart-account-creation event), which would
104
- // otherwise drop a SurfLiquid user's only history row.
105
- INITIAL_DEPOSIT: "Top up",
106
- DEPOSIT: "Top up",
107
- USER_DEPOSIT: "Top up",
108
- WITHDRAWAL: "Withdraw",
109
- USER_WITHDRAWAL: "Withdraw",
110
- REBALANCE: "Rebalance",
111
- REBALANCE_COMPLETED: "Rebalance",
112
- CROSS_CHAIN_REBALANCE: "Rebalance",
113
- MERKL_CLAIM: "Earned"
114
- };
115
- }
116
- });
117
-
118
- // src/agents/surfliquid/surfliquid.mapper.ts
119
- function mapMessage(message) {
120
- const action = SURFLIQUID_ACTION_MAP[message.transactionType];
121
- if (!action) return null;
122
- return {
123
- agent: "surfliquid",
124
- action,
125
- date: message.timestamp,
126
- oldApy: message.apyBefore != null ? String(message.apyBefore) : null,
127
- newApy: message.apyAfter != null ? String(message.apyAfter) : null,
128
- transactions: [
129
- {
130
- txHashes: [message.txHash],
131
- chainId: message.chainId,
132
- tokenSymbol: message.token ?? void 0,
133
- amount: message.amount != null ? String(message.amount) : void 0
134
- }
135
- ],
136
- rebalanceLog: []
137
- };
138
- }
139
- function mapHistory(result, _chainId) {
140
- const data = result.messages.map(mapMessage).filter((entry) => entry !== null);
141
- const hasMore = result.page < result.pages;
142
- return {
143
- data,
144
- hasMore,
145
- nextCursor: hasMore ? String(result.page + 1) : void 0
146
- };
147
- }
148
- function mapBalances2(vault, chainId, morphoStats) {
149
- const assets = (vault.assets ?? []).filter(
150
- (asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId
151
- );
152
- const tokens = assets.map((asset) => ({
153
- chain: SURFLIQUID_CHAIN_NAME,
154
- chainId: SURFLIQUID_CHAIN_ID,
155
- asset: "USDC",
156
- amount: String(asset.currentValueUSD)
157
- }));
158
- const positions = assets.map((asset) => {
159
- const stats = morphoStats?.get(asset.morphoVaultAddress?.toLowerCase() ?? "");
160
- return {
161
- chain: SURFLIQUID_CHAIN_NAME,
162
- protocol: "Morpho",
163
- // The specific MetaMorpho vault (e.g. "Gauntlet USDC Frontier"), read from
164
- // Morpho — renders as "Morpho <vault>" alongside zyfai's vault detail.
165
- pool: stats?.name ?? void 0,
166
- asset: "USDC",
167
- amount: String(asset.currentValueUSD),
168
- apy: asset.currentAPY,
169
- // TVL + liquidity come straight from Morpho (SurfLiquid's API omits them).
170
- tvl: stats?.tvlUsd,
171
- liquidity: stats?.liquidityUsd
172
- };
173
- });
174
- const total = assets.reduce(
175
- (sum, asset) => sum + asset.currentValueUSD,
176
- 0
177
- );
178
- return {
179
- smartWallet: vault.userVaultAddress ?? void 0,
180
- totalBalance: String(total),
181
- totalBalanceAsset: "usdc",
182
- tokens,
183
- positions
184
- };
185
- }
186
- function mapAccountApy(vault, days) {
187
- const breakdown = vault.apyBreakdown;
188
- const windowed = breakdown ? breakdown[APY_WINDOW_KEY[days]] : void 0;
189
- const apy = windowed != null ? windowed : breakdown?.currentAPY ?? 0;
190
- return {
191
- walletAddress: vault.walletAddress ?? "",
192
- weightedApyAfterFee: apy,
193
- apyByChainAndAsset: { [SURFLIQUID_CHAIN_ID]: { USDC: apy } },
194
- // Parity with Sail: SurfLiquid's core-sdk exposes no daily net-APY series.
195
- history: []
196
- };
197
- }
198
- function mapEarnings2(vault, vaultAddress) {
199
- return {
200
- smartWallet: vaultAddress,
201
- lifetimeEarnings: vault.earned?.totalEarningsUSD ?? 0,
202
- tokens: []
203
- };
204
- }
205
- function mapUserProfile2(vault, address) {
206
- return {
207
- address,
208
- smartWallet: vault.userVaultAddress ?? "",
209
- chains: [SURFLIQUID_CHAIN_ID],
210
- // SurfLiquid uses cookie-based session auth — no session-key concept.
211
- hasActiveSessionKey: false,
212
- protocols: ["SurfLiquid"]
213
- };
214
- }
215
- var APY_WINDOW_KEY;
216
- var init_surfliquid_mapper = __esm({
217
- "src/agents/surfliquid/surfliquid.mapper.ts"() {
218
- "use strict";
219
- init_surfliquid_constants();
220
- APY_WINDOW_KEY = {
221
- "7D": "apy7d",
222
- "14D": "apy14d",
223
- "30D": "apy30d"
224
- };
225
- }
226
- });
227
-
228
- // src/agents/surfliquid/surfliquid.wallet-adapter.ts
229
- var import_core_sdk, OwneyWalletAdapter;
230
- var init_surfliquid_wallet_adapter = __esm({
231
- "src/agents/surfliquid/surfliquid.wallet-adapter.ts"() {
232
- "use strict";
233
- import_core_sdk = require("@surf_liquid/core-sdk");
234
- OwneyWalletAdapter = class extends import_core_sdk.BaseWalletAdapter {
235
- constructor(eip1193Provider) {
236
- super();
237
- this.eip1193Provider = eip1193Provider;
238
- }
239
- eip1193Provider;
240
- name = "owney";
241
- get installed() {
242
- return true;
243
- }
244
- resolveProvider() {
245
- return this.eip1193Provider;
246
- }
247
- };
248
- }
249
- });
250
-
251
- // src/agents/surfliquid/surfliquid.morpho.ts
252
- async function fetchMorphoVaultStats(vaultAddress, chainId) {
253
- try {
254
- const res = await fetch(MORPHO_API_URL, {
255
- method: "POST",
256
- headers: { "Content-Type": "application/json" },
257
- body: JSON.stringify({
258
- query: VAULT_STATS_QUERY,
259
- variables: { address: vaultAddress, chainId }
260
- })
261
- });
262
- if (!res.ok) return null;
263
- const json = await res.json();
264
- if (json.errors) return null;
265
- const vault = json.data?.vaultByAddress;
266
- const tvlUsd = vault?.state?.totalAssetsUsd;
267
- const liquidityUsd = vault?.liquidity?.usd;
268
- if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
269
- return null;
270
- }
271
- const name = typeof vault?.name === "string" ? vault.name : null;
272
- return { name, tvlUsd, liquidityUsd };
273
- } catch (error) {
274
- console.warn("surfliquid: Morpho vault stats fetch failed", {
275
- vaultAddress,
276
- chainId,
277
- error
278
- });
279
- return null;
280
- }
281
- }
282
- async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
283
- const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
284
- const entries = await Promise.all(
285
- unique.map(
286
- async (address) => [address, await fetchMorphoVaultStats(address, chainId)]
287
- )
288
- );
289
- const byVault = /* @__PURE__ */ new Map();
290
- for (const [address, stats] of entries) {
291
- if (stats) byVault.set(address, stats);
292
- }
293
- return byVault;
294
- }
295
- var MORPHO_API_URL, VAULT_STATS_QUERY;
296
- var init_surfliquid_morpho = __esm({
297
- "src/agents/surfliquid/surfliquid.morpho.ts"() {
298
- "use strict";
299
- MORPHO_API_URL = "https://api.morpho.org/graphql";
300
- VAULT_STATS_QUERY = `
301
- query VaultStats($address: String!, $chainId: Int!) {
302
- vaultByAddress(address: $address, chainId: $chainId) {
303
- name
304
- state { totalAssetsUsd }
305
- liquidity { usd }
306
- }
307
- }
308
- `;
309
- }
310
- });
311
-
312
- // src/agents/surfliquid/surfliquid.agent.ts
313
- var surfliquid_agent_exports = {};
314
- __export(surfliquid_agent_exports, {
315
- SurfLiquidAgent: () => SurfLiquidAgent
316
- });
317
- var import_core_sdk2, import_viem5, APY_WINDOW_KEY2, SurfLiquidAgent;
318
- var init_surfliquid_agent = __esm({
319
- "src/agents/surfliquid/surfliquid.agent.ts"() {
320
- "use strict";
321
- import_core_sdk2 = require("@surf_liquid/core-sdk");
322
- import_viem5 = require("viem");
323
- init_errors();
324
- init_surfliquid_constants();
325
- init_surfliquid_mapper();
326
- init_surfliquid_wallet_adapter();
327
- init_surfliquid_morpho();
328
- APY_WINDOW_KEY2 = {
329
- "7D": "apy7d",
330
- "14D": "apy14d",
331
- "30D": "apy30d"
332
- };
333
- SurfLiquidAgent = class {
334
- constructor(config) {
335
- this.config = config;
336
- }
337
- config;
338
- id = "surfliquid";
339
- supportedChainIds = [SURFLIQUID_CHAIN_ID];
340
- supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
341
- surf = null;
342
- connectedAddress = null;
343
- // In-flight connect+auth, shared by concurrent callers to dedupe SIWE.
344
- connectPromise = null;
345
- ensureSurf() {
346
- if (this.surf) return this.surf;
347
- this.surf = import_core_sdk2.SurfClient.create({
348
- projectName: this.config.projectName,
349
- appId: this.config.appId,
350
- environment: "mainnet",
351
- chainId: SURFLIQUID_CHAIN_ID,
352
- apiBaseUrl: this.config.apiBaseUrl,
353
- rpcUrl: this.config.rpcUrl,
354
- // Let the SDK auto-approve USDC to the vault before depositing.
355
- autoApprove: true
356
- });
357
- return this.surf;
358
- }
359
- /**
360
- * Connects + authenticates the SurfClient against owney's provider. Skips the
361
- * SIWE prompt when already authenticated for this wallet (cookie session).
362
- */
363
- async connect(state) {
364
- const surf = this.ensureSurf();
365
- const sameWallet = this.connectedAddress?.toLowerCase() === state.walletAddress.toLowerCase();
366
- if (sameWallet && surf.getAuthState().authenticated) {
367
- return surf;
368
- }
369
- if (this.connectPromise) return this.connectPromise;
370
- this.connectPromise = (async () => {
371
- surf.registerWalletAdapter(
372
- "owney",
373
- new OwneyWalletAdapter(state.provider)
374
- );
375
- await surf.connectWallet("owney");
376
- await surf.authenticate();
377
- this.connectedAddress = state.walletAddress;
378
- return surf;
379
- })();
380
- try {
381
- return await this.connectPromise;
382
- } finally {
383
- this.connectPromise = null;
384
- }
385
- }
386
- /**
387
- * Returns the user's vault address, deploying one on first use. SurfLiquid's
388
- * deposit requires the vault to exist, so this must run before depositing.
389
- * Existing vault → returned as-is; otherwise `deployVault()` is sent
390
- * (user-pays) and the freshly deployed address is returned.
391
- */
392
- async resolveVaultAddress(surf, owner) {
393
- const vault = await surf.getVault(owner).catch(() => null);
394
- if (vault?.exists && vault.userVaultAddress) {
395
- return vault.userVaultAddress;
396
- }
397
- const { vaultAddress } = await surf.deployVault();
398
- return vaultAddress;
399
- }
400
- // --- IAgent: lifecycle ---
401
- async disconnect() {
402
- if (this.surf) {
403
- await this.surf.disconnectWallet();
404
- }
405
- this.connectedAddress = null;
406
- }
407
- async activateAgent(state) {
408
- await this.connect(state);
409
- }
410
- // --- IAgent: funds (user-pays; asset is always USDC, callback ignored) ---
411
- async deposit(state, _chainId, amount, _asset, _depositCallback) {
412
- const surf = await this.connect(state);
413
- const human = (0, import_viem5.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS);
414
- const smartWallet = await this.resolveVaultAddress(
415
- surf,
416
- state.walletAddress
417
- );
418
- const tx = await surf.deposit({
419
- asset: SURFLIQUID_USDC_ADDRESS,
420
- amount: human
421
- });
422
- await tx.wait();
423
- return { txHash: tx.hash, smartWallet, amount };
424
- }
425
- async withdraw(state, _chainId, _token, amount) {
426
- const surf = await this.connect(state);
427
- const human = amount != null ? (0, import_viem5.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS) : void 0;
428
- try {
429
- const tx = await surf.withdraw({
430
- asset: SURFLIQUID_USDC_ADDRESS,
431
- amount: human
432
- });
433
- await tx.wait();
434
- return {
435
- txHash: tx.hash,
436
- type: amount != null ? "partial" : "full",
437
- amount: amount ?? "0"
438
- };
439
- } catch (error) {
440
- throw new OwneyError(
441
- "WITHDRAW_FAILED",
442
- error instanceof Error ? error.message : "SurfLiquid withdraw failed.",
443
- { chainId: SURFLIQUID_CHAIN_ID, amount },
444
- this.id
445
- );
446
- }
447
- }
448
- // --- IAgent: portfolio reads ---
449
- async getBalances(state, chainId) {
450
- const surf = await this.connect(state);
451
- const vault = await surf.getVault(state.walletAddress);
452
- const morphoVaultAddresses = (vault.assets ?? []).filter((asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId).map((asset) => asset.morphoVaultAddress).filter((address) => Boolean(address));
453
- const morphoStats = await fetchMorphoStatsByVault(
454
- morphoVaultAddresses,
455
- chainId
456
- );
457
- return mapBalances2(vault, chainId, morphoStats);
458
- }
459
- async getEarnings(state) {
460
- const surf = await this.connect(state);
461
- const vault = await surf.getVault(state.walletAddress);
462
- return mapEarnings2(vault, vault.userVaultAddress ?? state.walletAddress);
463
- }
464
- async getAccountApy(state, _chainId, days, _tokenSymbol) {
465
- const surf = await this.connect(state);
466
- const vault = await surf.getVault(state.walletAddress);
467
- return mapAccountApy(vault, days);
468
- }
469
- async getHistory(state, chainId, options) {
470
- const surf = await this.connect(state);
471
- const page = options?.cursor ? Number(options.cursor) : 1;
472
- const limit = options?.limit ?? 10;
473
- const result = await surf.getAgentMessages(
474
- state.walletAddress,
475
- page,
476
- limit,
477
- options?.fromDate,
478
- options?.toDate
479
- );
480
- return mapHistory(result, chainId);
481
- }
482
- async getUserProfile(state) {
483
- const surf = await this.connect(state);
484
- const vault = await surf.getVault(state.walletAddress);
485
- return mapUserProfile2(vault, state.walletAddress);
486
- }
487
- // --- IAgent: discovery (no wallet) ---
488
- async getAgentApy(days, _options) {
489
- const surf = this.ensureSurf();
490
- const assets = await surf.getSupportedAssets(SURFLIQUID_CHAIN_ID);
491
- const usdc = assets.find((asset) => asset.assetSymbol === "USDC");
492
- if (!usdc) 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
21
  var index_exports = {};
502
22
  __export(index_exports, {
@@ -568,8 +88,56 @@ var SupportedAssets = [
568
88
  }
569
89
  ];
570
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
+
571
140
  // src/lib/utils.ts
572
- init_errors();
573
141
  var isValidChainId = (chainId) => {
574
142
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
575
143
  throw new OwneyError(
@@ -643,46 +211,46 @@ function resolveChainId(chain) {
643
211
  function mapBalances(raw, _chainId, smartWallet) {
644
212
  const portfolio = raw.portfolio;
645
213
  const portfolioByChain = portfolio.portfolioByChain ?? {};
646
- const rawPositions = portfolio.positions ?? [];
647
- const detailByKey = /* @__PURE__ */ new Map();
648
- for (const p of rawPositions) {
649
- const cid = resolveChainId(p.chain ?? "");
650
- const symbol = (p.token_symbol ?? "").toUpperCase();
651
- if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
652
- }
653
214
  let totalBalance = 0;
654
215
  const tokens = [];
655
- const positions = [];
656
216
  for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
657
217
  const positionChainId = Number(chainIdKey);
658
- const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
659
218
  for (const [symbol, { balance, decimals }] of Object.entries(
660
219
  tokensBySymbol ?? {}
661
220
  )) {
662
- const amount = hexToDecimal(balance || "0", tokenDecimals(symbol, decimals));
221
+ const amount = hexToDecimal(balance || "0", decimals);
663
222
  totalBalance += amount;
664
223
  tokens.push({
665
- chain: chainName,
224
+ chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
666
225
  chainId: positionChainId,
667
226
  asset: symbol,
668
227
  amount: String(amount)
669
228
  });
670
- const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
671
- positions.push({
672
- chain: chainName,
673
- protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
674
- protocolId: detail?.protocol_id,
675
- pool: detail?.pool,
676
- asset: symbol,
677
- amount: String(amount),
678
- apy: detail?.pool_apy,
679
- tvl: detail?.pool_tvl,
680
- // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
681
- // structural read keeps it undefined today and auto-populates later.
682
- liquidity: detail?.liquidity
683
- });
684
229
  }
685
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
+ }));
686
254
  return {
687
255
  smartWallet,
688
256
  totalBalance: String(totalBalance),
@@ -957,9 +525,6 @@ function decodeHistoryCursor(token) {
957
525
  return parsed;
958
526
  }
959
527
 
960
- // src/agents/zyfai/zyfai.agent.ts
961
- init_errors();
962
-
963
528
  // src/agents/zyfai/zyfai.auth-cache.ts
964
529
  var KEY_PREFIX = "owney.zyfai.session";
965
530
  var storage = () => {
@@ -970,7 +535,8 @@ var storage = () => {
970
535
  return null;
971
536
  }
972
537
  };
973
- var buildKey = (address, chainId) => `${KEY_PREFIX}:${address.toLowerCase()}:${chainId}`;
538
+ var buildKey = (address) => `${KEY_PREFIX}:${address.toLowerCase()}`;
539
+ var legacyKeyPrefix = (address) => `${KEY_PREFIX}:${address.toLowerCase()}:`;
974
540
  var isJwtExpired = (token) => {
975
541
  const parts = token.split(".");
976
542
  if (parts.length !== 3) return false;
@@ -987,9 +553,37 @@ var isJwtExpired = (token) => {
987
553
  };
988
554
  var memorySessions = /* @__PURE__ */ new Map();
989
555
  var isFreshSession = (session) => !!session && !!session.token && !isJwtExpired(session.token);
990
- var readSession = (address, chainId) => {
556
+ var readLegacySession = (store, address) => {
557
+ if (!store) return null;
558
+ const prefix = legacyKeyPrefix(address);
559
+ const legacyKeys = [];
560
+ try {
561
+ for (let i = 0; i < store.length; i++) {
562
+ const key = store.key(i);
563
+ if (key?.startsWith(prefix)) legacyKeys.push(key);
564
+ }
565
+ } catch {
566
+ return null;
567
+ }
568
+ let adopted = null;
569
+ for (const key of legacyKeys) {
570
+ if (!adopted) {
571
+ try {
572
+ const parsed = JSON.parse(store.getItem(key) ?? "");
573
+ if (isFreshSession(parsed)) adopted = parsed;
574
+ } catch {
575
+ }
576
+ }
577
+ try {
578
+ store.removeItem(key);
579
+ } catch {
580
+ }
581
+ }
582
+ return adopted;
583
+ };
584
+ var readSession = (address, _chainId) => {
991
585
  if (typeof window === "undefined") return null;
992
- const key = buildKey(address, chainId);
586
+ const key = buildKey(address);
993
587
  const store = storage();
994
588
  let raw = null;
995
589
  try {
@@ -1010,14 +604,19 @@ var readSession = (address, chainId) => {
1010
604
  }
1011
605
  return null;
1012
606
  }
607
+ const legacy = readLegacySession(store, address);
608
+ if (legacy) {
609
+ writeSession(address, _chainId, legacy);
610
+ return legacy;
611
+ }
1013
612
  const cached = memorySessions.get(key);
1014
613
  if (isFreshSession(cached)) return cached;
1015
614
  if (cached) memorySessions.delete(key);
1016
615
  return null;
1017
616
  };
1018
- var writeSession = (address, chainId, session) => {
617
+ var writeSession = (address, _chainId, session) => {
1019
618
  if (typeof window === "undefined") return;
1020
- const key = buildKey(address, chainId);
619
+ const key = buildKey(address);
1021
620
  memorySessions.set(key, session);
1022
621
  const store = storage();
1023
622
  try {
@@ -1025,14 +624,15 @@ var writeSession = (address, chainId, session) => {
1025
624
  } catch {
1026
625
  }
1027
626
  };
1028
- var clearSession = (address, chainId) => {
1029
- const key = buildKey(address, chainId);
627
+ var clearSession = (address, _chainId) => {
628
+ const key = buildKey(address);
1030
629
  memorySessions.delete(key);
1031
630
  const store = storage();
1032
631
  try {
1033
632
  store?.removeItem(key);
1034
633
  } catch {
1035
634
  }
635
+ readLegacySession(store, address);
1036
636
  };
1037
637
 
1038
638
  // src/agents/zyfai/autoSelect.ts
@@ -1531,11 +1131,7 @@ var ZyfaiAgent = class {
1531
1131
  }
1532
1132
  };
1533
1133
 
1534
- // src/client.ts
1535
- init_errors();
1536
-
1537
1134
  // src/lib/routing-api.ts
1538
- init_errors();
1539
1135
  var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
1540
1136
  async function fetchAgentKeys(apiKey) {
1541
1137
  const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
@@ -1566,7 +1162,6 @@ async function fetchAgentKeys(apiKey) {
1566
1162
  }
1567
1163
 
1568
1164
  // src/lib/health-report.ts
1569
- init_errors();
1570
1165
  var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
1571
1166
  async function reportAgentFailure(apiKey, agentType, errorCode) {
1572
1167
  try {
@@ -1716,12 +1311,9 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1716
1311
  }
1717
1312
 
1718
1313
  // src/client.ts
1719
- var import_viem6 = require("viem");
1314
+ var import_viem5 = require("viem");
1720
1315
  var import_chains2 = require("viem/chains");
1721
1316
 
1722
- // src/lib/sponsored-deposit.ts
1723
- init_errors();
1724
-
1725
1317
  // src/lib/transfer-auth.ts
1726
1318
  var import_viem3 = require("viem");
1727
1319
  var ERC20_META_ABI = [
@@ -1759,7 +1351,6 @@ function randomAuthNonce() {
1759
1351
  }
1760
1352
 
1761
1353
  // src/lib/sponsor-client.ts
1762
- init_errors();
1763
1354
  var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
1764
1355
  async function postSponsorTransferAuth(input) {
1765
1356
  const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
@@ -1926,9 +1517,6 @@ function makeSponsoredDepositCallback(deps) {
1926
1517
  };
1927
1518
  }
1928
1519
 
1929
- // src/lib/sponsored-weth-deposit.ts
1930
- init_errors();
1931
-
1932
1520
  // src/lib/permit2.ts
1933
1521
  var import_viem4 = require("viem");
1934
1522
  var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
@@ -2068,7 +1656,6 @@ var VIEM_CHAIN2 = {
2068
1656
  42161: import_chains2.arbitrum,
2069
1657
  1: import_chains2.mainnet
2070
1658
  };
2071
- var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
2072
1659
  var SPONSORED_WETH_BY_CHAIN = {
2073
1660
  8453: "0x4200000000000000000000000000000000000006",
2074
1661
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
@@ -2192,14 +1779,14 @@ var OwneySDK = class {
2192
1779
  // Casts work around viem's chain-narrowed Client vs the generic
2193
1780
  // PublicClient/WalletClient param types — structurally identical at
2194
1781
  // runtime, but the two share a name TS treats as unrelated.
2195
- getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
1782
+ getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
2196
1783
  chain: VIEM_CHAIN2[cid],
2197
- transport: (0, import_viem6.custom)(provider)
1784
+ transport: (0, import_viem5.custom)(provider)
2198
1785
  }),
2199
- getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
1786
+ getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
2200
1787
  account: owner,
2201
1788
  chain: VIEM_CHAIN2[cid],
2202
- transport: (0, import_viem6.custom)(provider)
1789
+ transport: (0, import_viem5.custom)(provider)
2203
1790
  })
2204
1791
  });
2205
1792
  return this.cachedSponsoredCallback;
@@ -2223,14 +1810,14 @@ var OwneySDK = class {
2223
1810
  // Casts work around viem's chain-narrowed Client vs the generic
2224
1811
  // PublicClient/WalletClient param types — structurally identical at
2225
1812
  // runtime, but the two share a name TS treats as unrelated.
2226
- getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
1813
+ getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
2227
1814
  chain: VIEM_CHAIN2[cid],
2228
- transport: (0, import_viem6.custom)(provider)
1815
+ transport: (0, import_viem5.custom)(provider)
2229
1816
  }),
2230
- getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
1817
+ getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
2231
1818
  account: owner,
2232
1819
  chain: VIEM_CHAIN2[cid],
2233
- transport: (0, import_viem6.custom)(provider)
1820
+ transport: (0, import_viem5.custom)(provider)
2234
1821
  })
2235
1822
  });
2236
1823
  return this.cachedWethSponsoredCallback;
@@ -2256,8 +1843,8 @@ var OwneySDK = class {
2256
1843
  this.initializingAgentsPromise = (async () => {
2257
1844
  const agentKeys = await fetchAgentKeys(this.apiKey);
2258
1845
  this.disabledAgents.clear();
2259
- for (const { key, agent_type, project_name, is_enabled } of agentKeys) {
2260
- const agent = await this.createAgent(agent_type, key, project_name);
1846
+ for (const { key, agent_type, is_enabled } of agentKeys) {
1847
+ const agent = this.createAgent(agent_type, key);
2261
1848
  if (!agent) continue;
2262
1849
  this.agents.set(agent_type, agent);
2263
1850
  if (is_enabled === false) {
@@ -2278,15 +1865,10 @@ var OwneySDK = class {
2278
1865
  this.initializingAgentsPromise = null;
2279
1866
  }
2280
1867
  }
2281
- async createAgent(agentId, key, projectName) {
1868
+ createAgent(agentId, key) {
2282
1869
  if (agentId === "zyfai") {
2283
1870
  return new ZyfaiAgent(key, this.zyfaiRpcUrls);
2284
1871
  }
2285
- if (agentId === "surfliquid") {
2286
- if (!projectName) return null;
2287
- const { SurfLiquidAgent: SurfLiquidAgent2 } = await Promise.resolve().then(() => (init_surfliquid_agent(), surfliquid_agent_exports));
2288
- return new SurfLiquidAgent2({ projectName, appId: key });
2289
- }
2290
1872
  return null;
2291
1873
  }
2292
1874
  // --- Account lifecycle ---
@@ -2439,30 +2021,18 @@ var OwneySDK = class {
2439
2021
  );
2440
2022
  }
2441
2023
  const agentResults = {};
2442
- const agentErrors = {};
2443
2024
  for (const { agent, amount: agentAmount } of agentAmounts) {
2444
- try {
2445
- agentResults[agent.id] = await this.depositWithFallback(
2446
- agent,
2447
- state,
2448
- chainId,
2449
- agentAmount,
2450
- asset,
2451
- effectiveCallback,
2452
- depositCallback
2453
- );
2454
- } catch (error) {
2455
- agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
2456
- }
2457
- }
2458
- if (Object.keys(agentResults).length === 0) {
2459
- throw new OwneyError(
2460
- "DEPOSIT_ALL_FAILED",
2461
- `All ${agentAmounts.length} agent deposit(s) failed.`,
2462
- { agentErrors }
2025
+ agentResults[agent.id] = await this.depositWithFallback(
2026
+ agent,
2027
+ state,
2028
+ chainId,
2029
+ agentAmount,
2030
+ asset,
2031
+ effectiveCallback,
2032
+ depositCallback
2463
2033
  );
2464
2034
  }
2465
- return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
2035
+ return { agentResults };
2466
2036
  }
2467
2037
  /**
2468
2038
  * Invokes `agent.deposit` with the resolved sponsored callback, composing
@@ -2619,34 +2189,6 @@ var OwneySDK = class {
2619
2189
  }
2620
2190
  return eligible;
2621
2191
  }
2622
- /**
2623
- * Agent ids the routing API provisioned for this org that support the given
2624
- * chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
2625
- * surfliquid first). Returns `[]` when the org has no compatible agent — never
2626
- * throws on an empty org. Loads agent keys on first call (apiKey only, no
2627
- * wallet), so the UI can resolve which agent to use before the user connects.
2628
- *
2629
- * This is the source of truth for agent availability: an agent appears here
2630
- * iff the routing API returned its key. No per-app feature flags.
2631
- */
2632
- async getEligibleAgentIds(chainId, asset) {
2633
- try {
2634
- await this.ensureAgentsInitialized();
2635
- } catch (error) {
2636
- if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
2637
- return [];
2638
- }
2639
- throw error;
2640
- }
2641
- return [...this.agents.values()].filter((agent) => {
2642
- const chainAssets = agent.supportedAssets.find(
2643
- (sa) => sa.chainId === chainId
2644
- );
2645
- return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
2646
- }).map((agent) => agent.id).sort(
2647
- (a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
2648
- );
2649
- }
2650
2192
  // --- Fund operations ---
2651
2193
  /**
2652
2194
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
@@ -2682,17 +2224,9 @@ var OwneySDK = class {
2682
2224
  }
2683
2225
  const eligibleAgents = this.getEligibleAgents(chainId, asset);
2684
2226
  if (!amount) {
2685
- const aggregated2 = await this.getBalances();
2686
- const funded = projectAgentBalancesForAsset(
2687
- eligibleAgents,
2688
- aggregated2.agentBalances,
2689
- chainId,
2690
- asset,
2691
- assetInfo.decimals
2692
- ).filter((b) => b.balance > 0n);
2693
2227
  const results2 = {};
2694
2228
  const agentErrors2 = {};
2695
- for (const { agent } of funded) {
2229
+ for (const agent of eligibleAgents) {
2696
2230
  try {
2697
2231
  results2[agent.id] = await agent.withdraw(state, chainId, token);
2698
2232
  } catch (err) {
@@ -2709,10 +2243,9 @@ var OwneySDK = class {
2709
2243
  { asset, agentErrors: agentErrors2 }
2710
2244
  );
2711
2245
  }
2712
- const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
2713
2246
  return {
2714
2247
  agentResult: results2,
2715
- totalWithdrawn: totalWithdrawn.toString()
2248
+ totalWithdrawn: sumWithdrawnAmount(results2).toString()
2716
2249
  };
2717
2250
  }
2718
2251
  const requested = BigInt(amount);
@@ -3082,10 +2615,10 @@ var OwneySDK = class {
3082
2615
  );
3083
2616
  }
3084
2617
  const provider = this.requireConnectedProvider();
3085
- const wallet = (0, import_viem6.createWalletClient)({
2618
+ const wallet = (0, import_viem5.createWalletClient)({
3086
2619
  account: state.walletAddress,
3087
2620
  chain: VIEM_CHAIN2[chainId],
3088
- transport: (0, import_viem6.custom)(provider)
2621
+ transport: (0, import_viem5.custom)(provider)
3089
2622
  });
3090
2623
  const hash = await wallet.writeContract({
3091
2624
  address: token,
@@ -3095,9 +2628,9 @@ var OwneySDK = class {
3095
2628
  account: state.walletAddress,
3096
2629
  chain: VIEM_CHAIN2[chainId]
3097
2630
  });
3098
- const publicClient = (0, import_viem6.createPublicClient)({
2631
+ const publicClient = (0, import_viem5.createPublicClient)({
3099
2632
  chain: VIEM_CHAIN2[chainId],
3100
- transport: (0, import_viem6.custom)(provider)
2633
+ transport: (0, import_viem5.custom)(provider)
3101
2634
  });
3102
2635
  const receipt = await publicClient.waitForTransactionReceipt({
3103
2636
  hash,
@@ -3205,11 +2738,8 @@ var OwneySDK = class {
3205
2738
  }
3206
2739
  };
3207
2740
 
3208
- // src/index.ts
3209
- init_errors();
3210
-
3211
2741
  // src/agents/zyfai/zyfai.siwx.ts
3212
- var import_viem7 = require("viem");
2742
+ var import_viem6 = require("viem");
3213
2743
  var import_siwe = require("siwe");
3214
2744
  var import_sdk2 = require("@zyfai/sdk");
3215
2745
 
@@ -3223,11 +2753,39 @@ var storage2 = () => {
3223
2753
  return null;
3224
2754
  }
3225
2755
  };
3226
- var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2756
+ var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
2757
+ var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
3227
2758
  var memorySiwxSessions = /* @__PURE__ */ new Map();
2759
+ var readLegacySiwxSession = (store, address) => {
2760
+ if (!store) return null;
2761
+ const prefix = legacyKeyPrefix2(address);
2762
+ const legacyKeys = [];
2763
+ try {
2764
+ for (let i = 0; i < store.length; i++) {
2765
+ const key = store.key(i);
2766
+ if (key?.startsWith(prefix)) legacyKeys.push(key);
2767
+ }
2768
+ } catch {
2769
+ return null;
2770
+ }
2771
+ let adopted = null;
2772
+ for (const key of legacyKeys) {
2773
+ if (!adopted) {
2774
+ try {
2775
+ adopted = JSON.parse(store.getItem(key) ?? "");
2776
+ } catch {
2777
+ }
2778
+ }
2779
+ try {
2780
+ store.removeItem(key);
2781
+ } catch {
2782
+ }
2783
+ }
2784
+ return adopted;
2785
+ };
3228
2786
  var readSiwxSession = (address, chainId) => {
3229
2787
  if (typeof window === "undefined") return null;
3230
- const key = buildKey2(address, chainId);
2788
+ const key = buildKey2(address);
3231
2789
  const store = storage2();
3232
2790
  let raw = null;
3233
2791
  try {
@@ -3247,11 +2805,16 @@ var readSiwxSession = (address, chainId) => {
3247
2805
  return null;
3248
2806
  }
3249
2807
  }
2808
+ const legacy = readLegacySiwxSession(store, address);
2809
+ if (legacy) {
2810
+ writeSiwxSession(address, chainId, legacy);
2811
+ return legacy;
2812
+ }
3250
2813
  return memorySiwxSessions.get(key) ?? null;
3251
2814
  };
3252
- var writeSiwxSession = (address, chainId, session) => {
2815
+ var writeSiwxSession = (address, _chainId, session) => {
3253
2816
  if (typeof window === "undefined") return;
3254
- const key = buildKey2(address, chainId);
2817
+ const key = buildKey2(address);
3255
2818
  memorySiwxSessions.set(key, session);
3256
2819
  const store = storage2();
3257
2820
  try {
@@ -3259,14 +2822,15 @@ var writeSiwxSession = (address, chainId, session) => {
3259
2822
  } catch {
3260
2823
  }
3261
2824
  };
3262
- var clearSiwxSession = (address, chainId) => {
3263
- const key = buildKey2(address, chainId);
2825
+ var clearSiwxSession = (address, _chainId) => {
2826
+ const key = buildKey2(address);
3264
2827
  memorySiwxSessions.delete(key);
3265
2828
  const store = storage2();
3266
2829
  try {
3267
2830
  store?.removeItem(key);
3268
2831
  } catch {
3269
2832
  }
2833
+ readLegacySiwxSession(store, address);
3270
2834
  };
3271
2835
 
3272
2836
  // src/agents/zyfai/zyfai.siwx.ts
@@ -3302,7 +2866,7 @@ function buildSIWXConfig(deps) {
3302
2866
  issuedAt,
3303
2867
  toString() {
3304
2868
  return new import_siwe.SiweMessage({
3305
- address: (0, import_viem7.getAddress)(accountAddress),
2869
+ address: (0, import_viem6.getAddress)(accountAddress),
3306
2870
  chainId: numericChainId(chainId),
3307
2871
  domain,
3308
2872
  uri,
@@ -3330,9 +2894,12 @@ function buildSIWXConfig(deps) {
3330
2894
  }
3331
2895
  if (!stored) return [];
3332
2896
  const session = {
3333
- // `stored.data.chainId` is a plain string in the cache (kept AppKit-free);
3334
- // it always holds a valid CaipNetworkId here, so narrow at the boundary.
3335
- data: stored.data,
2897
+ // `stored.data` is kept AppKit-free in the cache, so narrow at the
2898
+ // boundary. Echo the REQUESTED chain rather than the one originally
2899
+ // signed: the Zyfai JWT is account-scoped (no chain claim), so one
2900
+ // signature is valid for every chain, and AppKit would otherwise treat
2901
+ // the session as not covering the active network and re-prompt.
2902
+ data: { ...stored.data, chainId },
3336
2903
  message: stored.message,
3337
2904
  signature: stored.signature
3338
2905
  };