@owney/sdk 0.6.5-beta.1 → 0.6.5-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
@@ -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,12 @@ 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
76
82
  }
77
83
  ];
78
84
 
@@ -139,8 +145,7 @@ var isValidChainId = (chainId) => {
139
145
  function hexToDecimal(hex, decimals = 6) {
140
146
  const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
141
147
  const parsed = BigInt(normalized);
142
- if (decimals <= 0)
143
- return Number(parsed);
148
+ if (decimals <= 0) return Number(parsed);
144
149
  const divisor = BigInt(10 ** decimals);
145
150
  const whole = parsed / divisor;
146
151
  const remainder = parsed % divisor;
@@ -183,7 +188,8 @@ function mapWithdraw(raw) {
183
188
  }
184
189
  var CHAIN_ID_TO_NAME = {
185
190
  8453: "BASE",
186
- 42161: "ARBITRUM"
191
+ 42161: "ARBITRUM",
192
+ 1: "ETHEREUM"
187
193
  };
188
194
  var NAME_TO_CHAIN_ID = Object.entries(
189
195
  CHAIN_ID_TO_NAME
@@ -193,8 +199,7 @@ var NAME_TO_CHAIN_ID = Object.entries(
193
199
  }, {});
194
200
  function resolveChainId(chain) {
195
201
  const asNum = Number(chain);
196
- if (Number.isFinite(asNum) && asNum > 0)
197
- return asNum;
202
+ if (Number.isFinite(asNum) && asNum > 0) return asNum;
198
203
  return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
199
204
  }
200
205
  function mapBalances(raw, _chainId, smartWallet) {
@@ -278,41 +283,39 @@ function mapEarnings(raw, smartWallet) {
278
283
  };
279
284
  }
280
285
  function mapWeightedApyByChain(raw) {
281
- if (!raw)
282
- return void 0;
286
+ if (!raw) return void 0;
283
287
  const out = {};
284
288
  for (const [chainKey, tokenApy] of Object.entries(raw)) {
285
289
  const chainId = Number(chainKey);
286
- if (!SUPPORTED_CHAIN_IDS.includes(chainId))
287
- continue;
290
+ if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
288
291
  const perAsset = {};
289
292
  for (const [symbol, apy] of Object.entries(tokenApy)) {
290
293
  const token = symbol;
291
- if (!SUPPORTED_TOKENS.includes(token))
292
- continue;
294
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
293
295
  perAsset[token] = apy;
294
296
  }
295
- if (Object.keys(perAsset).length > 0)
296
- out[chainId] = perAsset;
297
+ if (Object.keys(perAsset).length > 0) out[chainId] = perAsset;
297
298
  }
298
299
  return Object.keys(out).length > 0 ? out : void 0;
299
300
  }
300
- function rawPoolApyForChain(entry, chainId) {
301
+ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
301
302
  let weightedSum = 0;
302
303
  let totalBalance = 0;
303
304
  for (const p of entry.positions ?? []) {
304
- if (p.chainId !== chainId)
305
- continue;
305
+ if (p.chainId !== chainId) continue;
306
+ if (tokenSymbol && p.tokenSymbol !== tokenSymbol) continue;
306
307
  const balance = p.balance ?? 0;
307
- if (balance <= 0 || typeof p.apy !== "number")
308
- continue;
308
+ if (balance <= 0 || typeof p.apy !== "number") continue;
309
309
  weightedSum += p.apy * balance;
310
310
  totalBalance += balance;
311
311
  }
312
312
  return totalBalance > 0 ? weightedSum / totalBalance : null;
313
313
  }
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));
314
+ function mapApyHistory(raw, chainId, tokenSymbol) {
315
+ const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
316
+ date,
317
+ apy: rawPoolApyForChain(entry, chainId, tokenSymbol)
318
+ })).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
316
319
  return {
317
320
  walletAddress: raw.walletAddress,
318
321
  weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
@@ -335,6 +338,7 @@ function mapEntries(rawEntries, chainId) {
335
338
  "Withdraw from protocol": "Withdraw",
336
339
  Rebalance: "Rebalance"
337
340
  };
341
+ void chainId;
338
342
  return rawEntries.map((entry) => {
339
343
  const rawLog = entry.rebalanceLog;
340
344
  const positions = entry.positions ?? [];
@@ -413,8 +417,7 @@ function mapApyByStrategy(raw) {
413
417
  const supported = SupportedAssets.find(
414
418
  (asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
415
419
  );
416
- if (!supported)
417
- continue;
420
+ if (!supported) continue;
418
421
  const chainKey = supported.chainId;
419
422
  const symbolKey = supported.symbol;
420
423
  const bucket = apyPerAsset[chainKey] ?? {};
@@ -444,10 +447,8 @@ function computeAllocationApy(positions) {
444
447
  totalValue += value;
445
448
  const chainId = resolveChainId(p.chain);
446
449
  const token = p.asset;
447
- if (!SUPPORTED_CHAIN_IDS.includes(chainId))
448
- continue;
449
- if (!SUPPORTED_TOKENS.includes(token))
450
- continue;
450
+ if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
451
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
451
452
  const perAsset = buckets[chainId] ?? {};
452
453
  const cell = perAsset[token] ?? { weightedSum: 0, value: 0 };
453
454
  cell.weightedSum += apy * value;
@@ -464,8 +465,7 @@ function computeAllocationApy(positions) {
464
465
  out[token] = cell.weightedSum / cell.value;
465
466
  }
466
467
  }
467
- if (Object.keys(out).length > 0)
468
- apyByChainAndAsset[chainId] = out;
468
+ if (Object.keys(out).length > 0) apyByChainAndAsset[chainId] = out;
469
469
  }
470
470
  const totalApy = totalValue > 0 ? String(weightedSum / totalValue) : "0";
471
471
  return { totalApy, apyByChainAndAsset };
@@ -482,19 +482,14 @@ function extractWithdrawnAmount(logs, recipient, token, decimals) {
482
482
  let total = 0n;
483
483
  let matched = false;
484
484
  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;
485
+ if (log.address.toLowerCase() !== wantToken) continue;
486
+ if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC) continue;
487
+ if (topicToAddress(log.topics[2]) !== wantRecipient) continue;
488
+ if (!log.data || log.data === "0x") continue;
493
489
  total += BigInt(log.data);
494
490
  matched = true;
495
491
  }
496
- if (!matched)
497
- return void 0;
492
+ if (!matched) return void 0;
498
493
  return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
499
494
  }
500
495
 
@@ -510,8 +505,7 @@ function encodeHistoryCursor(payload) {
510
505
  return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
511
506
  }
512
507
  function decodeHistoryCursor(token) {
513
- if (!token)
514
- throw new InvalidHistoryCursorError("Cursor is empty.");
508
+ if (!token) throw new InvalidHistoryCursorError("Cursor is empty.");
515
509
  let parsed;
516
510
  try {
517
511
  const json = Buffer.from(token, "base64").toString("utf8");
@@ -528,8 +522,7 @@ function decodeHistoryCursor(token) {
528
522
  // src/agents/zyfai/zyfai.auth-cache.ts
529
523
  var KEY_PREFIX = "owney.zyfai.session";
530
524
  var storage = () => {
531
- if (typeof window === "undefined")
532
- return null;
525
+ if (typeof window === "undefined") return null;
533
526
  try {
534
527
  return window.localStorage;
535
528
  } catch {
@@ -539,15 +532,13 @@ var storage = () => {
539
532
  var buildKey = (address, chainId) => `${KEY_PREFIX}:${address.toLowerCase()}:${chainId}`;
540
533
  var isJwtExpired = (token) => {
541
534
  const parts = token.split(".");
542
- if (parts.length !== 3)
543
- return false;
535
+ if (parts.length !== 3) return false;
544
536
  try {
545
537
  const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
546
538
  const padded = payload + "=".repeat((4 - payload.length % 4) % 4);
547
539
  const decoded = typeof atob === "function" ? atob(padded) : Buffer.from(padded, "base64").toString("utf8");
548
540
  const claims = JSON.parse(decoded);
549
- if (typeof claims.exp !== "number")
550
- return false;
541
+ if (typeof claims.exp !== "number") return false;
551
542
  return Date.now() / 1e3 >= claims.exp - 30;
552
543
  } catch {
553
544
  return false;
@@ -555,11 +546,9 @@ var isJwtExpired = (token) => {
555
546
  };
556
547
  var readSession = (address, chainId) => {
557
548
  const store = storage();
558
- if (!store)
559
- return null;
549
+ if (!store) return null;
560
550
  const raw = store.getItem(buildKey(address, chainId));
561
- if (!raw)
562
- return null;
551
+ if (!raw) return null;
563
552
  try {
564
553
  const parsed = JSON.parse(raw);
565
554
  if (!parsed.token || isJwtExpired(parsed.token)) {
@@ -574,8 +563,7 @@ var readSession = (address, chainId) => {
574
563
  };
575
564
  var writeSession = (address, chainId, session) => {
576
565
  const store = storage();
577
- if (!store)
578
- return;
566
+ if (!store) return;
579
567
  try {
580
568
  store.setItem(buildKey(address, chainId), JSON.stringify(session));
581
569
  } catch {
@@ -583,8 +571,7 @@ var writeSession = (address, chainId, session) => {
583
571
  };
584
572
  var clearSession = (address, chainId) => {
585
573
  const store = storage();
586
- if (!store)
587
- return;
574
+ if (!store) return;
588
575
  try {
589
576
  store.removeItem(buildKey(address, chainId));
590
577
  } catch {
@@ -593,8 +580,7 @@ var clearSession = (address, chainId) => {
593
580
 
594
581
  // src/agents/zyfai/autoSelect.ts
595
582
  function buildAutoSelectUpdate(current, asset) {
596
- if (current.autoSelectProtocols === true)
597
- return null;
583
+ if (current.autoSelectProtocols === true) return null;
598
584
  return {
599
585
  asset,
600
586
  autoSelectProtocols: true,
@@ -605,16 +591,18 @@ function buildAutoSelectUpdate(current, asset) {
605
591
  // src/agents/zyfai/zyfai.agent.ts
606
592
  var DEFAULT_ZYFAI_RPC_URLS = {
607
593
  8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
608
- 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
594
+ 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
595
+ 1: "https://eth-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
609
596
  };
610
597
  var WETH_ADDRESS_BY_CHAIN = {
611
598
  8453: "0x4200000000000000000000000000000000000006",
612
- 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
599
+ 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
600
+ 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
613
601
  };
614
- var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
602
+ var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
615
603
  var ZyfaiAgent = class {
616
604
  id = "zyfai";
617
- supportedChainIds = [8453, 42161];
605
+ supportedChainIds = [8453, 42161, 1];
618
606
  supportedAssets = [
619
607
  {
620
608
  chainId: 8453,
@@ -631,6 +619,13 @@ var ZyfaiAgent = class {
631
619
  { symbol: "USDC", minDepositAmount: "1500000" },
632
620
  { symbol: "WETH", minDepositAmount: "500000000000000" }
633
621
  ]
622
+ },
623
+ {
624
+ chainId: 1,
625
+ chain: "ETHEREUM",
626
+ // Zyfai enforces a 10,000 USDC minimum portfolio on Ethereum mainnet
627
+ // (mainnet gas only pays off on large positions). 10_000 * 1e6 raw units.
628
+ assets: [{ symbol: "USDC", minDepositAmount: "10000000000" }]
634
629
  }
635
630
  ];
636
631
  sdk;
@@ -654,8 +649,7 @@ var ZyfaiAgent = class {
654
649
  }
655
650
  getPublicClient(chainId) {
656
651
  const cached = this.publicClients.get(chainId);
657
- if (cached)
658
- return cached;
652
+ if (cached) return cached;
659
653
  const client = (0, import_viem.createPublicClient)({
660
654
  chain: VIEM_CHAIN[chainId],
661
655
  transport: (0, import_viem.http)(this.rpcUrls[chainId])
@@ -686,8 +680,7 @@ var ZyfaiAgent = class {
686
680
  const withdrawals = entries.filter(
687
681
  (e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
688
682
  );
689
- if (withdrawals.length === 0)
690
- return;
683
+ if (withdrawals.length === 0) return;
691
684
  const client = this.getPublicClient(chainId);
692
685
  await Promise.all(
693
686
  withdrawals.map(async (entry) => {
@@ -700,8 +693,7 @@ var ZyfaiAgent = class {
700
693
  ) ?? SupportedAssets.find(
701
694
  (a) => a.chainId === chainId && a.symbol === "USDC"
702
695
  );
703
- if (!asset)
704
- return;
696
+ if (!asset) return;
705
697
  const cacheKey = `${txHash}:${asset.address}`;
706
698
  const cached = this.withdrawAmountCache.get(cacheKey);
707
699
  if (cached !== void 0) {
@@ -738,13 +730,11 @@ var ZyfaiAgent = class {
738
730
  * for some apps and the patch only matters in the browser anyway.
739
731
  */
740
732
  installAuthCache() {
741
- if (typeof window === "undefined")
742
- return;
733
+ if (typeof window === "undefined") return;
743
734
  const internals = this.sdk;
744
735
  const original = internals.authenticateUser.bind(internals);
745
736
  internals.authenticateUser = async () => {
746
- if (internals.authenticatedUserId !== null)
747
- return;
737
+ if (internals.authenticatedUserId !== null) return;
748
738
  const address = internals.walletClient?.account?.address;
749
739
  const chainId = internals.currentChainId;
750
740
  if (address && chainId) {
@@ -819,12 +809,10 @@ var ZyfaiAgent = class {
819
809
  return await this.sdk.connectAccount(provider, chainId);
820
810
  } catch (error) {
821
811
  const message = error instanceof Error ? error.message : String(error);
822
- if (!message.toLowerCase().includes("unauthorized"))
823
- throw error;
812
+ if (!message.toLowerCase().includes("unauthorized")) throw error;
824
813
  const internals = this.sdk;
825
814
  const address = internals.walletClient?.account?.address;
826
- if (address)
827
- clearSession(address, chainId);
815
+ if (address) clearSession(address, chainId);
828
816
  return await this.sdk.connectAccount(provider, chainId);
829
817
  }
830
818
  }
@@ -954,10 +942,10 @@ var ZyfaiAgent = class {
954
942
  const raw = await this.sdk.getOnchainEarnings(smartWallet);
955
943
  return mapEarnings(raw, smartWallet);
956
944
  }
957
- async getAccountApy(state, chainId, days) {
945
+ async getAccountApy(state, chainId, days, tokenSymbol) {
958
946
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
959
947
  const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
960
- return mapApyHistory(raw, chainId);
948
+ return mapApyHistory(raw, chainId, tokenSymbol);
961
949
  }
962
950
  async getHistory(state, chainId, options) {
963
951
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
@@ -1022,8 +1010,7 @@ var ZyfaiAgent = class {
1022
1010
  },
1023
1011
  asset
1024
1012
  );
1025
- if (!update)
1026
- return false;
1013
+ if (!update) return false;
1027
1014
  await this.sdk.updateUserProfile(update);
1028
1015
  return true;
1029
1016
  }
@@ -1112,8 +1099,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
1112
1099
  const tokenBalance = agentBalance?.tokens.find(
1113
1100
  (t) => t.chainId === chainId && t.asset.toUpperCase() === target
1114
1101
  );
1115
- if (!tokenBalance)
1116
- return { agent, balance: 0n };
1102
+ if (!tokenBalance) return { agent, balance: 0n };
1117
1103
  return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
1118
1104
  });
1119
1105
  }
@@ -1130,11 +1116,9 @@ function planProportionalShares(balances, requested, totalAvailable) {
1130
1116
  return diff > 0n ? 1 : diff < 0n ? -1 : 0;
1131
1117
  });
1132
1118
  for (const p of byHeadroom) {
1133
- if (remainder === 0n)
1134
- break;
1119
+ if (remainder === 0n) break;
1135
1120
  const headroom = p.balance - p.planned;
1136
- if (headroom <= 0n)
1137
- continue;
1121
+ if (headroom <= 0n) continue;
1138
1122
  const take = headroom < remainder ? headroom : remainder;
1139
1123
  p.planned += take;
1140
1124
  remainder -= take;
@@ -1163,8 +1147,7 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
1163
1147
  (s, c) => s + (c.balance - c.planned),
1164
1148
  0n
1165
1149
  );
1166
- if (totalHeadroom === 0n)
1167
- return;
1150
+ if (totalHeadroom === 0n) return;
1168
1151
  let distributed = 0n;
1169
1152
  for (const c of candidates) {
1170
1153
  const headroom = c.balance - c.planned;
@@ -1175,11 +1158,9 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
1175
1158
  }
1176
1159
  let leftover = amount - distributed;
1177
1160
  for (const c of candidates) {
1178
- if (leftover === 0n)
1179
- break;
1161
+ if (leftover === 0n) break;
1180
1162
  const headroom = c.balance - c.planned;
1181
- if (headroom <= 0n)
1182
- continue;
1163
+ if (headroom <= 0n) continue;
1183
1164
  const take = headroom < leftover ? headroom : leftover;
1184
1165
  c.planned += take;
1185
1166
  leftover -= take;
@@ -1196,16 +1177,13 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1196
1177
  for (const id of Object.keys(agentApys)) {
1197
1178
  const cells = agentApys[id].apyByChainAndAsset;
1198
1179
  const balance = agentBalances[id] ?? 0;
1199
- if (!cells || balance <= 0)
1200
- continue;
1180
+ if (!cells || balance <= 0) continue;
1201
1181
  for (const [chainKey, perAsset] of Object.entries(cells)) {
1202
- if (!perAsset)
1203
- continue;
1182
+ if (!perAsset) continue;
1204
1183
  const chainId = Number(chainKey);
1205
1184
  for (const [asset, apyValue] of Object.entries(perAsset)) {
1206
1185
  const apy = Number(apyValue ?? 0);
1207
- if (apy === 0)
1208
- continue;
1186
+ if (apy === 0) continue;
1209
1187
  sums[chainId] ??= {};
1210
1188
  weights[chainId] ??= {};
1211
1189
  sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
@@ -1219,8 +1197,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1219
1197
  const perAssetOut = {};
1220
1198
  for (const asset of Object.keys(sums[chainId])) {
1221
1199
  const w = weights[chainId][asset];
1222
- if (w > 0)
1223
- perAssetOut[asset] = sums[chainId][asset] / w;
1200
+ if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
1224
1201
  }
1225
1202
  if (Object.keys(perAssetOut).length > 0) {
1226
1203
  out[chainId] = perAssetOut;
@@ -1277,7 +1254,10 @@ async function postSponsorTransferAuth(input) {
1277
1254
  try {
1278
1255
  res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
1279
1256
  method: "POST",
1280
- headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
1257
+ headers: {
1258
+ "content-type": "application/json",
1259
+ "x-owney-api-key": input.apiKey
1260
+ },
1281
1261
  body: JSON.stringify(input.body)
1282
1262
  });
1283
1263
  } catch (networkError) {
@@ -1297,7 +1277,13 @@ async function postSponsorTransferAuth(input) {
1297
1277
  throw new OwneyError(
1298
1278
  "SPONSOR_REQUEST_FAILED",
1299
1279
  `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1300
- { statusCode: res.status, responseBody: text.slice(0, 500) }
1280
+ {
1281
+ statusCode: res.status,
1282
+ responseBody: text.slice(0, 500),
1283
+ // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
1284
+ // before broadcast, so it is safe to fall back to a user-paid deposit.
1285
+ safeToFallback: res.status === 503
1286
+ }
1301
1287
  );
1302
1288
  }
1303
1289
  return parsed.data;
@@ -1308,7 +1294,10 @@ async function postSponsorPermit2Transfer(input) {
1308
1294
  try {
1309
1295
  res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
1310
1296
  method: "POST",
1311
- headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
1297
+ headers: {
1298
+ "content-type": "application/json",
1299
+ "x-owney-api-key": input.apiKey
1300
+ },
1312
1301
  body: JSON.stringify(input.body)
1313
1302
  });
1314
1303
  } catch (networkError) {
@@ -1331,7 +1320,7 @@ async function postSponsorPermit2Transfer(input) {
1331
1320
  {
1332
1321
  statusCode: res.status,
1333
1322
  responseBody: text.slice(0, 500),
1334
- safeToFallback: res.status >= 400 && res.status < 500
1323
+ safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
1335
1324
  }
1336
1325
  );
1337
1326
  }
@@ -1341,9 +1330,12 @@ async function getSponsorRelayerAddress(input) {
1341
1330
  const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1342
1331
  let res;
1343
1332
  try {
1344
- res = await fetch(`${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`, {
1345
- headers: { "x-owney-api-key": input.apiKey }
1346
- });
1333
+ res = await fetch(
1334
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
1335
+ {
1336
+ headers: { "x-owney-api-key": input.apiKey }
1337
+ }
1338
+ );
1347
1339
  } catch (networkError) {
1348
1340
  throw new OwneyError(
1349
1341
  "SPONSOR_REQUEST_FAILED",
@@ -1361,7 +1353,11 @@ async function getSponsorRelayerAddress(input) {
1361
1353
  throw new OwneyError(
1362
1354
  "SPONSOR_REQUEST_FAILED",
1363
1355
  `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1364
- { statusCode: res.status, responseBody: text.slice(0, 500), safeToFallback: true }
1356
+ {
1357
+ statusCode: res.status,
1358
+ responseBody: text.slice(0, 500),
1359
+ safeToFallback: true
1360
+ }
1365
1361
  );
1366
1362
  }
1367
1363
  return parsed.data.relayer;
@@ -1548,18 +1544,21 @@ function decodeMultiAgentCursor(token) {
1548
1544
  }
1549
1545
  var SPONSORED_USDC_BY_CHAIN = {
1550
1546
  8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1551
- 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
1547
+ 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
1548
+ 1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
1552
1549
  };
1553
1550
  var VIEM_CHAIN2 = {
1554
1551
  8453: import_chains2.base,
1555
- 42161: import_chains2.arbitrum
1552
+ 42161: import_chains2.arbitrum,
1553
+ 1: import_chains2.mainnet
1556
1554
  };
1557
1555
  var SPONSORED_WETH_BY_CHAIN = {
1558
1556
  8453: "0x4200000000000000000000000000000000000006",
1559
- 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
1557
+ 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
1558
+ 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
1560
1559
  };
1561
1560
  function shouldFallbackToUserPaid(error, asset, appCallback) {
1562
- return asset === "WETH" && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
1561
+ return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
1563
1562
  }
1564
1563
  var OwneySDK = class {
1565
1564
  agents = /* @__PURE__ */ new Map();
@@ -1573,12 +1572,14 @@ var OwneySDK = class {
1573
1572
  state = null;
1574
1573
  apiKey;
1575
1574
  zyfaiRpcUrls;
1575
+ routingApiBaseUrl;
1576
1576
  cachedSponsoredCallback = null;
1577
1577
  cachedWethSponsoredCallback = null;
1578
1578
  initializingAgentsPromise = null;
1579
1579
  constructor(config) {
1580
1580
  this.apiKey = config.apiKey;
1581
1581
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
1582
+ this.routingApiBaseUrl = config.routingApiBaseUrl;
1582
1583
  }
1583
1584
  /**
1584
1585
  * Establish connection state for all subsequent SDK calls.
@@ -1633,8 +1634,7 @@ var OwneySDK = class {
1633
1634
  return this.state?.chainId ?? null;
1634
1635
  }
1635
1636
  requireState() {
1636
- if (!this.state)
1637
- throw new NotConnectedError();
1637
+ if (!this.state) throw new NotConnectedError();
1638
1638
  return this.state;
1639
1639
  }
1640
1640
  requireChainId() {
@@ -1664,12 +1664,12 @@ var OwneySDK = class {
1664
1664
  * `TransferWithAuthorization`, then POSTs to the sponsor API.
1665
1665
  */
1666
1666
  getDefaultSponsoredCallback() {
1667
- if (this.cachedSponsoredCallback)
1668
- return this.cachedSponsoredCallback;
1667
+ if (this.cachedSponsoredCallback) return this.cachedSponsoredCallback;
1669
1668
  const provider = this.requireConnectedProvider();
1670
1669
  const owner = this.state.walletAddress;
1671
1670
  this.cachedSponsoredCallback = makeSponsoredDepositCallback({
1672
1671
  apiKey: this.apiKey,
1672
+ baseUrl: this.routingApiBaseUrl,
1673
1673
  ownerAddress: owner,
1674
1674
  tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
1675
1675
  // Casts work around viem's chain-narrowed Client vs the generic
@@ -1700,6 +1700,7 @@ var OwneySDK = class {
1700
1700
  const owner = this.state.walletAddress;
1701
1701
  this.cachedWethSponsoredCallback = makeSponsoredWethCallback({
1702
1702
  apiKey: this.apiKey,
1703
+ baseUrl: this.routingApiBaseUrl,
1703
1704
  ownerAddress: owner,
1704
1705
  tokenAddressByChain: SPONSORED_WETH_BY_CHAIN,
1705
1706
  // Casts work around viem's chain-narrowed Client vs the generic
@@ -1728,22 +1729,19 @@ var OwneySDK = class {
1728
1729
  const active = /* @__PURE__ */ new Map();
1729
1730
  for (const id of this.activeAgents) {
1730
1731
  const agent = this.agents.get(id);
1731
- if (agent)
1732
- active.set(id, agent);
1732
+ if (agent) active.set(id, agent);
1733
1733
  }
1734
1734
  return active;
1735
1735
  }
1736
1736
  async ensureAgentsInitialized() {
1737
- if (this.agents.size > 0)
1738
- return;
1737
+ if (this.agents.size > 0) return;
1739
1738
  if (!this.initializingAgentsPromise) {
1740
1739
  this.initializingAgentsPromise = (async () => {
1741
1740
  const agentKeys = await fetchAgentKeys(this.apiKey);
1742
1741
  this.disabledAgents.clear();
1743
1742
  for (const { key, agent_type, is_enabled } of agentKeys) {
1744
1743
  const agent = this.createAgent(agent_type, key);
1745
- if (!agent)
1746
- continue;
1744
+ if (!agent) continue;
1747
1745
  this.agents.set(agent_type, agent);
1748
1746
  if (is_enabled === false) {
1749
1747
  this.disabledAgents.add(agent_type);
@@ -1982,10 +1980,9 @@ var OwneySDK = class {
1982
1980
  await this.approvePermit2();
1983
1981
  continue;
1984
1982
  }
1985
- if (!shouldFallbackToUserPaid(error, asset, appCallback))
1986
- throw error;
1983
+ if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
1987
1984
  console.warn(
1988
- "[owney-sdk] WETH sponsorship unavailable, falling back to user-paid deposit:",
1985
+ `[owney-sdk] ${asset} sponsorship unavailable, falling back to user-paid deposit:`,
1989
1986
  error
1990
1987
  );
1991
1988
  return attempt(void 0);
@@ -2000,8 +1997,7 @@ var OwneySDK = class {
2000
1997
  return BigInt(assetEntry?.minDepositAmount ?? "0");
2001
1998
  }
2002
1999
  splitDepositAmount(totalAmount, agents, chainId, asset, exempt = /* @__PURE__ */ new Set()) {
2003
- if (agents.length === 0)
2004
- return [];
2000
+ if (agents.length === 0) return [];
2005
2001
  const perAgent = totalAmount / BigInt(agents.length);
2006
2002
  const remainder = totalAmount % BigInt(agents.length);
2007
2003
  const splits = agents.map((agent, i) => ({
@@ -2025,10 +2021,8 @@ var OwneySDK = class {
2025
2021
  async validateMinDepositAmount(agent, state, chainId, asset, amount) {
2026
2022
  const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
2027
2023
  const parsedAmount = BigInt(amount);
2028
- if (parsedAmount >= minDepositAmount)
2029
- return;
2030
- if (await this.hasExistingBalance(agent, state, chainId, asset))
2031
- return;
2024
+ if (parsedAmount >= minDepositAmount) return;
2025
+ if (await this.hasExistingBalance(agent, state, chainId, asset)) return;
2032
2026
  throw new OwneyError(
2033
2027
  "DEPOSIT_AMOUNT_BELOW_MINIMUM",
2034
2028
  `Amount "${amount}" is below the required minimum deposit "${minDepositAmount.toString()}" for agent "${agent.id}" on chain ${chainId} for asset "${asset}".`,
@@ -2192,8 +2186,7 @@ var OwneySDK = class {
2192
2186
  const agentErrors = {};
2193
2187
  for (let i = 0; i < plans.length; i++) {
2194
2188
  const p = plans[i];
2195
- if (p.planned === 0n)
2196
- continue;
2189
+ if (p.planned === 0n) continue;
2197
2190
  try {
2198
2191
  results[p.agent.id] = await p.agent.withdraw(
2199
2192
  state,
@@ -2327,19 +2320,30 @@ var OwneySDK = class {
2327
2320
  */
2328
2321
  async getAccountApy({
2329
2322
  agentId,
2330
- days
2323
+ days,
2324
+ tokenSymbol
2331
2325
  }) {
2332
2326
  const state = this.requireState();
2333
2327
  const chainId = this.requireChainId();
2334
2328
  if (agentId) {
2335
- return this.getAgent(agentId).getAccountApy(state, chainId, days);
2329
+ return this.getAgent(agentId).getAccountApy(
2330
+ state,
2331
+ chainId,
2332
+ days,
2333
+ tokenSymbol
2334
+ );
2336
2335
  }
2337
2336
  const activeAgents = this.getActiveAgents();
2338
2337
  const entries = [...activeAgents.entries()];
2339
2338
  const [apyResults, balanceResults] = await Promise.all([
2340
2339
  Promise.all(
2341
2340
  entries.map(async ([id, agent]) => {
2342
- const apy = await agent.getAccountApy(state, chainId, days);
2341
+ const apy = await agent.getAccountApy(
2342
+ state,
2343
+ chainId,
2344
+ days,
2345
+ tokenSymbol
2346
+ );
2343
2347
  return [id, apy];
2344
2348
  })
2345
2349
  ),
@@ -2362,15 +2366,13 @@ var OwneySDK = class {
2362
2366
  let relevantBalance = 0;
2363
2367
  for (const id of Object.keys(results)) {
2364
2368
  const agentApy = Number(results[id].weightedApyAfterFee ?? 0);
2365
- if (agentApy === 0)
2366
- continue;
2369
+ if (agentApy === 0) continue;
2367
2370
  relevantBalance += balances[id];
2368
2371
  }
2369
2372
  if (relevantBalance > 0) {
2370
2373
  for (const id of Object.keys(results)) {
2371
2374
  const agentApy = Number(results[id].weightedApyAfterFee ?? 0);
2372
- if (agentApy === 0)
2373
- continue;
2375
+ if (agentApy === 0) continue;
2374
2376
  const weight = balances[id] / relevantBalance;
2375
2377
  totalApy += agentApy * weight;
2376
2378
  }
@@ -2425,8 +2427,7 @@ var OwneySDK = class {
2425
2427
  const nextCursorMap = {};
2426
2428
  let hasMore = false;
2427
2429
  for (const { agentId: id, page } of perAgent) {
2428
- if (!page)
2429
- continue;
2430
+ if (!page) continue;
2430
2431
  merged.push(...page.data);
2431
2432
  if (page.hasMore && page.nextCursor) {
2432
2433
  nextCursorMap[id] = page.nextCursor;
@@ -2435,16 +2436,12 @@ var OwneySDK = class {
2435
2436
  }
2436
2437
  merged.sort((a, b) => {
2437
2438
  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;
2439
+ if (dateDiff !== 0) return dateDiff;
2440
+ if (a.agent !== b.agent) return a.agent < b.agent ? -1 : 1;
2442
2441
  const aTx = a.transactions?.[0]?.txHashes?.[0] ?? "";
2443
2442
  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;
2443
+ if (aTx !== bTx) return aTx < bTx ? -1 : 1;
2444
+ if (a.action !== b.action) return a.action < b.action ? -1 : 1;
2448
2445
  return 0;
2449
2446
  });
2450
2447
  return {
@@ -2490,8 +2487,7 @@ var OwneySDK = class {
2490
2487
  const state = this.requireState();
2491
2488
  const chainId = this.requireChainId();
2492
2489
  const agent = this.getAgent(agentId);
2493
- if (typeof agent.ensureAutoSelectProtocols !== "function")
2494
- return false;
2490
+ if (typeof agent.ensureAutoSelectProtocols !== "function") return false;
2495
2491
  return agent.ensureAutoSelectProtocols(state, chainId, asset);
2496
2492
  }
2497
2493
  /**
@@ -2503,8 +2499,10 @@ var OwneySDK = class {
2503
2499
  * @returns the approval transaction hash.
2504
2500
  */
2505
2501
  async approvePermit2(asset = "WETH") {
2502
+ void asset;
2506
2503
  const state = this.requireState();
2507
2504
  const chainId = this.requireChainId();
2505
+ this.validateAssetSupport(this.getAgent("zyfai"), chainId, "WETH");
2508
2506
  const token = SPONSORED_WETH_BY_CHAIN[chainId];
2509
2507
  if (!token) {
2510
2508
  throw new OwneyError(
@@ -2644,8 +2642,7 @@ var import_sdk2 = require("@zyfai/sdk");
2644
2642
  // src/agents/zyfai/zyfai.siwx-cache.ts
2645
2643
  var KEY_PREFIX2 = "owney.siwx.session";
2646
2644
  var storage2 = () => {
2647
- if (typeof window === "undefined")
2648
- return null;
2645
+ if (typeof window === "undefined") return null;
2649
2646
  try {
2650
2647
  return window.localStorage;
2651
2648
  } catch {
@@ -2655,11 +2652,9 @@ var storage2 = () => {
2655
2652
  var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2656
2653
  var readSiwxSession = (address, chainId) => {
2657
2654
  const store = storage2();
2658
- if (!store)
2659
- return null;
2655
+ if (!store) return null;
2660
2656
  const raw = store.getItem(buildKey2(address, chainId));
2661
- if (!raw)
2662
- return null;
2657
+ if (!raw) return null;
2663
2658
  try {
2664
2659
  return JSON.parse(raw);
2665
2660
  } catch {
@@ -2669,8 +2664,7 @@ var readSiwxSession = (address, chainId) => {
2669
2664
  };
2670
2665
  var writeSiwxSession = (address, chainId, session) => {
2671
2666
  const store = storage2();
2672
- if (!store)
2673
- return;
2667
+ if (!store) return;
2674
2668
  try {
2675
2669
  store.setItem(buildKey2(address, chainId), JSON.stringify(session));
2676
2670
  } catch {
@@ -2678,8 +2672,7 @@ var writeSiwxSession = (address, chainId, session) => {
2678
2672
  };
2679
2673
  var clearSiwxSession = (address, chainId) => {
2680
2674
  const store = storage2();
2681
- if (!store)
2682
- return;
2675
+ if (!store) return;
2683
2676
  try {
2684
2677
  store.removeItem(buildKey2(address, chainId));
2685
2678
  } catch {
@@ -2742,12 +2735,10 @@ function buildSIWXConfig(deps) {
2742
2735
  const jwt = readSession(address, id);
2743
2736
  const stored = readSiwxSession(address, id);
2744
2737
  if (!jwt) {
2745
- if (stored)
2746
- clearSiwxSession(address, id);
2738
+ if (stored) clearSiwxSession(address, id);
2747
2739
  return [];
2748
2740
  }
2749
- if (!stored)
2750
- return [];
2741
+ if (!stored) return [];
2751
2742
  const session = {
2752
2743
  // `stored.data.chainId` is a plain string in the cache (kept AppKit-free);
2753
2744
  // it always holds a valid CaipNetworkId here, so narrow at the boundary.