@owney/sdk 0.6.5-beta.1 → 0.6.5-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
@@ -18,8 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
20
  // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
23
  AgentChainIncompatibleError: () => AgentChainIncompatibleError,
24
24
  AgentNotFoundError: () => AgentNotFoundError,
25
25
  InvalidHistoryCursorError: () => InvalidHistoryCursorError,
@@ -28,7 +28,7 @@ __export(src_exports, {
28
28
  OwneySDK: () => OwneySDK,
29
29
  createOwneySIWX: () => createOwneySIWX
30
30
  });
31
- module.exports = __toCommonJS(src_exports);
31
+ module.exports = __toCommonJS(index_exports);
32
32
 
33
33
  // src/agents/zyfai/zyfai.agent.ts
34
34
  var import_sdk = require("@zyfai/sdk");
@@ -37,8 +37,8 @@ var import_chains = require("viem/chains");
37
37
 
38
38
  // src/types/config.ts
39
39
  var P_SUPPORTED_CHAINS = {
40
- chainIds: [8453, 42161],
41
- chains: ["BASE", "ARBITRUM"]
40
+ chainIds: [8453, 42161, 1],
41
+ chains: ["BASE", "ARBITRUM", "ETHEREUM"]
42
42
  };
43
43
  var SUPPORTED_TOKENS = ["USDC", "USDT", "WETH"];
44
44
  var SUPPORTED_CHAIN_IDS = P_SUPPORTED_CHAINS.chainIds;
@@ -73,6 +73,18 @@ var SupportedAssets = [
73
73
  symbol: "WETH",
74
74
  chainId: 42161,
75
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
76
88
  }
77
89
  ];
78
90
 
@@ -139,8 +151,7 @@ var isValidChainId = (chainId) => {
139
151
  function hexToDecimal(hex, decimals = 6) {
140
152
  const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
141
153
  const parsed = BigInt(normalized);
142
- if (decimals <= 0)
143
- return Number(parsed);
154
+ if (decimals <= 0) return Number(parsed);
144
155
  const divisor = BigInt(10 ** decimals);
145
156
  const whole = parsed / divisor;
146
157
  const remainder = parsed % divisor;
@@ -183,7 +194,8 @@ function mapWithdraw(raw) {
183
194
  }
184
195
  var CHAIN_ID_TO_NAME = {
185
196
  8453: "BASE",
186
- 42161: "ARBITRUM"
197
+ 42161: "ARBITRUM",
198
+ 1: "ETHEREUM"
187
199
  };
188
200
  var NAME_TO_CHAIN_ID = Object.entries(
189
201
  CHAIN_ID_TO_NAME
@@ -193,8 +205,7 @@ var NAME_TO_CHAIN_ID = Object.entries(
193
205
  }, {});
194
206
  function resolveChainId(chain) {
195
207
  const asNum = Number(chain);
196
- if (Number.isFinite(asNum) && asNum > 0)
197
- return asNum;
208
+ if (Number.isFinite(asNum) && asNum > 0) return asNum;
198
209
  return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
199
210
  }
200
211
  function mapBalances(raw, _chainId, smartWallet) {
@@ -278,41 +289,39 @@ function mapEarnings(raw, smartWallet) {
278
289
  };
279
290
  }
280
291
  function mapWeightedApyByChain(raw) {
281
- if (!raw)
282
- return void 0;
292
+ if (!raw) return void 0;
283
293
  const out = {};
284
294
  for (const [chainKey, tokenApy] of Object.entries(raw)) {
285
295
  const chainId = Number(chainKey);
286
- if (!SUPPORTED_CHAIN_IDS.includes(chainId))
287
- continue;
296
+ if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
288
297
  const perAsset = {};
289
298
  for (const [symbol, apy] of Object.entries(tokenApy)) {
290
299
  const token = symbol;
291
- if (!SUPPORTED_TOKENS.includes(token))
292
- continue;
300
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
293
301
  perAsset[token] = apy;
294
302
  }
295
- if (Object.keys(perAsset).length > 0)
296
- out[chainId] = perAsset;
303
+ if (Object.keys(perAsset).length > 0) out[chainId] = perAsset;
297
304
  }
298
305
  return Object.keys(out).length > 0 ? out : void 0;
299
306
  }
300
- function rawPoolApyForChain(entry, chainId) {
307
+ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
301
308
  let weightedSum = 0;
302
309
  let totalBalance = 0;
303
310
  for (const p of entry.positions ?? []) {
304
- if (p.chainId !== chainId)
305
- continue;
311
+ if (p.chainId !== chainId) continue;
312
+ if (tokenSymbol && p.tokenSymbol !== tokenSymbol) continue;
306
313
  const balance = p.balance ?? 0;
307
- if (balance <= 0 || typeof p.apy !== "number")
308
- continue;
314
+ if (balance <= 0 || typeof p.apy !== "number") continue;
309
315
  weightedSum += p.apy * balance;
310
316
  totalBalance += balance;
311
317
  }
312
318
  return totalBalance > 0 ? weightedSum / totalBalance : null;
313
319
  }
314
- function mapApyHistory(raw, chainId) {
315
- 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));
316
325
  return {
317
326
  walletAddress: raw.walletAddress,
318
327
  weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
@@ -335,6 +344,7 @@ function mapEntries(rawEntries, chainId) {
335
344
  "Withdraw from protocol": "Withdraw",
336
345
  Rebalance: "Rebalance"
337
346
  };
347
+ void chainId;
338
348
  return rawEntries.map((entry) => {
339
349
  const rawLog = entry.rebalanceLog;
340
350
  const positions = entry.positions ?? [];
@@ -413,8 +423,7 @@ function mapApyByStrategy(raw) {
413
423
  const supported = SupportedAssets.find(
414
424
  (asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
415
425
  );
416
- if (!supported)
417
- continue;
426
+ if (!supported) continue;
418
427
  const chainKey = supported.chainId;
419
428
  const symbolKey = supported.symbol;
420
429
  const bucket = apyPerAsset[chainKey] ?? {};
@@ -444,10 +453,8 @@ function computeAllocationApy(positions) {
444
453
  totalValue += value;
445
454
  const chainId = resolveChainId(p.chain);
446
455
  const token = p.asset;
447
- if (!SUPPORTED_CHAIN_IDS.includes(chainId))
448
- continue;
449
- if (!SUPPORTED_TOKENS.includes(token))
450
- continue;
456
+ if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
457
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
451
458
  const perAsset = buckets[chainId] ?? {};
452
459
  const cell = perAsset[token] ?? { weightedSum: 0, value: 0 };
453
460
  cell.weightedSum += apy * value;
@@ -464,8 +471,7 @@ function computeAllocationApy(positions) {
464
471
  out[token] = cell.weightedSum / cell.value;
465
472
  }
466
473
  }
467
- if (Object.keys(out).length > 0)
468
- apyByChainAndAsset[chainId] = out;
474
+ if (Object.keys(out).length > 0) apyByChainAndAsset[chainId] = out;
469
475
  }
470
476
  const totalApy = totalValue > 0 ? String(weightedSum / totalValue) : "0";
471
477
  return { totalApy, apyByChainAndAsset };
@@ -482,19 +488,14 @@ function extractWithdrawnAmount(logs, recipient, token, decimals) {
482
488
  let total = 0n;
483
489
  let matched = false;
484
490
  for (const log of logs) {
485
- if (log.address.toLowerCase() !== wantToken)
486
- continue;
487
- if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC)
488
- continue;
489
- if (topicToAddress(log.topics[2]) !== wantRecipient)
490
- continue;
491
- if (!log.data || log.data === "0x")
492
- 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;
493
495
  total += BigInt(log.data);
494
496
  matched = true;
495
497
  }
496
- if (!matched)
497
- return void 0;
498
+ if (!matched) return void 0;
498
499
  return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
499
500
  }
500
501
 
@@ -510,8 +511,7 @@ function encodeHistoryCursor(payload) {
510
511
  return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
511
512
  }
512
513
  function decodeHistoryCursor(token) {
513
- if (!token)
514
- throw new InvalidHistoryCursorError("Cursor is empty.");
514
+ if (!token) throw new InvalidHistoryCursorError("Cursor is empty.");
515
515
  let parsed;
516
516
  try {
517
517
  const json = Buffer.from(token, "base64").toString("utf8");
@@ -528,8 +528,7 @@ function decodeHistoryCursor(token) {
528
528
  // src/agents/zyfai/zyfai.auth-cache.ts
529
529
  var KEY_PREFIX = "owney.zyfai.session";
530
530
  var storage = () => {
531
- if (typeof window === "undefined")
532
- return null;
531
+ if (typeof window === "undefined") return null;
533
532
  try {
534
533
  return window.localStorage;
535
534
  } catch {
@@ -539,15 +538,13 @@ var storage = () => {
539
538
  var buildKey = (address, chainId) => `${KEY_PREFIX}:${address.toLowerCase()}:${chainId}`;
540
539
  var isJwtExpired = (token) => {
541
540
  const parts = token.split(".");
542
- if (parts.length !== 3)
543
- return false;
541
+ if (parts.length !== 3) return false;
544
542
  try {
545
543
  const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
546
544
  const padded = payload + "=".repeat((4 - payload.length % 4) % 4);
547
545
  const decoded = typeof atob === "function" ? atob(padded) : Buffer.from(padded, "base64").toString("utf8");
548
546
  const claims = JSON.parse(decoded);
549
- if (typeof claims.exp !== "number")
550
- return false;
547
+ if (typeof claims.exp !== "number") return false;
551
548
  return Date.now() / 1e3 >= claims.exp - 30;
552
549
  } catch {
553
550
  return false;
@@ -555,11 +552,9 @@ var isJwtExpired = (token) => {
555
552
  };
556
553
  var readSession = (address, chainId) => {
557
554
  const store = storage();
558
- if (!store)
559
- return null;
555
+ if (!store) return null;
560
556
  const raw = store.getItem(buildKey(address, chainId));
561
- if (!raw)
562
- return null;
557
+ if (!raw) return null;
563
558
  try {
564
559
  const parsed = JSON.parse(raw);
565
560
  if (!parsed.token || isJwtExpired(parsed.token)) {
@@ -574,8 +569,7 @@ var readSession = (address, chainId) => {
574
569
  };
575
570
  var writeSession = (address, chainId, session) => {
576
571
  const store = storage();
577
- if (!store)
578
- return;
572
+ if (!store) return;
579
573
  try {
580
574
  store.setItem(buildKey(address, chainId), JSON.stringify(session));
581
575
  } catch {
@@ -583,8 +577,7 @@ var writeSession = (address, chainId, session) => {
583
577
  };
584
578
  var clearSession = (address, chainId) => {
585
579
  const store = storage();
586
- if (!store)
587
- return;
580
+ if (!store) return;
588
581
  try {
589
582
  store.removeItem(buildKey(address, chainId));
590
583
  } catch {
@@ -593,8 +586,7 @@ var clearSession = (address, chainId) => {
593
586
 
594
587
  // src/agents/zyfai/autoSelect.ts
595
588
  function buildAutoSelectUpdate(current, asset) {
596
- if (current.autoSelectProtocols === true)
597
- return null;
589
+ if (current.autoSelectProtocols === true) return null;
598
590
  return {
599
591
  asset,
600
592
  autoSelectProtocols: true,
@@ -605,16 +597,18 @@ function buildAutoSelectUpdate(current, asset) {
605
597
  // src/agents/zyfai/zyfai.agent.ts
606
598
  var DEFAULT_ZYFAI_RPC_URLS = {
607
599
  8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
608
- 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"
609
602
  };
610
603
  var WETH_ADDRESS_BY_CHAIN = {
611
604
  8453: "0x4200000000000000000000000000000000000006",
612
- 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
605
+ 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
606
+ 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
613
607
  };
614
- var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
608
+ var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
615
609
  var ZyfaiAgent = class {
616
610
  id = "zyfai";
617
- supportedChainIds = [8453, 42161];
611
+ supportedChainIds = [8453, 42161, 1];
618
612
  supportedAssets = [
619
613
  {
620
614
  chainId: 8453,
@@ -631,6 +625,19 @@ var ZyfaiAgent = class {
631
625
  { symbol: "USDC", minDepositAmount: "1500000" },
632
626
  { symbol: "WETH", minDepositAmount: "500000000000000" }
633
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 (mainnet gas only pays off on
634
+ // large positions). USDC: 10,000 (10_000 * 1e6). WETH: 5 (5 * 1e18).
635
+ // NOTE: the @zyfai/sdk README claims WETH has no minimum — that's stale;
636
+ // the shipped code enforces 5 WETH, so match it or deposits reject on-chain.
637
+ assets: [
638
+ { symbol: "USDC", minDepositAmount: "10000000000" },
639
+ { symbol: "WETH", minDepositAmount: "5000000000000000000" }
640
+ ]
634
641
  }
635
642
  ];
636
643
  sdk;
@@ -654,8 +661,7 @@ var ZyfaiAgent = class {
654
661
  }
655
662
  getPublicClient(chainId) {
656
663
  const cached = this.publicClients.get(chainId);
657
- if (cached)
658
- return cached;
664
+ if (cached) return cached;
659
665
  const client = (0, import_viem.createPublicClient)({
660
666
  chain: VIEM_CHAIN[chainId],
661
667
  transport: (0, import_viem.http)(this.rpcUrls[chainId])
@@ -686,8 +692,7 @@ var ZyfaiAgent = class {
686
692
  const withdrawals = entries.filter(
687
693
  (e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
688
694
  );
689
- if (withdrawals.length === 0)
690
- return;
695
+ if (withdrawals.length === 0) return;
691
696
  const client = this.getPublicClient(chainId);
692
697
  await Promise.all(
693
698
  withdrawals.map(async (entry) => {
@@ -700,8 +705,7 @@ var ZyfaiAgent = class {
700
705
  ) ?? SupportedAssets.find(
701
706
  (a) => a.chainId === chainId && a.symbol === "USDC"
702
707
  );
703
- if (!asset)
704
- return;
708
+ if (!asset) return;
705
709
  const cacheKey = `${txHash}:${asset.address}`;
706
710
  const cached = this.withdrawAmountCache.get(cacheKey);
707
711
  if (cached !== void 0) {
@@ -738,13 +742,11 @@ var ZyfaiAgent = class {
738
742
  * for some apps and the patch only matters in the browser anyway.
739
743
  */
740
744
  installAuthCache() {
741
- if (typeof window === "undefined")
742
- return;
745
+ if (typeof window === "undefined") return;
743
746
  const internals = this.sdk;
744
747
  const original = internals.authenticateUser.bind(internals);
745
748
  internals.authenticateUser = async () => {
746
- if (internals.authenticatedUserId !== null)
747
- return;
749
+ if (internals.authenticatedUserId !== null) return;
748
750
  const address = internals.walletClient?.account?.address;
749
751
  const chainId = internals.currentChainId;
750
752
  if (address && chainId) {
@@ -819,12 +821,10 @@ var ZyfaiAgent = class {
819
821
  return await this.sdk.connectAccount(provider, chainId);
820
822
  } catch (error) {
821
823
  const message = error instanceof Error ? error.message : String(error);
822
- if (!message.toLowerCase().includes("unauthorized"))
823
- throw error;
824
+ if (!message.toLowerCase().includes("unauthorized")) throw error;
824
825
  const internals = this.sdk;
825
826
  const address = internals.walletClient?.account?.address;
826
- if (address)
827
- clearSession(address, chainId);
827
+ if (address) clearSession(address, chainId);
828
828
  return await this.sdk.connectAccount(provider, chainId);
829
829
  }
830
830
  }
@@ -954,10 +954,10 @@ var ZyfaiAgent = class {
954
954
  const raw = await this.sdk.getOnchainEarnings(smartWallet);
955
955
  return mapEarnings(raw, smartWallet);
956
956
  }
957
- async getAccountApy(state, chainId, days) {
957
+ async getAccountApy(state, chainId, days, tokenSymbol) {
958
958
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
959
959
  const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
960
- return mapApyHistory(raw, chainId);
960
+ return mapApyHistory(raw, chainId, tokenSymbol);
961
961
  }
962
962
  async getHistory(state, chainId, options) {
963
963
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
@@ -1022,8 +1022,7 @@ var ZyfaiAgent = class {
1022
1022
  },
1023
1023
  asset
1024
1024
  );
1025
- if (!update)
1026
- return false;
1025
+ if (!update) return false;
1027
1026
  await this.sdk.updateUserProfile(update);
1028
1027
  return true;
1029
1028
  }
@@ -1112,8 +1111,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
1112
1111
  const tokenBalance = agentBalance?.tokens.find(
1113
1112
  (t) => t.chainId === chainId && t.asset.toUpperCase() === target
1114
1113
  );
1115
- if (!tokenBalance)
1116
- return { agent, balance: 0n };
1114
+ if (!tokenBalance) return { agent, balance: 0n };
1117
1115
  return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
1118
1116
  });
1119
1117
  }
@@ -1130,11 +1128,9 @@ function planProportionalShares(balances, requested, totalAvailable) {
1130
1128
  return diff > 0n ? 1 : diff < 0n ? -1 : 0;
1131
1129
  });
1132
1130
  for (const p of byHeadroom) {
1133
- if (remainder === 0n)
1134
- break;
1131
+ if (remainder === 0n) break;
1135
1132
  const headroom = p.balance - p.planned;
1136
- if (headroom <= 0n)
1137
- continue;
1133
+ if (headroom <= 0n) continue;
1138
1134
  const take = headroom < remainder ? headroom : remainder;
1139
1135
  p.planned += take;
1140
1136
  remainder -= take;
@@ -1163,8 +1159,7 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
1163
1159
  (s, c) => s + (c.balance - c.planned),
1164
1160
  0n
1165
1161
  );
1166
- if (totalHeadroom === 0n)
1167
- return;
1162
+ if (totalHeadroom === 0n) return;
1168
1163
  let distributed = 0n;
1169
1164
  for (const c of candidates) {
1170
1165
  const headroom = c.balance - c.planned;
@@ -1175,11 +1170,9 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
1175
1170
  }
1176
1171
  let leftover = amount - distributed;
1177
1172
  for (const c of candidates) {
1178
- if (leftover === 0n)
1179
- break;
1173
+ if (leftover === 0n) break;
1180
1174
  const headroom = c.balance - c.planned;
1181
- if (headroom <= 0n)
1182
- continue;
1175
+ if (headroom <= 0n) continue;
1183
1176
  const take = headroom < leftover ? headroom : leftover;
1184
1177
  c.planned += take;
1185
1178
  leftover -= take;
@@ -1196,16 +1189,13 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1196
1189
  for (const id of Object.keys(agentApys)) {
1197
1190
  const cells = agentApys[id].apyByChainAndAsset;
1198
1191
  const balance = agentBalances[id] ?? 0;
1199
- if (!cells || balance <= 0)
1200
- continue;
1192
+ if (!cells || balance <= 0) continue;
1201
1193
  for (const [chainKey, perAsset] of Object.entries(cells)) {
1202
- if (!perAsset)
1203
- continue;
1194
+ if (!perAsset) continue;
1204
1195
  const chainId = Number(chainKey);
1205
1196
  for (const [asset, apyValue] of Object.entries(perAsset)) {
1206
1197
  const apy = Number(apyValue ?? 0);
1207
- if (apy === 0)
1208
- continue;
1198
+ if (apy === 0) continue;
1209
1199
  sums[chainId] ??= {};
1210
1200
  weights[chainId] ??= {};
1211
1201
  sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
@@ -1219,8 +1209,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1219
1209
  const perAssetOut = {};
1220
1210
  for (const asset of Object.keys(sums[chainId])) {
1221
1211
  const w = weights[chainId][asset];
1222
- if (w > 0)
1223
- perAssetOut[asset] = sums[chainId][asset] / w;
1212
+ if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
1224
1213
  }
1225
1214
  if (Object.keys(perAssetOut).length > 0) {
1226
1215
  out[chainId] = perAssetOut;
@@ -1277,7 +1266,10 @@ async function postSponsorTransferAuth(input) {
1277
1266
  try {
1278
1267
  res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
1279
1268
  method: "POST",
1280
- 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
+ },
1281
1273
  body: JSON.stringify(input.body)
1282
1274
  });
1283
1275
  } catch (networkError) {
@@ -1297,7 +1289,13 @@ async function postSponsorTransferAuth(input) {
1297
1289
  throw new OwneyError(
1298
1290
  "SPONSOR_REQUEST_FAILED",
1299
1291
  `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1300
- { 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
+ }
1301
1299
  );
1302
1300
  }
1303
1301
  return parsed.data;
@@ -1308,7 +1306,10 @@ async function postSponsorPermit2Transfer(input) {
1308
1306
  try {
1309
1307
  res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
1310
1308
  method: "POST",
1311
- headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
1309
+ headers: {
1310
+ "content-type": "application/json",
1311
+ "x-owney-api-key": input.apiKey
1312
+ },
1312
1313
  body: JSON.stringify(input.body)
1313
1314
  });
1314
1315
  } catch (networkError) {
@@ -1331,7 +1332,7 @@ async function postSponsorPermit2Transfer(input) {
1331
1332
  {
1332
1333
  statusCode: res.status,
1333
1334
  responseBody: text.slice(0, 500),
1334
- safeToFallback: res.status >= 400 && res.status < 500
1335
+ safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
1335
1336
  }
1336
1337
  );
1337
1338
  }
@@ -1341,9 +1342,12 @@ async function getSponsorRelayerAddress(input) {
1341
1342
  const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1342
1343
  let res;
1343
1344
  try {
1344
- res = await fetch(`${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`, {
1345
- headers: { "x-owney-api-key": input.apiKey }
1346
- });
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
+ );
1347
1351
  } catch (networkError) {
1348
1352
  throw new OwneyError(
1349
1353
  "SPONSOR_REQUEST_FAILED",
@@ -1361,7 +1365,11 @@ async function getSponsorRelayerAddress(input) {
1361
1365
  throw new OwneyError(
1362
1366
  "SPONSOR_REQUEST_FAILED",
1363
1367
  `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1364
- { statusCode: res.status, responseBody: text.slice(0, 500), safeToFallback: true }
1368
+ {
1369
+ statusCode: res.status,
1370
+ responseBody: text.slice(0, 500),
1371
+ safeToFallback: true
1372
+ }
1365
1373
  );
1366
1374
  }
1367
1375
  return parsed.data.relayer;
@@ -1548,18 +1556,21 @@ function decodeMultiAgentCursor(token) {
1548
1556
  }
1549
1557
  var SPONSORED_USDC_BY_CHAIN = {
1550
1558
  8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1551
- 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
1559
+ 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
1560
+ 1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
1552
1561
  };
1553
1562
  var VIEM_CHAIN2 = {
1554
1563
  8453: import_chains2.base,
1555
- 42161: import_chains2.arbitrum
1564
+ 42161: import_chains2.arbitrum,
1565
+ 1: import_chains2.mainnet
1556
1566
  };
1557
1567
  var SPONSORED_WETH_BY_CHAIN = {
1558
1568
  8453: "0x4200000000000000000000000000000000000006",
1559
- 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
1569
+ 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
1570
+ 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
1560
1571
  };
1561
1572
  function shouldFallbackToUserPaid(error, asset, appCallback) {
1562
- return asset === "WETH" && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
1573
+ return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
1563
1574
  }
1564
1575
  var OwneySDK = class {
1565
1576
  agents = /* @__PURE__ */ new Map();
@@ -1573,12 +1584,14 @@ var OwneySDK = class {
1573
1584
  state = null;
1574
1585
  apiKey;
1575
1586
  zyfaiRpcUrls;
1587
+ routingApiBaseUrl;
1576
1588
  cachedSponsoredCallback = null;
1577
1589
  cachedWethSponsoredCallback = null;
1578
1590
  initializingAgentsPromise = null;
1579
1591
  constructor(config) {
1580
1592
  this.apiKey = config.apiKey;
1581
1593
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
1594
+ this.routingApiBaseUrl = config.routingApiBaseUrl;
1582
1595
  }
1583
1596
  /**
1584
1597
  * Establish connection state for all subsequent SDK calls.
@@ -1633,8 +1646,7 @@ var OwneySDK = class {
1633
1646
  return this.state?.chainId ?? null;
1634
1647
  }
1635
1648
  requireState() {
1636
- if (!this.state)
1637
- throw new NotConnectedError();
1649
+ if (!this.state) throw new NotConnectedError();
1638
1650
  return this.state;
1639
1651
  }
1640
1652
  requireChainId() {
@@ -1664,12 +1676,12 @@ var OwneySDK = class {
1664
1676
  * `TransferWithAuthorization`, then POSTs to the sponsor API.
1665
1677
  */
1666
1678
  getDefaultSponsoredCallback() {
1667
- if (this.cachedSponsoredCallback)
1668
- return this.cachedSponsoredCallback;
1679
+ if (this.cachedSponsoredCallback) return this.cachedSponsoredCallback;
1669
1680
  const provider = this.requireConnectedProvider();
1670
1681
  const owner = this.state.walletAddress;
1671
1682
  this.cachedSponsoredCallback = makeSponsoredDepositCallback({
1672
1683
  apiKey: this.apiKey,
1684
+ baseUrl: this.routingApiBaseUrl,
1673
1685
  ownerAddress: owner,
1674
1686
  tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
1675
1687
  // Casts work around viem's chain-narrowed Client vs the generic
@@ -1700,6 +1712,7 @@ var OwneySDK = class {
1700
1712
  const owner = this.state.walletAddress;
1701
1713
  this.cachedWethSponsoredCallback = makeSponsoredWethCallback({
1702
1714
  apiKey: this.apiKey,
1715
+ baseUrl: this.routingApiBaseUrl,
1703
1716
  ownerAddress: owner,
1704
1717
  tokenAddressByChain: SPONSORED_WETH_BY_CHAIN,
1705
1718
  // Casts work around viem's chain-narrowed Client vs the generic
@@ -1728,22 +1741,19 @@ var OwneySDK = class {
1728
1741
  const active = /* @__PURE__ */ new Map();
1729
1742
  for (const id of this.activeAgents) {
1730
1743
  const agent = this.agents.get(id);
1731
- if (agent)
1732
- active.set(id, agent);
1744
+ if (agent) active.set(id, agent);
1733
1745
  }
1734
1746
  return active;
1735
1747
  }
1736
1748
  async ensureAgentsInitialized() {
1737
- if (this.agents.size > 0)
1738
- return;
1749
+ if (this.agents.size > 0) return;
1739
1750
  if (!this.initializingAgentsPromise) {
1740
1751
  this.initializingAgentsPromise = (async () => {
1741
1752
  const agentKeys = await fetchAgentKeys(this.apiKey);
1742
1753
  this.disabledAgents.clear();
1743
1754
  for (const { key, agent_type, is_enabled } of agentKeys) {
1744
1755
  const agent = this.createAgent(agent_type, key);
1745
- if (!agent)
1746
- continue;
1756
+ if (!agent) continue;
1747
1757
  this.agents.set(agent_type, agent);
1748
1758
  if (is_enabled === false) {
1749
1759
  this.disabledAgents.add(agent_type);
@@ -1982,10 +1992,9 @@ var OwneySDK = class {
1982
1992
  await this.approvePermit2();
1983
1993
  continue;
1984
1994
  }
1985
- if (!shouldFallbackToUserPaid(error, asset, appCallback))
1986
- throw error;
1995
+ if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
1987
1996
  console.warn(
1988
- "[owney-sdk] WETH sponsorship unavailable, falling back to user-paid deposit:",
1997
+ `[owney-sdk] ${asset} sponsorship unavailable, falling back to user-paid deposit:`,
1989
1998
  error
1990
1999
  );
1991
2000
  return attempt(void 0);
@@ -2000,8 +2009,7 @@ var OwneySDK = class {
2000
2009
  return BigInt(assetEntry?.minDepositAmount ?? "0");
2001
2010
  }
2002
2011
  splitDepositAmount(totalAmount, agents, chainId, asset, exempt = /* @__PURE__ */ new Set()) {
2003
- if (agents.length === 0)
2004
- return [];
2012
+ if (agents.length === 0) return [];
2005
2013
  const perAgent = totalAmount / BigInt(agents.length);
2006
2014
  const remainder = totalAmount % BigInt(agents.length);
2007
2015
  const splits = agents.map((agent, i) => ({
@@ -2025,10 +2033,8 @@ var OwneySDK = class {
2025
2033
  async validateMinDepositAmount(agent, state, chainId, asset, amount) {
2026
2034
  const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
2027
2035
  const parsedAmount = BigInt(amount);
2028
- if (parsedAmount >= minDepositAmount)
2029
- return;
2030
- if (await this.hasExistingBalance(agent, state, chainId, asset))
2031
- return;
2036
+ if (parsedAmount >= minDepositAmount) return;
2037
+ if (await this.hasExistingBalance(agent, state, chainId, asset)) return;
2032
2038
  throw new OwneyError(
2033
2039
  "DEPOSIT_AMOUNT_BELOW_MINIMUM",
2034
2040
  `Amount "${amount}" is below the required minimum deposit "${minDepositAmount.toString()}" for agent "${agent.id}" on chain ${chainId} for asset "${asset}".`,
@@ -2192,8 +2198,7 @@ var OwneySDK = class {
2192
2198
  const agentErrors = {};
2193
2199
  for (let i = 0; i < plans.length; i++) {
2194
2200
  const p = plans[i];
2195
- if (p.planned === 0n)
2196
- continue;
2201
+ if (p.planned === 0n) continue;
2197
2202
  try {
2198
2203
  results[p.agent.id] = await p.agent.withdraw(
2199
2204
  state,
@@ -2327,19 +2332,30 @@ var OwneySDK = class {
2327
2332
  */
2328
2333
  async getAccountApy({
2329
2334
  agentId,
2330
- days
2335
+ days,
2336
+ tokenSymbol
2331
2337
  }) {
2332
2338
  const state = this.requireState();
2333
2339
  const chainId = this.requireChainId();
2334
2340
  if (agentId) {
2335
- return this.getAgent(agentId).getAccountApy(state, chainId, days);
2341
+ return this.getAgent(agentId).getAccountApy(
2342
+ state,
2343
+ chainId,
2344
+ days,
2345
+ tokenSymbol
2346
+ );
2336
2347
  }
2337
2348
  const activeAgents = this.getActiveAgents();
2338
2349
  const entries = [...activeAgents.entries()];
2339
2350
  const [apyResults, balanceResults] = await Promise.all([
2340
2351
  Promise.all(
2341
2352
  entries.map(async ([id, agent]) => {
2342
- const apy = await agent.getAccountApy(state, chainId, days);
2353
+ const apy = await agent.getAccountApy(
2354
+ state,
2355
+ chainId,
2356
+ days,
2357
+ tokenSymbol
2358
+ );
2343
2359
  return [id, apy];
2344
2360
  })
2345
2361
  ),
@@ -2362,15 +2378,13 @@ var OwneySDK = class {
2362
2378
  let relevantBalance = 0;
2363
2379
  for (const id of Object.keys(results)) {
2364
2380
  const agentApy = Number(results[id].weightedApyAfterFee ?? 0);
2365
- if (agentApy === 0)
2366
- continue;
2381
+ if (agentApy === 0) continue;
2367
2382
  relevantBalance += balances[id];
2368
2383
  }
2369
2384
  if (relevantBalance > 0) {
2370
2385
  for (const id of Object.keys(results)) {
2371
2386
  const agentApy = Number(results[id].weightedApyAfterFee ?? 0);
2372
- if (agentApy === 0)
2373
- continue;
2387
+ if (agentApy === 0) continue;
2374
2388
  const weight = balances[id] / relevantBalance;
2375
2389
  totalApy += agentApy * weight;
2376
2390
  }
@@ -2425,8 +2439,7 @@ var OwneySDK = class {
2425
2439
  const nextCursorMap = {};
2426
2440
  let hasMore = false;
2427
2441
  for (const { agentId: id, page } of perAgent) {
2428
- if (!page)
2429
- continue;
2442
+ if (!page) continue;
2430
2443
  merged.push(...page.data);
2431
2444
  if (page.hasMore && page.nextCursor) {
2432
2445
  nextCursorMap[id] = page.nextCursor;
@@ -2435,16 +2448,12 @@ var OwneySDK = class {
2435
2448
  }
2436
2449
  merged.sort((a, b) => {
2437
2450
  const dateDiff = new Date(b.date).getTime() - new Date(a.date).getTime();
2438
- if (dateDiff !== 0)
2439
- return dateDiff;
2440
- if (a.agent !== b.agent)
2441
- 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;
2442
2453
  const aTx = a.transactions?.[0]?.txHashes?.[0] ?? "";
2443
2454
  const bTx = b.transactions?.[0]?.txHashes?.[0] ?? "";
2444
- if (aTx !== bTx)
2445
- return aTx < bTx ? -1 : 1;
2446
- if (a.action !== b.action)
2447
- 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;
2448
2457
  return 0;
2449
2458
  });
2450
2459
  return {
@@ -2490,8 +2499,7 @@ var OwneySDK = class {
2490
2499
  const state = this.requireState();
2491
2500
  const chainId = this.requireChainId();
2492
2501
  const agent = this.getAgent(agentId);
2493
- if (typeof agent.ensureAutoSelectProtocols !== "function")
2494
- return false;
2502
+ if (typeof agent.ensureAutoSelectProtocols !== "function") return false;
2495
2503
  return agent.ensureAutoSelectProtocols(state, chainId, asset);
2496
2504
  }
2497
2505
  /**
@@ -2503,8 +2511,10 @@ var OwneySDK = class {
2503
2511
  * @returns the approval transaction hash.
2504
2512
  */
2505
2513
  async approvePermit2(asset = "WETH") {
2514
+ void asset;
2506
2515
  const state = this.requireState();
2507
2516
  const chainId = this.requireChainId();
2517
+ this.validateAssetSupport(this.getAgent("zyfai"), chainId, "WETH");
2508
2518
  const token = SPONSORED_WETH_BY_CHAIN[chainId];
2509
2519
  if (!token) {
2510
2520
  throw new OwneyError(
@@ -2644,8 +2654,7 @@ var import_sdk2 = require("@zyfai/sdk");
2644
2654
  // src/agents/zyfai/zyfai.siwx-cache.ts
2645
2655
  var KEY_PREFIX2 = "owney.siwx.session";
2646
2656
  var storage2 = () => {
2647
- if (typeof window === "undefined")
2648
- return null;
2657
+ if (typeof window === "undefined") return null;
2649
2658
  try {
2650
2659
  return window.localStorage;
2651
2660
  } catch {
@@ -2655,11 +2664,9 @@ var storage2 = () => {
2655
2664
  var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2656
2665
  var readSiwxSession = (address, chainId) => {
2657
2666
  const store = storage2();
2658
- if (!store)
2659
- return null;
2667
+ if (!store) return null;
2660
2668
  const raw = store.getItem(buildKey2(address, chainId));
2661
- if (!raw)
2662
- return null;
2669
+ if (!raw) return null;
2663
2670
  try {
2664
2671
  return JSON.parse(raw);
2665
2672
  } catch {
@@ -2669,8 +2676,7 @@ var readSiwxSession = (address, chainId) => {
2669
2676
  };
2670
2677
  var writeSiwxSession = (address, chainId, session) => {
2671
2678
  const store = storage2();
2672
- if (!store)
2673
- return;
2679
+ if (!store) return;
2674
2680
  try {
2675
2681
  store.setItem(buildKey2(address, chainId), JSON.stringify(session));
2676
2682
  } catch {
@@ -2678,8 +2684,7 @@ var writeSiwxSession = (address, chainId, session) => {
2678
2684
  };
2679
2685
  var clearSiwxSession = (address, chainId) => {
2680
2686
  const store = storage2();
2681
- if (!store)
2682
- return;
2687
+ if (!store) return;
2683
2688
  try {
2684
2689
  store.removeItem(buildKey2(address, chainId));
2685
2690
  } catch {
@@ -2742,12 +2747,10 @@ function buildSIWXConfig(deps) {
2742
2747
  const jwt = readSession(address, id);
2743
2748
  const stored = readSiwxSession(address, id);
2744
2749
  if (!jwt) {
2745
- if (stored)
2746
- clearSiwxSession(address, id);
2750
+ if (stored) clearSiwxSession(address, id);
2747
2751
  return [];
2748
2752
  }
2749
- if (!stored)
2750
- return [];
2753
+ if (!stored) return [];
2751
2754
  const session = {
2752
2755
  // `stored.data.chainId` is a plain string in the cache (kept AppKit-free);
2753
2756
  // it always holds a valid CaipNetworkId here, so narrow at the boundary.