@owney/sdk 0.7.17-beta.3 → 0.7.17

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
@@ -26,7 +26,6 @@ __export(index_exports, {
26
26
  NotConnectedError: () => NotConnectedError,
27
27
  OwneyError: () => OwneyError,
28
28
  OwneySDK: () => OwneySDK,
29
- YieldseekerAgent: () => YieldseekerAgent,
30
29
  createOwneySIWX: () => createOwneySIWX,
31
30
  setOwneyDebug: () => setOwneyDebug
32
31
  });
@@ -311,18 +310,18 @@ function tokenDecimals(symbol, explicit) {
311
310
  return explicit;
312
311
  return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
313
312
  }
314
- function mapDeposit(raw2) {
313
+ function mapDeposit(raw) {
315
314
  return {
316
- txHash: raw2.txHash,
317
- smartWallet: raw2.smartWallet,
318
- amount: raw2.amount
315
+ txHash: raw.txHash,
316
+ smartWallet: raw.smartWallet,
317
+ amount: raw.amount
319
318
  };
320
319
  }
321
- function mapWithdraw(raw2) {
320
+ function mapWithdraw(raw) {
322
321
  return {
323
- txHash: raw2.txHash,
324
- type: raw2.type,
325
- amount: raw2.amount
322
+ txHash: raw.txHash,
323
+ type: raw.type,
324
+ amount: raw.amount
326
325
  };
327
326
  }
328
327
  var CHAIN_ID_TO_NAME = {
@@ -341,10 +340,10 @@ function resolveChainId(chain) {
341
340
  if (Number.isFinite(asNum) && asNum > 0) return asNum;
342
341
  return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
343
342
  }
344
- function mapPendingAllocations(raw2) {
345
- if (!Array.isArray(raw2)) return void 0;
343
+ function mapPendingAllocations(raw) {
344
+ if (!Array.isArray(raw)) return void 0;
346
345
  const pending = [];
347
- for (const entry of raw2) {
346
+ for (const entry of raw) {
348
347
  if (typeof entry !== "object" || entry === null) continue;
349
348
  const e = entry;
350
349
  if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
@@ -367,8 +366,8 @@ function mapPendingAllocations(raw2) {
367
366
  }
368
367
  return pending.length > 0 ? pending : void 0;
369
368
  }
370
- function mapBalances(raw2, _chainId, smartWallet) {
371
- const portfolio = raw2.portfolio;
369
+ function mapBalances(raw, _chainId, smartWallet) {
370
+ const portfolio = raw.portfolio;
372
371
  const portfolioByChain = portfolio.portfolioByChain ?? {};
373
372
  let totalBalance = 0;
374
373
  const tokens = [];
@@ -437,8 +436,8 @@ function sumTokenValues(tokens) {
437
436
  function sumTokenEarnings(tokens) {
438
437
  return Object.values(tokens).reduce((sum, val) => sum + Number(val), 0);
439
438
  }
440
- function mapEarnings(raw2, smartWallet) {
441
- const totalEarningsByChain = raw2.data.totalEarningsByChainWithFee ?? raw2.data.totalEarningsByChain ?? {};
439
+ function mapEarnings(raw, smartWallet) {
440
+ const totalEarningsByChain = raw.data.totalEarningsByChainWithFee ?? raw.data.totalEarningsByChain ?? {};
442
441
  const tokens = [];
443
442
  for (const [chainIdKey, tokensBySymbol] of Object.entries(
444
443
  totalEarningsByChain
@@ -457,15 +456,15 @@ function mapEarnings(raw2, smartWallet) {
457
456
  return {
458
457
  smartWallet,
459
458
  lifetimeEarnings: sumTokenEarnings(
460
- raw2.data.totalEarningsByTokenWithFee ?? raw2.data.totalEarningsByToken
459
+ raw.data.totalEarningsByTokenWithFee ?? raw.data.totalEarningsByToken
461
460
  ),
462
461
  tokens
463
462
  };
464
463
  }
465
- function mapWeightedApyByChain(raw2) {
466
- if (!raw2) return void 0;
464
+ function mapWeightedApyByChain(raw) {
465
+ if (!raw) return void 0;
467
466
  const out = {};
468
- for (const [chainKey, tokenApy] of Object.entries(raw2)) {
467
+ for (const [chainKey, tokenApy] of Object.entries(raw)) {
469
468
  const chainId = Number(chainKey);
470
469
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
471
470
  const perAsset = {};
@@ -505,15 +504,15 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
505
504
  }
506
505
  return totalBalance > 0 ? weightedSum / totalBalance : null;
507
506
  }
508
- function mapApyHistory(raw2, chainId, tokenSymbol) {
509
- const history = Object.entries(raw2.history ?? {}).map(([date, entry]) => ({
507
+ function mapApyHistory(raw, chainId, tokenSymbol) {
508
+ const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
510
509
  date,
511
510
  apy: rawPoolApyForChain(entry, chainId, tokenSymbol)
512
511
  })).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
513
512
  return {
514
- walletAddress: raw2.walletAddress,
515
- weightedApyAfterFee: raw2.weightedApyAfterFee ? sumTokenValues(raw2.weightedApyAfterFee) : void 0,
516
- apyByChainAndAsset: mapWeightedApyByChain(raw2.weightedApyAfterFeeByChain),
513
+ walletAddress: raw.walletAddress,
514
+ weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
515
+ apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain),
517
516
  history
518
517
  };
519
518
  }
@@ -609,23 +608,23 @@ function mapEntries(rawEntries, chainId) {
609
608
  };
610
609
  });
611
610
  }
612
- function mapUserProfile(raw2, userAddress) {
611
+ function mapUserProfile(raw, userAddress) {
613
612
  return {
614
613
  address: userAddress,
615
- smartWallet: raw2.smartWallet || "",
616
- chains: raw2.chains || [],
617
- strategy: raw2.strategy,
618
- hasActiveSessionKey: raw2.hasActiveSessionKey || false,
619
- protocols: raw2.protocols || [],
620
- splitting: raw2.splitting,
621
- minSplits: raw2.minSplits
614
+ smartWallet: raw.smartWallet || "",
615
+ chains: raw.chains || [],
616
+ strategy: raw.strategy,
617
+ hasActiveSessionKey: raw.hasActiveSessionKey || false,
618
+ protocols: raw.protocols || [],
619
+ splitting: raw.splitting,
620
+ minSplits: raw.minSplits
622
621
  };
623
622
  }
624
- function mapApyByStrategy(raw2) {
623
+ function mapApyByStrategy(raw) {
625
624
  const apyPerAsset = {};
626
625
  let apySum = 0;
627
626
  let apyCount = 0;
628
- for (const entry of raw2.data) {
627
+ for (const entry of raw.data) {
629
628
  const supported = SupportedAssets.find(
630
629
  (asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
631
630
  );
@@ -796,15 +795,15 @@ var readSession = (address, _chainId) => {
796
795
  if (typeof window === "undefined") return null;
797
796
  const key2 = buildKey(address);
798
797
  const store = storage();
799
- let raw2 = null;
798
+ let raw = null;
800
799
  try {
801
- raw2 = store?.getItem(key2) ?? null;
800
+ raw = store?.getItem(key2) ?? null;
802
801
  } catch {
803
- raw2 = null;
802
+ raw = null;
804
803
  }
805
- if (raw2) {
804
+ if (raw) {
806
805
  try {
807
- const parsed = JSON.parse(raw2);
806
+ const parsed = JSON.parse(raw);
808
807
  if (isFreshSession(parsed)) return parsed;
809
808
  } catch {
810
809
  }
@@ -972,8 +971,8 @@ function buildChainsByProtocol(protocols, dashboardChainIds) {
972
971
  }
973
972
  return result;
974
973
  }
975
- function flattenAvailablePools(raw2) {
976
- const byChain = raw2 ?? {};
974
+ function flattenAvailablePools(raw) {
975
+ const byChain = raw ?? {};
977
976
  const names = [];
978
977
  for (const byToken of Object.values(byChain ?? {})) {
979
978
  for (const entry of Object.values(byToken ?? {})) {
@@ -1474,8 +1473,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
1474
1473
  const poolResults = await Promise.all(
1475
1474
  universe.map(async (protocol) => {
1476
1475
  try {
1477
- const raw2 = await this.sdk.getAvailablePools(protocol.id, strategy);
1478
- return [protocol.id, flattenAvailablePools(raw2)];
1476
+ const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
1477
+ return [protocol.id, flattenAvailablePools(raw)];
1479
1478
  } catch (error) {
1480
1479
  console.warn(
1481
1480
  `[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
@@ -1541,14 +1540,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
1541
1540
  async readWalletState(ownerAddress) {
1542
1541
  try {
1543
1542
  const { portfolio } = await this.sdk.getPositions(ownerAddress);
1544
- const raw2 = portfolio;
1543
+ const raw = portfolio;
1545
1544
  debugLog("zyfai:onboard", "wallet state from getPositions", {
1546
- predeployed: raw2?.predeployed,
1547
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1545
+ predeployed: raw?.predeployed,
1546
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1548
1547
  });
1549
1548
  return {
1550
- predeployed: raw2?.predeployed,
1551
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1549
+ predeployed: raw?.predeployed,
1550
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1552
1551
  };
1553
1552
  } catch (error) {
1554
1553
  console.warn(
@@ -1828,14 +1827,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
1828
1827
  return { txHash, smartWallet, amount };
1829
1828
  }
1830
1829
  await this.ensureWalletDeployed(this.getAddress(), validChainId);
1831
- const raw2 = await this.sdk.depositFunds(
1830
+ const raw = await this.sdk.depositFunds(
1832
1831
  this.getAddress(),
1833
1832
  validChainId,
1834
1833
  amount,
1835
1834
  asset,
1836
1835
  "aggressive"
1837
1836
  );
1838
- return mapDeposit(raw2);
1837
+ return mapDeposit(raw);
1839
1838
  } catch (error) {
1840
1839
  throw error;
1841
1840
  }
@@ -1844,27 +1843,27 @@ var ZyfaiAgent = class _ZyfaiAgent {
1844
1843
  async withdraw(state, chainId, token, amount) {
1845
1844
  const validChainId = isValidChainId(chainId);
1846
1845
  await this.ensureConnected(state, validChainId);
1847
- const raw2 = await this.sdk.withdrawFunds(
1846
+ const raw = await this.sdk.withdrawFunds(
1848
1847
  this.getAddress(),
1849
1848
  validChainId,
1850
1849
  amount,
1851
1850
  token
1852
1851
  );
1853
- if (!raw2.success) {
1852
+ if (!raw.success) {
1854
1853
  throw new OwneyError(
1855
1854
  "WITHDRAW_FAILED",
1856
- raw2.message || "Zyfai withdraw failed.",
1857
- { chainId: validChainId, token, amount, response: raw2 },
1855
+ raw.message || "Zyfai withdraw failed.",
1856
+ { chainId: validChainId, token, amount, response: raw },
1858
1857
  this.id
1859
1858
  );
1860
1859
  }
1861
- return mapWithdraw(raw2);
1860
+ return mapWithdraw(raw);
1862
1861
  }
1863
1862
  // --- IAgent: Portfolio reads ---
1864
1863
  async getBalances(state, chainId) {
1865
1864
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
1866
- const raw2 = await this.sdk.getPortfolio(this.getAddress());
1867
- return mapBalances(raw2, validChainId, smartWallet);
1865
+ const raw = await this.sdk.getPortfolio(this.getAddress());
1866
+ return mapBalances(raw, validChainId, smartWallet);
1868
1867
  }
1869
1868
  earningsKey(state, chainId, smartWallet) {
1870
1869
  return JSON.stringify([
@@ -1877,11 +1876,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
1877
1876
  const existing = this.earningsReads.get(key2);
1878
1877
  if (existing) return existing;
1879
1878
  const generation = this.earningsGeneration;
1880
- const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw2) => {
1879
+ const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw) => {
1881
1880
  if (generation === this.earningsGeneration) {
1882
- this.earningsSnapshot = { key: key2, raw: raw2, at: Date.now() };
1881
+ this.earningsSnapshot = { key: key2, raw, at: Date.now() };
1883
1882
  }
1884
- return raw2;
1883
+ return raw;
1885
1884
  }).finally(() => {
1886
1885
  if (this.earningsReads.get(key2) === pending)
1887
1886
  this.earningsReads.delete(key2);
@@ -1891,11 +1890,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
1891
1890
  }
1892
1891
  async getEarnings(state, chainId) {
1893
1892
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
1894
- const raw2 = await this.readEarnings(
1893
+ const raw = await this.readEarnings(
1895
1894
  this.earningsKey(state, chainId, smartWallet),
1896
1895
  smartWallet
1897
1896
  );
1898
- return mapEarnings(raw2, smartWallet);
1897
+ return mapEarnings(raw, smartWallet);
1899
1898
  }
1900
1899
  async refreshEarnings(state, chainId) {
1901
1900
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
@@ -1922,8 +1921,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
1922
1921
  }
1923
1922
  async getAccountApy(state, chainId, days, tokenSymbol) {
1924
1923
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
1925
- const raw2 = await this.sdk.getDailyApyHistory(smartWallet, days);
1926
- return mapApyHistory(raw2, chainId, tokenSymbol);
1924
+ const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
1925
+ return mapApyHistory(raw, chainId, tokenSymbol);
1927
1926
  }
1928
1927
  /**
1929
1928
  * Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
@@ -1958,7 +1957,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1958
1957
  const matched = [];
1959
1958
  let backendExhausted = false;
1960
1959
  for (let i = 0; i < MAX_BACKEND_CALLS && matched.length < limit; i++) {
1961
- const raw2 = await this.sdk.getHistory(smartWallet, validChainId, {
1960
+ const raw = await this.sdk.getHistory(smartWallet, validChainId, {
1962
1961
  limit: backendPageSize,
1963
1962
  offset,
1964
1963
  fromDate: options?.fromDate,
@@ -1969,13 +1968,13 @@ var ZyfaiAgent = class _ZyfaiAgent {
1969
1968
  // asset's rows and handing back a page that filters to nothing.
1970
1969
  assetType
1971
1970
  });
1972
- raw2.data.forEach((entry, idx) => {
1971
+ raw.data.forEach((entry, idx) => {
1973
1972
  if (entry.chainId === validChainId) {
1974
1973
  matched.push({ entry, rawIdx: offset + idx });
1975
1974
  }
1976
1975
  });
1977
- offset += raw2.data.length;
1978
- if (raw2.data.length < backendPageSize) {
1976
+ offset += raw.data.length;
1977
+ if (raw.data.length < backendPageSize) {
1979
1978
  backendExhausted = true;
1980
1979
  break;
1981
1980
  }
@@ -1997,18 +1996,18 @@ var ZyfaiAgent = class _ZyfaiAgent {
1997
1996
  }
1998
1997
  async getUserProfile(state, chainId) {
1999
1998
  await this.connectAuth(state, chainId);
2000
- const raw2 = await this.sdk.getUserDetails();
1999
+ const raw = await this.sdk.getUserDetails();
2001
2000
  debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
2002
2001
  asset: "USDC (default \u2014 no asset passed)",
2003
- splitting: raw2.splitting,
2004
- minSplits: raw2.minSplits,
2005
- strategy: raw2.strategy,
2006
- chains: raw2.chains,
2007
- protocolCount: raw2.protocols?.length,
2008
- hasActiveSessionKey: raw2.hasActiveSessionKey,
2009
- smartWallet: raw2.smartWallet
2002
+ splitting: raw.splitting,
2003
+ minSplits: raw.minSplits,
2004
+ strategy: raw.strategy,
2005
+ chains: raw.chains,
2006
+ protocolCount: raw.protocols?.length,
2007
+ hasActiveSessionKey: raw.hasActiveSessionKey,
2008
+ smartWallet: raw.smartWallet
2010
2009
  });
2011
- return mapUserProfile(raw2, this.connectedAddress);
2010
+ return mapUserProfile(raw, this.connectedAddress);
2012
2011
  }
2013
2012
  async ensureAutoSelectProtocols(state, chainId, asset) {
2014
2013
  await this.connectAuth(state, chainId);
@@ -2027,58 +2026,236 @@ var ZyfaiAgent = class _ZyfaiAgent {
2027
2026
  }
2028
2027
  // --- IAgent: Discovery (no wallet required) ---
2029
2028
  async getAgentApy(days, options) {
2030
- const raw2 = await this.sdk.getAPYPerStrategy(
2029
+ const raw = await this.sdk.getAPYPerStrategy(
2031
2030
  false,
2032
2031
  DayFilterMapping[days],
2033
2032
  "aggressive",
2034
2033
  options?.chainId,
2035
2034
  options?.tokenSymbol
2036
2035
  );
2037
- return mapApyByStrategy(raw2);
2036
+ return mapApyByStrategy(raw);
2038
2037
  }
2039
2038
  };
2040
2039
 
2041
- // src/agents/yieldseeker/yieldseeker.agent.ts
2042
- var import_viem6 = require("viem");
2043
- var import_chains3 = require("viem/chains");
2044
-
2045
- // src/lib/chain-guard.ts
2046
- var CHAIN_NAMES = {
2047
- 1: "Ethereum",
2048
- 8453: "Base",
2049
- 42161: "Arbitrum"
2050
- };
2051
- function chainName(chainId) {
2052
- return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
2053
- }
2054
- async function ensureWalletOnChain(pub, wallet, expected) {
2055
- const actual = await pub.getChainId();
2056
- if (actual === expected) return;
2040
+ // src/lib/routing-api.ts
2041
+ var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2042
+ async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
2043
+ const url = `${baseUrl}/api/v1/agent/org-config`;
2057
2044
  try {
2058
- await wallet.switchChain({ id: expected });
2045
+ const res = await fetch(url, {
2046
+ method: "GET",
2047
+ headers: {
2048
+ "Content-Type": "application/json",
2049
+ "x-owney-api-key": `${apiKey}`
2050
+ }
2051
+ });
2052
+ if (!res.ok) {
2053
+ if (res.status !== 404) {
2054
+ console.warn(
2055
+ `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
2056
+ );
2057
+ }
2058
+ return null;
2059
+ }
2060
+ const json = await res.json();
2061
+ const policy = json.success ? json.data ?? null : null;
2062
+ debugLog(
2063
+ "owney-sdk",
2064
+ policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
2065
+ policy ?? void 0
2066
+ );
2067
+ return policy;
2059
2068
  } catch (error) {
2069
+ console.warn(
2070
+ "[owney-sdk] Could not read org agent config (non-fatal):",
2071
+ error instanceof Error ? error.message : String(error)
2072
+ );
2073
+ return null;
2074
+ }
2075
+ }
2076
+ async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
2077
+ const url = `${baseUrl}/api/v1/agent/keys`;
2078
+ const res = await fetch(url, {
2079
+ method: "GET",
2080
+ headers: {
2081
+ "Content-Type": "application/json",
2082
+ "x-owney-api-key": `${apiKey}`
2083
+ }
2084
+ });
2085
+ if (!res.ok) {
2086
+ const text = await res.text().catch(() => "");
2060
2087
  throw new OwneyError(
2061
- "CHAIN_MISMATCH",
2062
- `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2063
- {
2064
- expectedChainId: expected,
2065
- actualChainId: actual,
2066
- cause: error instanceof Error ? error.message : String(error)
2067
- }
2088
+ "API_ROUTING_ERROR",
2089
+ `Routing API error ${res.status}: ${text}`,
2090
+ { statusCode: res.status, responseBody: text }
2068
2091
  );
2069
2092
  }
2070
- const after = await pub.getChainId();
2071
- if (after !== expected) {
2093
+ const json = await res.json();
2094
+ if (!json.success) {
2072
2095
  throw new OwneyError(
2073
- "CHAIN_MISMATCH",
2074
- `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2075
- { expectedChainId: expected, actualChainId: after }
2096
+ "API_ROUTING_FAILED",
2097
+ `Routing API request failed: ${json.message}`,
2098
+ { message: json.message }
2076
2099
  );
2077
2100
  }
2101
+ return json.data;
2078
2102
  }
2079
2103
 
2080
- // src/lib/transfer-auth.ts
2104
+ // src/lib/health-report.ts
2105
+ var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2106
+ async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
2107
+ try {
2108
+ await fetch(`${baseUrl}/api/v1/agent/health-report`, {
2109
+ method: "POST",
2110
+ headers: {
2111
+ "Content-Type": "application/json",
2112
+ "x-owney-api-key": apiKey
2113
+ },
2114
+ body: JSON.stringify({
2115
+ agent_type: agentType,
2116
+ error_code: errorCode,
2117
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2118
+ })
2119
+ });
2120
+ } catch (err) {
2121
+ console.warn(
2122
+ `[owney-sdk] health-report failed for agent "${agentType}":`,
2123
+ err instanceof Error ? err.message : err
2124
+ );
2125
+ }
2126
+ }
2127
+ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
2128
+ try {
2129
+ return await fn();
2130
+ } catch (err) {
2131
+ const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
2132
+ void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
2133
+ throw err;
2134
+ }
2135
+ }
2136
+
2137
+ // src/lib/helpers/withdraw-helper.ts
2081
2138
  var import_viem2 = require("viem");
2139
+ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
2140
+ const target = asset.toUpperCase();
2141
+ return agents.map((agent) => {
2142
+ const agentBalance = aggregated[agent.id];
2143
+ const tokenBalance = agentBalance?.tokens.find(
2144
+ (t) => t.chainId === chainId && t.asset.toUpperCase() === target
2145
+ );
2146
+ if (!tokenBalance) return { agent, balance: 0n };
2147
+ return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
2148
+ });
2149
+ }
2150
+ function planProportionalShares(balances, requested, totalAvailable) {
2151
+ const plans = balances.map(({ agent, balance }) => ({
2152
+ agent,
2153
+ balance,
2154
+ planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
2155
+ }));
2156
+ const assigned = plans.reduce((s, p) => s + p.planned, 0n);
2157
+ let remainder = requested - assigned;
2158
+ const byHeadroom = [...plans].sort((a, b) => {
2159
+ const diff = b.balance - b.planned - (a.balance - a.planned);
2160
+ return diff > 0n ? 1 : diff < 0n ? -1 : 0;
2161
+ });
2162
+ for (const p of byHeadroom) {
2163
+ if (remainder === 0n) break;
2164
+ const headroom = p.balance - p.planned;
2165
+ if (headroom <= 0n) continue;
2166
+ const take = headroom < remainder ? headroom : remainder;
2167
+ p.planned += take;
2168
+ remainder -= take;
2169
+ }
2170
+ return plans;
2171
+ }
2172
+ function planDisabledDrain(disabled, requested) {
2173
+ const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
2174
+ const plans = [];
2175
+ let remaining = requested;
2176
+ for (const { agent, balance } of sorted) {
2177
+ if (remaining === 0n) {
2178
+ plans.push({ agent, balance, planned: 0n });
2179
+ continue;
2180
+ }
2181
+ const take = balance < remaining ? balance : remaining;
2182
+ plans.push({ agent, balance, planned: take });
2183
+ remaining -= take;
2184
+ }
2185
+ return { plans, remaining };
2186
+ }
2187
+ function redistributeShare(plans, fromIndex, amount, candidatePool) {
2188
+ const pool = candidatePool ?? plans.slice(fromIndex + 1);
2189
+ const candidates = pool.filter((c) => c.balance - c.planned > 0n);
2190
+ const totalHeadroom = candidates.reduce(
2191
+ (s, c) => s + (c.balance - c.planned),
2192
+ 0n
2193
+ );
2194
+ if (totalHeadroom === 0n) return;
2195
+ let distributed = 0n;
2196
+ for (const c of candidates) {
2197
+ const headroom = c.balance - c.planned;
2198
+ const proportional = headroom * amount / totalHeadroom;
2199
+ const give = proportional > headroom ? headroom : proportional;
2200
+ c.planned += give;
2201
+ distributed += give;
2202
+ }
2203
+ let leftover = amount - distributed;
2204
+ for (const c of candidates) {
2205
+ if (leftover === 0n) break;
2206
+ const headroom = c.balance - c.planned;
2207
+ if (headroom <= 0n) continue;
2208
+ const take = headroom < leftover ? headroom : leftover;
2209
+ c.planned += take;
2210
+ leftover -= take;
2211
+ }
2212
+ }
2213
+ function sumWithdrawnAmount(results) {
2214
+ return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
2215
+ }
2216
+
2217
+ // src/lib/helpers/account-apy-helper.ts
2218
+ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
2219
+ const sums = {};
2220
+ const weights = {};
2221
+ for (const id of Object.keys(agentApys)) {
2222
+ const cells = agentApys[id].apyByChainAndAsset;
2223
+ const balance = agentBalances[id] ?? 0;
2224
+ if (!cells || balance <= 0) continue;
2225
+ for (const [chainKey, perAsset] of Object.entries(cells)) {
2226
+ if (!perAsset) continue;
2227
+ const chainId = Number(chainKey);
2228
+ for (const [asset, apyValue] of Object.entries(perAsset)) {
2229
+ const apy = Number(apyValue ?? 0);
2230
+ if (apy === 0) continue;
2231
+ sums[chainId] ??= {};
2232
+ weights[chainId] ??= {};
2233
+ sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
2234
+ weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2235
+ }
2236
+ }
2237
+ }
2238
+ const out = {};
2239
+ for (const chainKey of Object.keys(sums)) {
2240
+ const chainId = Number(chainKey);
2241
+ const perAssetOut = {};
2242
+ for (const asset of Object.keys(sums[chainId])) {
2243
+ const w = weights[chainId][asset];
2244
+ if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
2245
+ }
2246
+ if (Object.keys(perAssetOut).length > 0) {
2247
+ out[chainId] = perAssetOut;
2248
+ }
2249
+ }
2250
+ return out;
2251
+ }
2252
+
2253
+ // src/client.ts
2254
+ var import_viem6 = require("viem");
2255
+ var import_chains2 = require("viem/chains");
2256
+
2257
+ // src/lib/transfer-auth.ts
2258
+ var import_viem3 = require("viem");
2082
2259
  var ERC20_META_ABI = [
2083
2260
  { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
2084
2261
  { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
@@ -2110,29 +2287,28 @@ async function readTokenMeta(publicClient, token) {
2110
2287
  function randomAuthNonce() {
2111
2288
  const bytes = new Uint8Array(32);
2112
2289
  globalThis.crypto.getRandomValues(bytes);
2113
- return (0, import_viem2.bytesToHex)(bytes);
2290
+ return (0, import_viem3.bytesToHex)(bytes);
2114
2291
  }
2115
2292
 
2116
2293
  // src/lib/sponsor-client.ts
2117
- var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2118
- async function postPaymasterIntent(input) {
2119
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2294
+ var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2295
+ async function postSponsorTransferAuth(input) {
2296
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2120
2297
  let res;
2121
2298
  try {
2122
- res = await fetch(`${base5}/api/v1/sponsor/paymaster-intent`, {
2299
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2123
2300
  method: "POST",
2124
2301
  headers: {
2125
2302
  "content-type": "application/json",
2126
- "x-owney-api-key": input.apiKey,
2127
- Authorization: `Signature ${input.yieldseekerSignature}`
2303
+ "x-owney-api-key": input.apiKey
2128
2304
  },
2129
2305
  body: JSON.stringify(input.body)
2130
2306
  });
2131
2307
  } catch (networkError) {
2132
2308
  throw new OwneyError(
2133
2309
  "SPONSOR_REQUEST_FAILED",
2134
- `Paymaster intent network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2135
- { cause: String(networkError), safeToFallback: true }
2310
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2311
+ { cause: String(networkError) }
2136
2312
  );
2137
2313
  }
2138
2314
  const text = await res.text();
@@ -2141,29 +2317,30 @@ async function postPaymasterIntent(input) {
2141
2317
  parsed = JSON.parse(text);
2142
2318
  } catch {
2143
2319
  }
2144
- if (!res.ok || !parsed?.success || typeof parsed.data?.intent !== "string" || typeof parsed.data.expiresAt !== "number") {
2320
+ if (!res.ok || !parsed?.success || !parsed.data) {
2145
2321
  throw new OwneyError(
2146
2322
  "SPONSOR_REQUEST_FAILED",
2147
- `Paymaster intent API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2323
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2148
2324
  {
2149
2325
  statusCode: res.status,
2150
2326
  responseBody: text.slice(0, 500),
2151
- safeToFallback: true
2327
+ // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2328
+ // before broadcast, so it is safe to fall back to a user-paid deposit.
2329
+ safeToFallback: res.status === 503
2152
2330
  }
2153
2331
  );
2154
2332
  }
2155
2333
  return parsed.data;
2156
2334
  }
2157
- async function postSponsorTransferAuth(input) {
2158
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2335
+ async function postSponsorPermit2Transfer(input) {
2336
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2159
2337
  let res;
2160
2338
  try {
2161
- res = await fetch(`${base5}/api/v1/sponsor/erc20-transfer-auth`, {
2339
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2162
2340
  method: "POST",
2163
2341
  headers: {
2164
2342
  "content-type": "application/json",
2165
- "x-owney-api-key": input.apiKey,
2166
- ...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
2343
+ "x-owney-api-key": input.apiKey
2167
2344
  },
2168
2345
  body: JSON.stringify(input.body)
2169
2346
  });
@@ -2171,7 +2348,7 @@ async function postSponsorTransferAuth(input) {
2171
2348
  throw new OwneyError(
2172
2349
  "SPONSOR_REQUEST_FAILED",
2173
2350
  `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2174
- { cause: String(networkError) }
2351
+ { cause: String(networkError), safeToFallback: false }
2175
2352
  );
2176
2353
  }
2177
2354
  const text = await res.text();
@@ -2187,59 +2364,18 @@ async function postSponsorTransferAuth(input) {
2187
2364
  {
2188
2365
  statusCode: res.status,
2189
2366
  responseBody: text.slice(0, 500),
2190
- // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2191
- // before broadcast, so it is safe to fall back to a user-paid deposit.
2192
- safeToFallback: res.status === 503
2367
+ safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
2193
2368
  }
2194
2369
  );
2195
2370
  }
2196
2371
  return parsed.data;
2197
2372
  }
2198
- async function postSponsorPermit2Transfer(input) {
2199
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2200
- let res;
2201
- try {
2202
- res = await fetch(`${base5}/api/v1/sponsor/permit2-transfer`, {
2203
- method: "POST",
2204
- headers: {
2205
- "content-type": "application/json",
2206
- "x-owney-api-key": input.apiKey,
2207
- ...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
2208
- },
2209
- body: JSON.stringify(input.body)
2210
- });
2211
- } catch (networkError) {
2212
- throw new OwneyError(
2213
- "SPONSOR_REQUEST_FAILED",
2214
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2215
- { cause: String(networkError), safeToFallback: false }
2216
- );
2217
- }
2218
- const text = await res.text();
2219
- let parsed = null;
2220
- try {
2221
- parsed = JSON.parse(text);
2222
- } catch {
2223
- }
2224
- if (!res.ok || !parsed?.success || !parsed.data) {
2225
- throw new OwneyError(
2226
- "SPONSOR_REQUEST_FAILED",
2227
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2228
- {
2229
- statusCode: res.status,
2230
- responseBody: text.slice(0, 500),
2231
- safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
2232
- }
2233
- );
2234
- }
2235
- return parsed.data;
2236
- }
2237
- async function getSponsorRelayerAddress(input) {
2238
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2373
+ async function getSponsorRelayerAddress(input) {
2374
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2239
2375
  let res;
2240
2376
  try {
2241
2377
  res = await fetch(
2242
- `${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2378
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2243
2379
  {
2244
2380
  headers: { "x-owney-api-key": input.apiKey }
2245
2381
  }
@@ -2272,7 +2408,7 @@ async function getSponsorRelayerAddress(input) {
2272
2408
  }
2273
2409
 
2274
2410
  // src/lib/permit2.ts
2275
- var import_viem3 = require("viem");
2411
+ var import_viem4 = require("viem");
2276
2412
  var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2277
2413
  var MAX_UINT256 = 2n ** 256n - 1n;
2278
2414
  var ERC20_ALLOWANCE_ABI = [
@@ -2330,7 +2466,7 @@ function buildPermitTransferFromTypedData(input) {
2330
2466
  function randomPermit2Nonce() {
2331
2467
  const bytes = new Uint8Array(32);
2332
2468
  globalThis.crypto.getRandomValues(bytes);
2333
- return BigInt((0, import_viem3.bytesToHex)(bytes));
2469
+ return BigInt((0, import_viem4.bytesToHex)(bytes));
2334
2470
  }
2335
2471
  async function readPermit2Allowance(publicClient, token, owner) {
2336
2472
  return publicClient.readContract({
@@ -2340,1972 +2476,213 @@ async function readPermit2Allowance(publicClient, token, owner) {
2340
2476
  args: [owner, PERMIT2_ADDRESS]
2341
2477
  });
2342
2478
  }
2343
- async function readErc20Balance(publicClient, token, owner) {
2344
- return publicClient.readContract({
2345
- address: token,
2346
- abi: ERC20_ALLOWANCE_ABI,
2347
- functionName: "balanceOf",
2348
- args: [owner]
2349
- });
2350
- }
2351
-
2352
- // src/lib/sponsored-deposit.ts
2353
- var AUTH_WINDOW_SECONDS = 15 * 60;
2354
- var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
2355
- function provideDepositVerificationContext(callback, context) {
2356
- callback[verificationSetter]?.(context);
2357
- }
2358
- function makeVerificationAwareDepositCallback(implementation) {
2359
- let nextVerification;
2360
- const callback = async (smartWallet, chainId, amount) => {
2361
- const verification = nextVerification;
2362
- nextVerification = void 0;
2363
- return implementation(smartWallet, chainId, amount, verification);
2364
- };
2365
- Object.defineProperty(callback, verificationSetter, {
2366
- value: (context) => {
2367
- nextVerification = context;
2368
- }
2369
- });
2370
- return callback;
2371
- }
2372
- function makeSponsoredDepositCallback(deps) {
2373
- const post = deps.httpPost ?? postSponsorTransferAuth;
2374
- return makeVerificationAwareDepositCallback(
2375
- async (smartWallet, chainId, amount, verification) => {
2376
- const cid = chainId;
2377
- const token = deps.tokenAddressByChain[cid];
2378
- if (!token) {
2379
- throw new OwneyError(
2380
- "CHAIN_UNSUPPORTED",
2381
- `No sponsored token configured for chain ${chainId}`
2382
- );
2383
- }
2384
- const pub = deps.getPublicClient(cid);
2385
- const wallet = deps.getWalletClient(cid);
2386
- await ensureWalletOnChain(pub, wallet, cid);
2387
- try {
2388
- const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2389
- if (balance < BigInt(amount)) {
2390
- throw new OwneyError(
2391
- "DEPOSIT_INSUFFICIENT_BALANCE",
2392
- "Insufficient balance for this deposit.",
2393
- { token, chainId: cid, balance: balance.toString(), amount }
2394
- );
2395
- }
2396
- } catch (err) {
2397
- if (err instanceof OwneyError) throw err;
2398
- console.warn(
2399
- "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2400
- err instanceof Error ? err.message : String(err)
2401
- );
2402
- }
2403
- const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2404
- const validAfter = 0n;
2405
- const validBefore = BigInt(
2406
- Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2407
- );
2408
- const nonce = randomAuthNonce();
2409
- const typedData = buildTransferWithAuthorizationTypedData({
2410
- token,
2411
- chainId: cid,
2412
- tokenName,
2413
- tokenVersion,
2414
- message: {
2415
- from: deps.ownerAddress,
2416
- to: smartWallet,
2417
- value: BigInt(amount),
2418
- validAfter,
2419
- validBefore,
2420
- nonce
2421
- }
2422
- });
2423
- const authSignature = await wallet.signTypedData({
2424
- account: deps.ownerAddress,
2425
- ...typedData
2426
- });
2427
- deps.onApproved?.();
2428
- const result = await post({
2429
- baseUrl: deps.baseUrl,
2430
- apiKey: deps.apiKey,
2431
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
2432
- body: {
2433
- chainId: cid,
2434
- token,
2435
- from: deps.ownerAddress,
2436
- to: smartWallet,
2437
- value: amount,
2438
- validAfter: validAfter.toString(),
2439
- validBefore: validBefore.toString(),
2440
- nonce,
2441
- authSignature,
2442
- tokenName,
2443
- tokenVersion,
2444
- ...verification?.agentId === "yieldseeker" ? {
2445
- yieldseekerUserId: verification.userId,
2446
- yieldseekerAgentId: verification.yieldseekerAgentId
2447
- } : {}
2448
- }
2449
- });
2450
- return result.txHash;
2451
- }
2452
- );
2453
- }
2454
-
2455
- // src/agents/yieldseeker/yieldseeker.auth.ts
2456
- var import_siwe = require("siwe");
2457
- var import_viem4 = require("viem");
2458
- var import_chains2 = require("viem/chains");
2459
-
2460
- // src/agents/yieldseeker/yieldseeker.auth-cache.ts
2461
- var KEY_PREFIX2 = "owney.yieldseeker.session.v5";
2462
- var INVALIDATED_KEY_PREFIXES = [
2463
- "owney.yieldseeker.session",
2464
- "owney.yieldseeker.session.v3",
2465
- "owney.yieldseeker.session.v4"
2466
- ];
2467
- var storage2 = () => {
2468
- if (typeof window === "undefined") return null;
2469
- try {
2470
- return window.localStorage;
2471
- } catch {
2472
- return null;
2473
- }
2474
- };
2475
- var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2476
- var invalidatedKeys = (address, chainId) => INVALIDATED_KEY_PREFIXES.map(
2477
- (prefix) => `${prefix}:${address.toLowerCase()}:${chainId}`
2478
- );
2479
- var clearInvalidatedSessions = (store, address, chainId) => {
2480
- for (const key2 of invalidatedKeys(address, chainId)) {
2481
- memorySessions2.delete(key2);
2482
- try {
2483
- store?.removeItem(key2);
2484
- } catch {
2485
- }
2486
- }
2487
- };
2488
- var memorySessions2 = /* @__PURE__ */ new Map();
2489
- var isValidSession = (session) => {
2490
- if (!session?.token) return false;
2491
- try {
2492
- const parsed = JSON.parse(atob(session.token));
2493
- return typeof parsed.message === "string" && typeof parsed.signature === "string" && parsed.signature.startsWith("0x");
2494
- } catch {
2495
- return false;
2496
- }
2497
- };
2498
- var readYieldseekerSession = (address, chainId) => {
2499
- if (typeof window === "undefined") return null;
2500
- const key2 = buildKey2(address, chainId);
2501
- const store = storage2();
2502
- clearInvalidatedSessions(store, address, chainId);
2503
- let raw2 = null;
2504
- try {
2505
- raw2 = store?.getItem(key2) ?? null;
2506
- } catch {
2507
- raw2 = null;
2508
- }
2509
- if (raw2) {
2510
- try {
2511
- const parsed = JSON.parse(raw2);
2512
- if (isValidSession(parsed)) return parsed.token;
2513
- } catch {
2514
- }
2515
- memorySessions2.delete(key2);
2516
- try {
2517
- store?.removeItem(key2);
2518
- } catch {
2519
- }
2520
- return null;
2521
- }
2522
- const cached = memorySessions2.get(key2);
2523
- if (isValidSession(cached)) return cached.token;
2524
- if (cached) memorySessions2.delete(key2);
2525
- return null;
2526
- };
2527
- var writeYieldseekerSession = (address, chainId, token) => {
2528
- if (typeof window === "undefined") return;
2529
- const session = { token };
2530
- if (!isValidSession(session)) return;
2531
- const key2 = buildKey2(address, chainId);
2532
- memorySessions2.set(key2, session);
2533
- const store = storage2();
2534
- try {
2535
- store?.setItem(key2, JSON.stringify(session));
2536
- } catch {
2537
- }
2538
- };
2539
- var clearYieldseekerSession = (address, chainId) => {
2540
- const key2 = buildKey2(address, chainId);
2541
- memorySessions2.delete(key2);
2542
- const store = storage2();
2543
- clearInvalidatedSessions(store, address, chainId);
2544
- try {
2545
- store?.removeItem(key2);
2546
- } catch {
2547
- }
2548
- };
2549
-
2550
- // src/agents/yieldseeker/yieldseeker.auth.ts
2551
- function resolveSiweOrigin(override) {
2552
- const origin = override?.trim() || (typeof window !== "undefined" ? window.location?.origin : void 0);
2553
- if (!origin || origin === "null") {
2554
- throw new Error("Yieldseeker sign-in requires the requesting app's browser origin.");
2555
- }
2556
- const url = new URL(origin);
2557
- if (url.protocol !== "https:" && url.protocol !== "http:") {
2558
- throw new Error("Yieldseeker sign-in requires an HTTP or HTTPS app origin.");
2559
- }
2560
- if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
2561
- throw new Error("Yieldseeker SIWE override must be an origin without credentials, path, query, or fragment.");
2562
- }
2563
- return url;
2564
- }
2565
- function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
2566
- const url = resolveSiweOrigin(dependencies.origin);
2567
- return new import_siwe.SiweMessage({
2568
- scheme: url.protocol.slice(0, -1),
2569
- domain: url.host,
2570
- address: (0, import_viem4.getAddress)(address),
2571
- uri: url.origin,
2572
- version: "1",
2573
- chainId,
2574
- nonce: (dependencies.nonce ?? import_siwe.generateNonce)(),
2575
- issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
2576
- }).prepareMessage();
2577
- }
2578
- function encodeYieldseekerAuthToken(token) {
2579
- const bytes = new TextEncoder().encode(JSON.stringify(token));
2580
- let binary = "";
2581
- for (const byte of bytes) binary += String.fromCharCode(byte);
2582
- return btoa(binary);
2583
- }
2584
- var YieldseekerAuth = class {
2585
- constructor(dependencies = {}) {
2586
- this.dependencies = dependencies;
2587
- }
2588
- dependencies;
2589
- tokens = /* @__PURE__ */ new Map();
2590
- pending = /* @__PURE__ */ new Map();
2591
- scopes = /* @__PURE__ */ new Map();
2592
- key(state, chainId) {
2593
- return `${state.walletAddress.toLowerCase()}:${chainId}:${resolveSiweOrigin(this.dependencies.origin).origin}`;
2594
- }
2595
- async getToken(state, chainId) {
2596
- const key2 = this.key(state, chainId);
2597
- const scope = { address: state.walletAddress, chainId };
2598
- this.scopes.set(key2, scope);
2599
- const cached = this.tokens.get(key2);
2600
- if (cached) return cached;
2601
- const persisted = readYieldseekerSession(scope.address, scope.chainId);
2602
- if (persisted && this.matchesOrigin(persisted)) {
2603
- this.tokens.set(key2, persisted);
2604
- return persisted;
2605
- }
2606
- if (persisted) clearYieldseekerSession(scope.address, scope.chainId);
2607
- const inFlight = this.pending.get(key2);
2608
- if (inFlight) return inFlight;
2609
- const request = this.sign(state, chainId).then((token) => {
2610
- this.tokens.set(key2, token);
2611
- writeYieldseekerSession(scope.address, scope.chainId, token);
2612
- return token;
2613
- });
2614
- this.pending.set(key2, request);
2615
- try {
2616
- return await request;
2617
- } finally {
2618
- this.pending.delete(key2);
2619
- }
2620
- }
2621
- matchesOrigin(token) {
2622
- try {
2623
- const message = new import_siwe.SiweMessage(JSON.parse(atob(token)).message);
2624
- const url = resolveSiweOrigin(this.dependencies.origin);
2625
- return message.domain === url.host && message.uri === url.origin && message.scheme === url.protocol.slice(0, -1);
2626
- } catch {
2627
- return false;
2628
- }
2629
- }
2630
- clear(state, chainId) {
2631
- if (!state || chainId === void 0) {
2632
- for (const scope of this.scopes.values()) {
2633
- clearYieldseekerSession(scope.address, scope.chainId);
2634
- }
2635
- this.tokens.clear();
2636
- this.pending.clear();
2637
- this.scopes.clear();
2638
- return;
2639
- }
2640
- const key2 = this.key(state, chainId);
2641
- this.tokens.delete(key2);
2642
- this.pending.delete(key2);
2643
- this.scopes.delete(key2);
2644
- clearYieldseekerSession(state.walletAddress, chainId);
2645
- }
2646
- async sign(state, chainId) {
2647
- const account = (0, import_viem4.getAddress)(state.walletAddress);
2648
- const publicClient = (0, import_viem4.createPublicClient)({
2649
- chain: import_chains2.base,
2650
- transport: (0, import_viem4.custom)(state.provider)
2651
- });
2652
- const walletClient = (0, import_viem4.createWalletClient)({
2653
- account,
2654
- chain: import_chains2.base,
2655
- transport: (0, import_viem4.custom)(state.provider)
2656
- });
2657
- await ensureWalletOnChain(
2658
- publicClient,
2659
- walletClient,
2660
- 8453
2661
- );
2662
- const message = createYieldseekerSiweMessage(
2663
- account,
2664
- chainId,
2665
- this.dependencies
2666
- );
2667
- const signature = await walletClient.signMessage({ account, message });
2668
- return encodeYieldseekerAuthToken({ message, signature });
2669
- }
2670
- };
2671
-
2672
- // src/agents/yieldseeker/yieldseeker.identity-cache.ts
2673
- var KEY_PREFIX3 = "owney.yieldseeker.identity.v1";
2674
- var YIELDSEEKER_IDENTITY_TTL_MS = 24 * 60 * 60 * 1e3;
2675
- var memoryIdentities = /* @__PURE__ */ new Map();
2676
- var storage3 = () => {
2677
- if (typeof window === "undefined") return null;
2678
- try {
2679
- return window.localStorage;
2680
- } catch {
2681
- return null;
2682
- }
2683
- };
2684
- var keyFor = (walletAddress, chainId) => `${KEY_PREFIX3}:${walletAddress.toLowerCase()}:${chainId}`;
2685
- function valid(value, walletAddress, chainId, now) {
2686
- return Boolean(
2687
- value && typeof value.userId === "string" && /^[a-zA-Z0-9_-]{1,128}$/.test(value.userId) && value.walletAddress.toLowerCase() === walletAddress.toLowerCase() && value.chainId === chainId && Number.isSafeInteger(value.expiresAt) && value.expiresAt > now
2688
- );
2689
- }
2690
- function readYieldseekerIdentity(walletAddress, chainId, now = Date.now()) {
2691
- if (typeof window === "undefined") return null;
2692
- const key2 = keyFor(walletAddress, chainId);
2693
- const store = storage3();
2694
- let parsed = null;
2695
- try {
2696
- const raw2 = store?.getItem(key2);
2697
- parsed = raw2 ? JSON.parse(raw2) : null;
2698
- } catch {
2699
- parsed = null;
2700
- }
2701
- const candidate = parsed ?? memoryIdentities.get(key2);
2702
- if (valid(candidate, walletAddress, chainId, now)) {
2703
- memoryIdentities.set(key2, candidate);
2704
- return { userId: candidate.userId };
2705
- }
2706
- memoryIdentities.delete(key2);
2707
- try {
2708
- store?.removeItem(key2);
2709
- } catch {
2710
- }
2711
- return null;
2712
- }
2713
- function writeYieldseekerIdentity(walletAddress, chainId, userId, now = Date.now()) {
2714
- if (typeof window === "undefined") return;
2715
- const identity = {
2716
- userId,
2717
- walletAddress,
2718
- chainId,
2719
- expiresAt: now + YIELDSEEKER_IDENTITY_TTL_MS
2720
- };
2721
- if (!valid(identity, walletAddress, chainId, now)) return;
2722
- const key2 = keyFor(walletAddress, chainId);
2723
- memoryIdentities.set(key2, identity);
2724
- try {
2725
- storage3()?.setItem(key2, JSON.stringify(identity));
2726
- } catch {
2727
- }
2728
- }
2729
- function clearYieldseekerIdentity(walletAddress, chainId) {
2730
- const key2 = keyFor(walletAddress, chainId);
2731
- memoryIdentities.delete(key2);
2732
- try {
2733
- storage3()?.removeItem(key2);
2734
- } catch {
2735
- }
2736
- }
2737
-
2738
- // src/agents/yieldseeker/yieldseeker.client.ts
2739
- var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2740
- function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
2741
- return `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/agent/yieldseeker`;
2742
- }
2743
- var YIELDSEEKER_API_BASE_URL = getYieldseekerProxyBaseUrl();
2744
- var YieldseekerApiError = class extends Error {
2745
- constructor(status, providerCode, responseFields) {
2746
- super(`Yieldseeker request failed (${status}): ${providerCode}`);
2747
- this.status = status;
2748
- this.providerCode = providerCode;
2749
- this.responseFields = responseFields;
2750
- this.name = "YieldseekerApiError";
2751
- }
2752
- status;
2753
- providerCode;
2754
- responseFields;
2755
- get isAuthenticationError() {
2756
- return this.status === 401 || this.status === 403;
2757
- }
2758
- };
2759
- function providerError(body, fallback) {
2760
- if (!body || typeof body !== "object") return { code: fallback };
2761
- const record = body;
2762
- return {
2763
- code: typeof record.message === "string" ? record.message : fallback,
2764
- fields: record.fields && typeof record.fields === "object" ? record.fields : void 0
2765
- };
2766
- }
2767
- var YieldseekerApiClient = class {
2768
- constructor(owneyApiKey, baseUrl = YIELDSEEKER_API_BASE_URL, fetchFn = fetch) {
2769
- this.owneyApiKey = owneyApiKey;
2770
- this.baseUrl = baseUrl;
2771
- this.fetchFn = fetchFn;
2772
- }
2773
- owneyApiKey;
2774
- baseUrl;
2775
- fetchFn;
2776
- async request(path, options = {}) {
2777
- const controller = new AbortController();
2778
- const timer = setTimeout(
2779
- () => controller.abort(),
2780
- options.timeoutMs ?? 15e3
2781
- );
2782
- try {
2783
- const response = await this.fetchFn(`${this.baseUrl}${path}`, {
2784
- method: options.method ?? "GET",
2785
- headers: {
2786
- "Content-Type": "application/json",
2787
- "x-owney-api-key": this.owneyApiKey,
2788
- ...options.signature ? { Authorization: `Signature ${options.signature}` } : {}
2789
- },
2790
- body: options.body ? JSON.stringify(options.body) : void 0,
2791
- signal: controller.signal
2792
- });
2793
- const payload = await response.json().catch(() => null);
2794
- if (!response.ok) {
2795
- const error = providerError(payload, `HTTP_${response.status}`);
2796
- throw new YieldseekerApiError(
2797
- response.status,
2798
- error.code,
2799
- error.fields
2800
- );
2801
- }
2802
- if (payload && typeof payload === "object" && payload.success === true && "data" in payload) {
2803
- return payload.data;
2804
- }
2805
- return payload;
2806
- } catch (error) {
2807
- if (error instanceof YieldseekerApiError) throw error;
2808
- if (error instanceof DOMException && error.name === "AbortError") {
2809
- throw new YieldseekerApiError(408, "REQUEST_TIMEOUT");
2810
- }
2811
- throw new YieldseekerApiError(0, "NETWORK_ERROR", {
2812
- cause: error instanceof Error ? error.message : String(error)
2813
- });
2814
- } finally {
2815
- clearTimeout(timer);
2816
- }
2817
- }
2818
- };
2819
-
2820
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2821
- var import_viem5 = require("viem");
2822
-
2823
- // src/agents/yieldseeker/yieldseeker.types.ts
2824
- var YIELDSEEKER_ASSET_METADATA = {
2825
- USDC: {
2826
- address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
2827
- decimals: 6
2828
- },
2829
- WETH: {
2830
- address: "0x4200000000000000000000000000000000000006",
2831
- decimals: 18
2832
- }
2833
- };
2834
-
2835
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2836
- function invalid(endpoint, detail) {
2837
- throw new OwneyError(
2838
- "AGENT_INVALID_RESPONSE",
2839
- `Yieldseeker returned an invalid ${endpoint} response: ${detail}.`,
2840
- { endpoint, detail },
2841
- "yieldseeker"
2842
- );
2843
- }
2844
- function raw(value, endpoint) {
2845
- if (typeof value !== "string" || !/^-?[0-9]+$/.test(value)) {
2846
- return invalid(endpoint, "expected a base-10 integer string");
2847
- }
2848
- return BigInt(value);
2849
- }
2850
- function decimal(value, decimals, endpoint) {
2851
- return (0, import_viem5.formatUnits)(raw(value, endpoint), decimals);
2852
- }
2853
- function usd(rawAmount, decimals, price) {
2854
- return Number((0, import_viem5.formatUnits)(rawAmount, decimals)) * price;
2855
- }
2856
- function percent(value) {
2857
- const result = Number(value);
2858
- return Number.isFinite(result) ? result * 100 : 0;
2859
- }
2860
- var YIELDSEEKER_POSITIVE_YIELD_FEE_RATE = 0.1;
2861
- function publicApyAfterYieldseekerFee(value) {
2862
- const grossPercent = percent(value);
2863
- if (grossPercent <= 0) return grossPercent;
2864
- const netPercent = grossPercent * (1 - YIELDSEEKER_POSITIVE_YIELD_FEE_RATE);
2865
- return Math.round(netPercent * 1e12) / 1e12;
2866
- }
2867
- function riskAdjustedApyForDays(option, days) {
2868
- if (days === "7D") return option.riskAdjustedApy7dAverage;
2869
- if (days === "30D") return option.riskAdjustedApy30dAverage;
2870
- return (option.riskAdjustedApy7dAverage + option.riskAdjustedApy30dAverage) / 2;
2871
- }
2872
- function assetAddressValue(record, address) {
2873
- const entry = Object.entries(record).find(
2874
- ([key2]) => key2.toLowerCase() === address.toLowerCase()
2875
- );
2876
- return entry?.[1] ?? "0";
2877
- }
2878
- function position(value, asset, baseAssetDecimals) {
2879
- const option = value?.yieldOption;
2880
- if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem5.isAddress)(option.address)) {
2881
- return invalid("yield positions", "missing vault metadata");
2882
- }
2883
- return {
2884
- chain: "BASE",
2885
- protocol: option.provider,
2886
- protocolId: option.address,
2887
- pool: option.name,
2888
- asset,
2889
- // `assetsRaw` is the ERC-4626 vault-share quantity, whose decimals can
2890
- // differ from the underlying asset. Yieldseeker already converts it to
2891
- // underlying base-asset units in `assetsBase`; pair that value with the
2892
- // snapshot's corresponding `baseAssetDecimals` for display. Keep the raw
2893
- // share quantity separately because withdraw-from-position expects it.
2894
- amount: decimal(
2895
- value.assetsBase,
2896
- baseAssetDecimals,
2897
- "yield positions"
2898
- ),
2899
- amountRaw: String(value.assetsRaw),
2900
- apy: percent(option.riskAdjustedApy),
2901
- tvl: Number(option.totalDepositsUsd),
2902
- liquidity: Number(option.withdrawableDepositsUsd)
2903
- };
2904
- }
2905
- function mapYieldseekerBalances(contexts) {
2906
- const tokens = [];
2907
- const assetBalances = [];
2908
- const positions = [];
2909
- let totalUsd = 0;
2910
- for (const context of contexts) {
2911
- const metadata = YIELDSEEKER_ASSET_METADATA[context.asset];
2912
- assetBalances.push({
2913
- chain: "BASE",
2914
- chainId: 8453,
2915
- asset: context.asset,
2916
- amount: decimal(context.snapshot.totalValueBase, context.snapshot.baseAssetDecimals, "snapshot")
2917
- });
2918
- const idle = assetAddressValue(
2919
- context.snapshot.tokenBalances,
2920
- metadata.address
2921
- );
2922
- tokens.push({
2923
- chain: "BASE",
2924
- chainId: 8453,
2925
- asset: context.asset,
2926
- amount: decimal(idle, metadata.decimals, "snapshot")
2927
- });
2928
- positions.push(
2929
- ...context.positions.map(
2930
- (entry) => position(
2931
- entry,
2932
- context.asset,
2933
- context.snapshot.baseAssetDecimals
2934
- )
2935
- )
2936
- );
2937
- totalUsd += usd(
2938
- raw(context.snapshot.totalValueBase, "snapshot"),
2939
- context.snapshot.baseAssetDecimals,
2940
- context.snapshot.baseAssetPriceUsd
2941
- );
2942
- }
2943
- return {
2944
- ...contexts.length === 1 ? { smartWallet: contexts[0].wallet.walletAddress } : {},
2945
- totalBalance: String(totalUsd),
2946
- totalBalanceAsset: "usdc",
2947
- assetBalances,
2948
- tokens,
2949
- positions
2950
- };
2951
- }
2952
- function mapYieldseekerEarnings(contexts) {
2953
- const tokens = [];
2954
- let lifetimeEarnings = 0;
2955
- for (const context of contexts) {
2956
- const amount = raw(context.snapshot.cumulativeYieldBase, "snapshot");
2957
- tokens.push({
2958
- chain: "BASE",
2959
- chainId: 8453,
2960
- asset: context.asset,
2961
- amount: (0, import_viem5.formatUnits)(amount, context.snapshot.baseAssetDecimals)
2962
- });
2963
- lifetimeEarnings += usd(
2964
- amount,
2965
- context.snapshot.baseAssetDecimals,
2966
- context.snapshot.baseAssetPriceUsd
2967
- );
2968
- }
2969
- return {
2970
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
2971
- lifetimeEarnings,
2972
- tokens
2973
- };
2974
- }
2975
- function apyForDays(snapshot, days) {
2976
- if (days === "7D") return percent(snapshot.apy7d);
2977
- if (days === "30D") return percent(snapshot.apy30d);
2978
- return percent((snapshot.apy7d + snapshot.apy30d) / 2);
2979
- }
2980
- function dailyApy(point) {
2981
- const total = raw(point.totalValueBase, "historic position");
2982
- const earned = raw(point.dailyYieldBase, "historic position");
2983
- const principal = total - earned;
2984
- if (principal <= 0n || earned === 0n) return 0;
2985
- return Number(earned) / Number(principal) * 365 * 100;
2986
- }
2987
- function aggregateHistory(contexts, dayCount) {
2988
- const byDate = /* @__PURE__ */ new Map();
2989
- for (const context of contexts) {
2990
- const points = context.historic?.dailyYieldSnapshots ?? [];
2991
- for (const point of points.slice(-dayCount)) {
2992
- const valueUsd = usd(
2993
- raw(point.totalValueBase, "historic position"),
2994
- point.baseAssetDecimals,
2995
- point.baseAssetPriceUsd
2996
- );
2997
- const current = byDate.get(point.date) ?? { weighted: 0, valueUsd: 0 };
2998
- current.weighted += dailyApy(point) * valueUsd;
2999
- current.valueUsd += valueUsd;
3000
- byDate.set(point.date, current);
3001
- }
3002
- }
3003
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
3004
- date,
3005
- apy: value.valueUsd > 0 ? value.weighted / value.valueUsd : 0
3006
- }));
3007
- }
3008
- function mapYieldseekerApy(walletAddress, contexts, days) {
3009
- let weighted = 0;
3010
- let totalUsd = 0;
3011
- const byAsset = {};
3012
- for (const context of contexts) {
3013
- const valueUsd = usd(
3014
- raw(context.snapshot.totalValueBase, "snapshot"),
3015
- context.snapshot.baseAssetDecimals,
3016
- context.snapshot.baseAssetPriceUsd
3017
- );
3018
- const apy = apyForDays(context.snapshot, days);
3019
- weighted += apy * valueUsd;
3020
- totalUsd += valueUsd;
3021
- byAsset[context.asset] = apy;
3022
- }
3023
- const dayCount = Number(days.slice(0, -1));
3024
- return {
3025
- walletAddress,
3026
- weightedApyAfterFee: totalUsd > 0 ? weighted / totalUsd : 0,
3027
- apyByChainAndAsset: { 8453: byAsset },
3028
- history: aggregateHistory(contexts, dayCount)
3029
- };
3030
- }
3031
- function actionType(value) {
3032
- const normalized = value.toLowerCase();
3033
- if (normalized.includes("deposit")) return "Deposit";
3034
- if (normalized.includes("withdraw")) return "Withdraw";
3035
- if (normalized.includes("yield") || normalized.includes("earn"))
3036
- return "Earned";
3037
- return "Rebalance";
3038
- }
3039
- function transactionHashes(details) {
3040
- if (!details) return [];
3041
- const values = [
3042
- details.transactionHash,
3043
- details.txHash,
3044
- ...Array.isArray(details.transactionHashes) ? details.transactionHashes : [],
3045
- ...Array.isArray(details.txHashes) ? details.txHashes : []
3046
- ];
3047
- return values.filter(
3048
- (value) => typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value)
3049
- ).filter((value, index, all) => all.indexOf(value) === index);
3050
- }
3051
- function actionEntry(action) {
3052
- if (action.actionType.toLowerCase().includes("withdraw")) return void 0;
3053
- return {
3054
- agent: "yieldseeker",
3055
- action: actionType(action.actionType),
3056
- date: action.createdDate,
3057
- oldApy: null,
3058
- newApy: null,
3059
- transactions: [
3060
- {
3061
- txHashes: transactionHashes(action.details),
3062
- chainId: 8453
3063
- }
3064
- ],
3065
- rebalanceLog: []
3066
- };
3067
- }
3068
- function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddresses) {
3069
- const from = movement.fromAddress.toLowerCase();
3070
- const to = movement.toAddress.toLowerCase();
3071
- const owner = ownerAddress.toLowerCase();
3072
- const agentWallet = wallet.walletAddress.toLowerCase();
3073
- const baseAsset = agent.assetAddress.toLowerCase();
3074
- if (movement.chainId !== agent.chainId || movement.assetAddress.toLowerCase() !== baseAsset) {
3075
- return void 0;
3076
- }
3077
- let action;
3078
- if (from === owner && to === agentWallet) {
3079
- action = "Top up";
3080
- } else if (from === agentWallet && to === owner) {
3081
- action = "Withdraw";
3082
- } else if (from === agentWallet && vaultAddresses.has(to)) {
3083
- action = "Deposit";
3084
- }
3085
- if (!action) return void 0;
3086
- return {
3087
- agent: "yieldseeker",
3088
- action,
3089
- date: movement.blockDate,
3090
- oldApy: null,
3091
- newApy: null,
3092
- transactions: [
3093
- {
3094
- txHashes: [movement.transactionHash],
3095
- chainId: agent.chainId,
3096
- tokenSymbol: asset,
3097
- amount: decimal(
3098
- movement.assetAmount,
3099
- YIELDSEEKER_ASSET_METADATA[asset].decimals,
3100
- "historic position"
3101
- )
3102
- }
3103
- ],
3104
- rebalanceLog: []
3105
- };
3106
- }
3107
- function mapYieldseekerHistory(contexts, options) {
3108
- const entries = contexts.flatMap((context) => {
3109
- const vaultAddresses = new Set(
3110
- context.positions.map(
3111
- (position2) => position2.yieldOption.address.toLowerCase()
3112
- )
3113
- );
3114
- return [
3115
- ...(context.historic?.movements ?? []).map(
3116
- (movement) => movementEntry(
3117
- movement,
3118
- context.wallet,
3119
- context.agent,
3120
- context.asset,
3121
- options.ownerAddress,
3122
- vaultAddresses
3123
- )
3124
- ),
3125
- ...(context.actions ?? []).map(actionEntry)
3126
- ].filter((entry) => entry !== void 0);
3127
- });
3128
- const filtered = entries.filter(
3129
- (entry) => (!options.fromDate || entry.date >= options.fromDate) && (!options.toDate || entry.date <= options.toDate)
3130
- ).filter((entry, index, all) => {
3131
- const transactionHash = entry.transactions[0]?.txHashes[0];
3132
- if (!transactionHash) return true;
3133
- return all.findIndex(
3134
- (candidate) => candidate.action === entry.action && candidate.transactions[0]?.txHashes[0] === transactionHash
3135
- ) === index;
3136
- }).sort((left, right) => right.date.localeCompare(left.date));
3137
- return {
3138
- data: filtered.slice(0, options.limit),
3139
- // v1 returns the whole action/movement collection and defines no cursor.
3140
- // Report a terminal page so callers never loop over the same prefix.
3141
- hasMore: false
3142
- };
3143
- }
3144
- function mapYieldseekerProfile(address, contexts) {
3145
- const protocols = /* @__PURE__ */ new Set();
3146
- for (const context of contexts) {
3147
- for (const current of context.positions) {
3148
- if (current.yieldOption?.provider) {
3149
- protocols.add(String(current.yieldOption.provider));
3150
- }
3151
- }
3152
- }
3153
- return {
3154
- address,
3155
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
3156
- chains: contexts.length > 0 ? [8453] : [],
3157
- hasActiveSessionKey: contexts.some(
3158
- (context) => context.wallet.initializedDate != null
3159
- ),
3160
- protocols: [...protocols]
3161
- };
3162
- }
3163
- function mapYieldseekerAgentApy(options, days) {
3164
- const perAsset = {};
3165
- const all = [];
3166
- for (const entry of options) {
3167
- const apys = entry.yieldOptions.map(
3168
- (option) => publicApyAfterYieldseekerFee(riskAdjustedApyForDays(option, days))
3169
- ).filter(Number.isFinite);
3170
- if (apys.length === 0) continue;
3171
- const average = apys.reduce((sum, value) => sum + value, 0) / apys.length;
3172
- perAsset[entry.asset] = average;
3173
- all.push(average);
3174
- }
3175
- return {
3176
- averageApy: all.length > 0 ? all.reduce((sum, value) => sum + value, 0) / all.length : 0,
3177
- detailedApys: { apyPerAsset: { 8453: perAsset } }
3178
- };
3179
- }
3180
-
3181
- // src/agents/yieldseeker/yieldseeker.agent.ts
3182
- var OWNEY_AGENT_NAME = "owney";
3183
- var YIELDSEEKER_USERNAME_PREFIX = "owney_";
3184
- var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
3185
- var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
3186
- function generateYieldseekerUsername() {
3187
- const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
3188
- return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
3189
- }
3190
- function isUsernameConflict(error) {
3191
- if (!(error instanceof YieldseekerApiError)) return false;
3192
- const code = error.providerCode.toUpperCase();
3193
- return code.includes("USERNAME") && (code.includes("TAKEN") || code.includes("EXIST") || code.includes("UNAVAILABLE") || code.includes("IN_USE"));
3194
- }
3195
- var YIELDSEEKER_AGENT_WALLET_ABI = [
3196
- {
3197
- type: "function",
3198
- name: "withdrawAssetToUser",
3199
- stateMutability: "nonpayable",
3200
- inputs: [
3201
- { name: "recipient", type: "address" },
3202
- { name: "asset", type: "address" },
3203
- { name: "amount", type: "uint256" }
3204
- ],
3205
- outputs: []
3206
- },
3207
- {
3208
- type: "function",
3209
- name: "withdrawAllAssetToUser",
3210
- stateMutability: "nonpayable",
3211
- inputs: [
3212
- { name: "recipient", type: "address" },
3213
- { name: "asset", type: "address" }
3214
- ],
3215
- outputs: []
3216
- }
3217
- ];
3218
- function query(params) {
3219
- const search = new URLSearchParams();
3220
- for (const [key2, value] of Object.entries(params)) {
3221
- if (value !== void 0) search.set(key2, String(value));
3222
- }
3223
- const encoded = search.toString();
3224
- return encoded ? `?${encoded}` : "";
3225
- }
3226
- var YieldseekerAgent = class {
3227
- id = "yieldseeker";
3228
- balanceComposition = "tokens-plus-positions";
3229
- supportedChainIds = [8453];
3230
- supportedAssets = [
3231
- {
3232
- chainId: 8453,
3233
- chain: "BASE",
3234
- assets: [
3235
- { symbol: "USDC", minDepositAmount: "10000000" },
3236
- { symbol: "WETH", minDepositAmount: "1" }
3237
- ]
3238
- }
3239
- ];
3240
- api;
3241
- auth;
3242
- transactionExecutor;
3243
- unwindReceiptWaiter;
3244
- agentContexts = /* @__PURE__ */ new Map();
3245
- users = /* @__PURE__ */ new Map();
3246
- pendingAgents = /* @__PURE__ */ new Map();
3247
- constructor(owneyApiKey, options = {}) {
3248
- this.api = new YieldseekerApiClient(
3249
- owneyApiKey,
3250
- options.baseUrl ?? getYieldseekerProxyBaseUrl(),
3251
- options.fetchFn
3252
- );
3253
- this.auth = new YieldseekerAuth(options.auth);
3254
- this.transactionExecutor = options.transactionExecutor;
3255
- this.unwindReceiptWaiter = options.unwindReceiptWaiter;
3256
- }
3257
- async disconnect() {
3258
- this.auth.clear();
3259
- for (const key2 of this.users.keys()) {
3260
- const [walletAddress, chainId] = key2.split(":");
3261
- clearYieldseekerIdentity(walletAddress, Number(chainId));
3262
- }
3263
- this.users.clear();
3264
- this.agentContexts.clear();
3265
- this.pendingAgents.clear();
3266
- }
3267
- async activateAgent(state, chainId, asset) {
3268
- this.assertChain(chainId);
3269
- const targetAsset = asset ?? "USDC";
3270
- this.assertAsset(targetAsset);
3271
- await this.ensureAgent(state, chainId, targetAsset);
3272
- }
3273
- async deposit(state, chainId, amount, asset, depositCallback) {
3274
- this.assertChain(chainId);
3275
- this.assertAsset(asset);
3276
- if (BigInt(amount) <= 0n) {
3277
- throw new OwneyError(
3278
- "DEPOSIT_AMOUNT_BELOW_MINIMUM",
3279
- "Yieldseeker deposits must be greater than zero.",
3280
- { amount, minDepositAmount: "1" },
3281
- this.id
3282
- );
3283
- }
3284
- const context = await this.ensureAgent(state, chainId, asset);
3285
- let txHash;
3286
- try {
3287
- if (depositCallback) {
3288
- provideDepositVerificationContext(depositCallback, {
3289
- agentId: "yieldseeker",
3290
- signature: await this.auth.getToken(state, chainId),
3291
- userId: context.user.userId,
3292
- yieldseekerAgentId: context.agent.agentId
3293
- });
3294
- txHash = await depositCallback(
3295
- context.wallet.walletAddress,
3296
- chainId,
3297
- amount
3298
- );
3299
- await this.waitForReceipt(state, chainId, txHash);
3300
- } else {
3301
- txHash = await this.submitTransaction(state, chainId, {
3302
- from: (0, import_viem6.getAddress)(state.walletAddress),
3303
- to: YIELDSEEKER_ASSET_METADATA[asset].address,
3304
- data: (0, import_viem6.encodeFunctionData)({
3305
- abi: import_viem6.erc20Abi,
3306
- functionName: "transfer",
3307
- args: [(0, import_viem6.getAddress)(context.wallet.walletAddress), BigInt(amount)]
3308
- }),
3309
- value: "0",
3310
- chainId
3311
- });
3312
- }
3313
- await this.deployAfterFunding(state, chainId, context);
3314
- } finally {
3315
- await this.refreshSnapshotAfterMovement(
3316
- state,
3317
- chainId,
3318
- context,
3319
- "deposit"
3320
- );
3321
- }
3322
- return {
3323
- txHash,
3324
- smartWallet: context.wallet.walletAddress,
3325
- amount
3326
- };
3327
- }
3328
- async withdraw(state, chainId, asset, amount) {
3329
- this.assertChain(chainId);
3330
- this.assertAsset(asset);
3331
- if (amount !== void 0 && BigInt(amount) <= 0n) {
3332
- throw new OwneyError(
3333
- "WITHDRAW_FAILED",
3334
- "Yieldseeker withdrawals must be greater than zero.",
3335
- { amount },
3336
- this.id
3337
- );
3338
- }
3339
- const context = await this.findAgent(state, chainId, asset);
3340
- if (!context) {
3341
- throw new OwneyError(
3342
- "WITHDRAW_INSUFFICIENT_BALANCE",
3343
- `No Yieldseeker ${asset} agent exists for this wallet.`,
3344
- { asset, available: "0" },
3345
- this.id
3346
- );
3347
- }
3348
- try {
3349
- const portfolio = await this.loadPortfolioContext(
3350
- state,
3351
- chainId,
3352
- context
3353
- );
3354
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3355
- const idleEntry = Object.entries(portfolio.snapshot.tokenBalances).find(
3356
- ([address]) => address.toLowerCase() === metadata.address.toLowerCase()
3357
- );
3358
- const idle = BigInt(idleEntry?.[1] ?? "0");
3359
- const deployed = portfolio.positions.reduce(
3360
- (total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
3361
- 0n
3362
- );
3363
- const totalAvailable = idle + deployed;
3364
- const requested = amount === void 0 ? totalAvailable : BigInt(amount);
3365
- if (requested > totalAvailable) {
3366
- throw new OwneyError(
3367
- "WITHDRAW_INSUFFICIENT_BALANCE",
3368
- `Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
3369
- {
3370
- asset,
3371
- requested: requested.toString(),
3372
- available: totalAvailable.toString()
3373
- },
3374
- this.id
3375
- );
3376
- }
3377
- let remaining = requested > idle ? requested - idle : 0n;
3378
- for (const position2 of portfolio.positions) {
3379
- if (remaining === 0n) break;
3380
- const available = BigInt(position2.withdrawableAssetsRaw);
3381
- if (available <= 0n) continue;
3382
- const assetsRaw = available < remaining ? available : remaining;
3383
- const response = await this.walletRequest(
3384
- state,
3385
- chainId,
3386
- this.agentPath(context, "withdraw-from-position"),
3387
- {
3388
- method: "POST",
3389
- body: {
3390
- chainId,
3391
- vaultAddress: position2.yieldOption.address,
3392
- assetsRaw: assetsRaw.toString()
3393
- }
3394
- }
3395
- );
3396
- if (!this.isTransactionHash(response?.transactionHash)) {
3397
- throw this.invalidResponse("position withdrawal");
3398
- }
3399
- await this.waitForReceipt(state, chainId, response.transactionHash);
3400
- remaining -= assetsRaw;
3401
- }
3402
- if (remaining > 0n) {
3403
- throw this.invalidResponse("yield positions", {
3404
- reason: "Withdrawable positions could not cover the request.",
3405
- remaining: remaining.toString()
3406
- });
3407
- }
3408
- const account = (0, import_viem6.getAddress)(state.walletAddress);
3409
- const txHash = await this.submitTransaction(state, chainId, {
3410
- from: account,
3411
- to: (0, import_viem6.getAddress)(context.wallet.walletAddress),
3412
- data: amount === void 0 ? (0, import_viem6.encodeFunctionData)({
3413
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3414
- functionName: "withdrawAllAssetToUser",
3415
- args: [account, metadata.address]
3416
- }) : (0, import_viem6.encodeFunctionData)({
3417
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3418
- functionName: "withdrawAssetToUser",
3419
- args: [account, metadata.address, requested]
3420
- }),
3421
- value: "0",
3422
- chainId
3423
- });
3424
- return {
3425
- txHash,
3426
- type: amount === void 0 ? "full" : "partial",
3427
- amount: requested.toString()
3428
- };
3429
- } finally {
3430
- await this.refreshSnapshotAfterMovement(
3431
- state,
3432
- chainId,
3433
- context,
3434
- "withdrawal"
3435
- );
3436
- }
3437
- }
3438
- async getBalances(state, chainId) {
3439
- this.assertChain(chainId);
3440
- return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, {}));
3441
- }
3442
- async getEarnings(state, chainId) {
3443
- this.assertChain(chainId);
3444
- return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
3445
- }
3446
- async getAccountApy(state, chainId, days, tokenSymbol) {
3447
- this.assertChain(chainId);
3448
- const asset = tokenSymbol?.toUpperCase();
3449
- if (asset !== void 0) this.assertAsset(asset);
3450
- const contexts = await this.loadPortfolio(state, chainId, {
3451
- ...asset ? { asset } : {},
3452
- historic: true
3453
- });
3454
- return mapYieldseekerApy(state.walletAddress, contexts, days);
3455
- }
3456
- async getHistory(state, chainId, options) {
3457
- this.assertChain(chainId);
3458
- const asset = options?.tokenSymbol?.toUpperCase();
3459
- if (asset !== void 0) this.assertAsset(asset);
3460
- const contexts = await this.loadPortfolio(state, chainId, {
3461
- ...asset ? { asset } : {},
3462
- historic: true,
3463
- actions: true
3464
- });
3465
- return mapYieldseekerHistory(contexts, {
3466
- limit: options?.limit ?? 10,
3467
- ownerAddress: state.walletAddress,
3468
- ...options?.fromDate ? { fromDate: options.fromDate } : {},
3469
- ...options?.toDate ? { toDate: options.toDate } : {}
3470
- });
3471
- }
3472
- async getUserProfile(state, chainId) {
3473
- this.assertChain(chainId);
3474
- return mapYieldseekerProfile(
3475
- state.walletAddress,
3476
- await this.loadPortfolio(state, chainId, {})
3477
- );
3478
- }
3479
- async getAgentApy(days, options) {
3480
- this.assertOptionalChain(options?.chainId);
3481
- const requested = options?.tokenSymbol?.toUpperCase();
3482
- if (requested !== void 0) this.assertAsset(requested);
3483
- const assets = requested ? [requested] : ["USDC", "WETH"];
3484
- const values = await Promise.all(
3485
- assets.map(async (asset) => {
3486
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3487
- const response = await this.api.request(
3488
- `/chains/8453/assets/${metadata.address}/yield-options`
3489
- );
3490
- if (!Array.isArray(response?.yieldOptions)) {
3491
- throw this.invalidResponse("yield options");
3492
- }
3493
- return { asset, yieldOptions: response.yieldOptions };
3494
- })
3495
- );
3496
- return mapYieldseekerAgentApy(values, days);
3497
- }
3498
- userKey(state, chainId) {
3499
- return `${state.walletAddress.toLowerCase()}:${chainId}`;
3500
- }
3501
- contextKey(state, chainId, asset) {
3502
- return `${this.userKey(state, chainId)}:${asset}`;
3503
- }
3504
- async resolveUser(state, chainId) {
3505
- const key2 = this.userKey(state, chainId);
3506
- const inMemory = this.users.get(key2);
3507
- if (inMemory) return inMemory;
3508
- const persisted = readYieldseekerIdentity(state.walletAddress, chainId);
3509
- if (persisted) {
3510
- this.users.set(key2, persisted);
3511
- return persisted;
3512
- }
3513
- const walletAddress = (0, import_viem6.getAddress)(state.walletAddress);
3514
- let user = null;
3515
- try {
3516
- const login = await this.providerRequest(
3517
- state,
3518
- chainId,
3519
- "/users/login-with-wallet",
3520
- { method: "POST", body: { walletAddress } }
3521
- );
3522
- user = login?.user ?? null;
3523
- if (!user) {
3524
- throw this.invalidResponse("wallet login", {
3525
- reason: "A successful login returned no user."
3526
- });
3527
- }
3528
- } catch (error) {
3529
- if (!(error instanceof YieldseekerApiError) || error.providerCode !== "NO_USER") {
3530
- if (error instanceof OwneyError) throw error;
3531
- throw this.mapApiError(error);
3532
- }
3533
- let created;
3534
- for (let attempt = 0; attempt < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS; attempt += 1) {
3535
- try {
3536
- created = await this.providerRequest(
3537
- state,
3538
- chainId,
3539
- "/users",
3540
- {
3541
- method: "POST",
3542
- body: {
3543
- walletAddress,
3544
- username: generateYieldseekerUsername()
3545
- }
3546
- }
3547
- );
3548
- break;
3549
- } catch (createError) {
3550
- const canRetry = isUsernameConflict(createError) && attempt + 1 < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS;
3551
- if (canRetry) continue;
3552
- throw this.mapApiError(createError);
3553
- }
3554
- }
3555
- user = created?.user ?? null;
3556
- }
3557
- if (!user || !/^[a-zA-Z0-9_-]{1,128}$/.test(user.userId)) {
3558
- throw this.invalidResponse("wallet identity");
3559
- }
3560
- const resolved = { userId: user.userId };
3561
- this.users.set(key2, resolved);
3562
- writeYieldseekerIdentity(state.walletAddress, chainId, resolved.userId);
3563
- return resolved;
3564
- }
3565
- forgetUser(state, chainId) {
3566
- this.users.delete(this.userKey(state, chainId));
3567
- clearYieldseekerIdentity(state.walletAddress, chainId);
3568
- }
3569
- async ensureAgent(state, chainId, asset) {
3570
- const key2 = this.contextKey(state, chainId, asset);
3571
- const cached = this.agentContexts.get(key2);
3572
- if (cached) return cached;
3573
- const pending = this.pendingAgents.get(key2);
3574
- if (pending) return pending;
3575
- const request = this.resolveAgent(state, chainId, asset, true).then(
3576
- (context) => {
3577
- if (!context) throw this.invalidResponse("agent creation");
3578
- this.agentContexts.set(key2, context);
3579
- return context;
3580
- }
3581
- );
3582
- this.pendingAgents.set(key2, request);
3583
- try {
3584
- return await request;
3585
- } finally {
3586
- this.pendingAgents.delete(key2);
3587
- }
3588
- }
3589
- async findAgent(state, chainId, asset) {
3590
- const key2 = this.contextKey(state, chainId, asset);
3591
- const cached = this.agentContexts.get(key2);
3592
- if (cached) return cached;
3593
- const context = await this.resolveAgent(state, chainId, asset, false);
3594
- if (context) this.agentContexts.set(key2, context);
3595
- return context;
3596
- }
3597
- async resolveAgent(state, chainId, asset, createIfMissing) {
3598
- const user = await this.resolveUser(state, chainId);
3599
- const response = await this.walletRequest(
3600
- state,
3601
- chainId,
3602
- `/users/${user.userId}/agents`
3603
- );
3604
- if (!Array.isArray(response?.agents)) {
3605
- throw this.invalidResponse("agent list");
3606
- }
3607
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3608
- let agent = response.agents.find(
3609
- (candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
3610
- );
3611
- if (!agent && createIfMissing) {
3612
- const created = await this.walletRequest(
3613
- state,
3614
- chainId,
3615
- `/users/${user.userId}/agents`,
3616
- {
3617
- method: "POST",
3618
- body: {
3619
- name: OWNEY_AGENT_NAME,
3620
- emoji: "\u{1F989}",
3621
- chainId,
3622
- assetAddress: metadata.address,
3623
- type: "vault",
3624
- rulePreset: null
3625
- }
3626
- }
3627
- );
3628
- agent = created?.agent;
3629
- }
3630
- if (!agent) return null;
3631
- this.assertAgent(agent);
3632
- const walletResponse = await this.walletRequest(
3633
- state,
3634
- chainId,
3635
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3636
- );
3637
- if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
3638
- throw this.invalidResponse("agent wallet");
3639
- }
3640
- return { user, agent, wallet: walletResponse.agentWallet, asset };
3641
- }
3642
- async loadPortfolio(state, chainId, options) {
3643
- const user = await this.resolveUser(state, chainId);
3644
- const response = await this.walletRequest(
3645
- state,
3646
- chainId,
3647
- `/users/${user.userId}/agents`
3648
- );
3649
- if (!Array.isArray(response?.agents)) {
3650
- throw this.invalidResponse("agent list");
3651
- }
3652
- const contexts = [];
3653
- for (const agent of response.agents) {
3654
- const asset = this.assetForAgent(agent);
3655
- if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
3656
- continue;
3657
- }
3658
- this.assertAgent(agent);
3659
- const walletResponse = await this.walletRequest(
3660
- state,
3661
- chainId,
3662
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3663
- );
3664
- if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
3665
- throw this.invalidResponse("agent wallet");
3666
- }
3667
- const context = {
3668
- user,
3669
- agent,
3670
- wallet: walletResponse.agentWallet,
3671
- asset
3672
- };
3673
- this.agentContexts.set(this.contextKey(state, chainId, asset), context);
3674
- contexts.push(context);
3675
- }
3676
- return Promise.all(
3677
- contexts.map(
3678
- (context) => this.loadPortfolioContext(state, chainId, context, options)
3679
- )
3680
- );
3681
- }
3682
- async loadPortfolioContext(state, chainId, context, options = {}) {
3683
- const [snapshot, positions, historic, actions] = await Promise.all([
3684
- this.walletRequest(
3685
- state,
3686
- chainId,
3687
- `${this.agentPath(context, "snapshot")}${query({
3688
- shouldOnlyUseRecentValue: true,
3689
- shouldAllowStaleOnError: true
3690
- })}`
3691
- ),
3692
- this.walletRequest(
3693
- state,
3694
- chainId,
3695
- this.agentPath(context, "yield-positions")
3696
- ),
3697
- options.historic ? this.walletRequest(
3698
- state,
3699
- chainId,
3700
- this.agentPath(context, "wallet/historic-position")
3701
- ) : Promise.resolve(void 0),
3702
- options.actions ? this.walletRequest(
3703
- state,
3704
- chainId,
3705
- this.agentPath(context, "actions")
3706
- ) : Promise.resolve(void 0)
3707
- ]);
3708
- if (!snapshot?.agentSnapshot) {
3709
- throw this.invalidResponse("agent snapshot");
3710
- }
3711
- if (!Array.isArray(positions?.yieldPositions)) {
3712
- throw this.invalidResponse("yield positions");
3713
- }
3714
- return {
3715
- ...context,
3716
- snapshot: snapshot.agentSnapshot,
3717
- positions: positions.yieldPositions,
3718
- ...historic?.position ? { historic: historic.position } : {},
3719
- ...actions?.actions ? { actions: actions.actions } : {}
3720
- };
3721
- }
3722
- async deployAfterFunding(state, chainId, context) {
3723
- if (context.wallet.initializedDate != null) return;
3724
- try {
3725
- const deployed = await this.walletRequest(
3726
- state,
3727
- chainId,
3728
- this.agentPath(context, "deploy"),
3729
- { method: "POST", body: {} }
3730
- );
3731
- if (deployed?.agentWallet) {
3732
- context.wallet = deployed.agentWallet;
3733
- }
3734
- } catch (error) {
3735
- console.warn(
3736
- "[owney-sdk] Yieldseeker deposit is funded but not deployable yet:",
3737
- error
3738
- );
3739
- }
3740
- }
3741
- async refreshSnapshotAfterMovement(state, chainId, context, movement) {
3742
- try {
3743
- const response = await this.walletRequest(
3744
- state,
3745
- chainId,
3746
- `${this.agentPath(context, "snapshot")}${query({
3747
- shouldForceRefresh: true
3748
- })}`
3749
- );
3750
- if (!response?.agentSnapshot) {
3751
- throw this.invalidResponse("agent snapshot refresh");
3752
- }
3753
- } catch (error) {
3754
- console.warn(
3755
- `[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
3756
- error
3757
- );
3758
- }
3759
- }
3760
- agentPath(context, suffix) {
3761
- return `/users/${context.user.userId}/agents/${context.agent.agentId}/${suffix}`;
3762
- }
3763
- async walletRequest(state, chainId, path, options = {}) {
3764
- try {
3765
- return await this.providerRequest(state, chainId, path, options);
3766
- } catch (error) {
3767
- throw this.mapApiError(error);
3768
- }
3769
- }
3770
- async providerRequest(state, chainId, path, options = {}) {
3771
- this.assertChain(chainId);
3772
- const request = (signature2) => this.api.request(path, {
3773
- ...options,
3774
- signature: signature2
3775
- });
3776
- let signature = await this.auth.getToken(state, chainId);
3777
- try {
3778
- return await request(signature);
3779
- } catch (error) {
3780
- if (!(error instanceof YieldseekerApiError)) throw error;
3781
- if (error.providerCode === "NO_USER") throw error;
3782
- if (!error.isAuthenticationError) throw error;
3783
- this.auth.clear(state, chainId);
3784
- signature = await this.auth.getToken(state, chainId);
3785
- try {
3786
- return await request(signature);
3787
- } catch (retryError) {
3788
- if (retryError instanceof YieldseekerApiError && retryError.isAuthenticationError) {
3789
- this.forgetUser(state, chainId);
3790
- }
3791
- throw retryError;
3792
- }
3793
- }
3794
- }
3795
- mapApiError(error) {
3796
- if (!(error instanceof YieldseekerApiError)) {
3797
- return new OwneyError(
3798
- "AGENT_API_ERROR",
3799
- "Yieldseeker request failed.",
3800
- { cause: error instanceof Error ? error.message : String(error) },
3801
- this.id
3802
- );
3803
- }
3804
- const code = error.isAuthenticationError ? "AGENT_AUTH_FAILED" : error.providerCode === "REQUEST_TIMEOUT" ? "AGENT_TIMEOUT" : "AGENT_API_ERROR";
3805
- return new OwneyError(
3806
- code,
3807
- `Yieldseeker request failed: ${error.providerCode}.`,
3808
- {
3809
- statusCode: error.status,
3810
- providerCode: error.providerCode,
3811
- ...error.responseFields ? { fields: error.responseFields } : {}
3812
- },
3813
- this.id
3814
- );
3815
- }
3816
- async submitTransaction(state, chainId, transaction) {
3817
- if (this.transactionExecutor) {
3818
- return this.transactionExecutor(state, chainId, transaction);
3819
- }
3820
- this.assertTransaction(transaction, state, chainId);
3821
- const account = (0, import_viem6.getAddress)(state.walletAddress);
3822
- const walletClient = (0, import_viem6.createWalletClient)({
3823
- account,
3824
- chain: import_chains3.base,
3825
- transport: (0, import_viem6.custom)(state.provider)
3826
- });
3827
- const publicClient = (0, import_viem6.createPublicClient)({
3828
- chain: import_chains3.base,
3829
- transport: (0, import_viem6.custom)(state.provider)
3830
- });
3831
- await ensureWalletOnChain(
3832
- publicClient,
3833
- walletClient,
3834
- 8453
3835
- );
3836
- const hash = await walletClient.sendTransaction({
3837
- account,
3838
- chain: import_chains3.base,
3839
- to: (0, import_viem6.getAddress)(transaction.to),
3840
- data: transaction.data,
3841
- value: BigInt(transaction.value)
3842
- });
3843
- const receipt = await publicClient.waitForTransactionReceipt({
3844
- hash,
3845
- confirmations: 1
3846
- });
3847
- if (receipt.status !== "success") {
3848
- throw new OwneyError(
3849
- "AGENT_TRANSACTION_REVERTED",
3850
- `Yieldseeker transaction reverted (${hash}).`,
3851
- { transactionHash: hash },
3852
- this.id
3853
- );
3854
- }
3855
- return hash;
3856
- }
3857
- async waitForReceipt(state, chainId, transactionHash) {
3858
- if (this.unwindReceiptWaiter) {
3859
- await this.unwindReceiptWaiter(state, chainId, transactionHash);
3860
- return;
3861
- }
3862
- const publicClient = (0, import_viem6.createPublicClient)({
3863
- chain: import_chains3.base,
3864
- transport: (0, import_viem6.custom)(state.provider)
3865
- });
3866
- const receipt = await publicClient.waitForTransactionReceipt({
3867
- hash: transactionHash,
3868
- confirmations: 1
3869
- });
3870
- if (receipt.status !== "success") {
3871
- throw new OwneyError(
3872
- "AGENT_TRANSACTION_REVERTED",
3873
- `Yieldseeker transaction reverted (${transactionHash}).`,
3874
- { transactionHash },
3875
- this.id
3876
- );
3877
- }
3878
- }
3879
- assertTransaction(transaction, state, chainId) {
3880
- if (!transaction || typeof transaction.from !== "string" || !(0, import_viem6.isAddress)(transaction.from) || typeof transaction.to !== "string" || !(0, import_viem6.isAddress)(transaction.to) || typeof transaction.data !== "string" || !/^0x[a-fA-F0-9]*$/.test(transaction.data) || typeof transaction.value !== "string" || !/^[0-9]+$/.test(transaction.value) || transaction.chainId !== chainId || (0, import_viem6.getAddress)(transaction.from) !== (0, import_viem6.getAddress)(state.walletAddress)) {
3881
- throw this.invalidResponse("transaction");
3882
- }
3883
- }
3884
- assertAgent(agent) {
3885
- if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem6.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
3886
- throw this.invalidResponse("agent");
3887
- }
3888
- }
3889
- isOwneyAgent(agent) {
3890
- return typeof agent.name === "string" && agent.name.trim().toLowerCase() === OWNEY_AGENT_NAME;
3891
- }
3892
- assetForAgent(agent) {
3893
- for (const asset of ["USDC", "WETH"]) {
3894
- if (agent.assetAddress.toLowerCase() === YIELDSEEKER_ASSET_METADATA[asset].address.toLowerCase()) {
3895
- return asset;
3896
- }
3897
- }
3898
- return null;
3899
- }
3900
- isTransactionHash(value) {
3901
- return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
3902
- }
3903
- assertChain(chainId) {
3904
- if (chainId !== 8453) {
3905
- throw new OwneyError(
3906
- "CHAIN_UNSUPPORTED",
3907
- `Yieldseeker does not support chain ${chainId}.`,
3908
- { chainId, supportedChainIds: [8453] },
3909
- this.id
3910
- );
3911
- }
3912
- }
3913
- assertOptionalChain(chainId) {
3914
- if (chainId !== void 0) this.assertChain(chainId);
3915
- }
3916
- assertAsset(asset) {
3917
- if (asset !== "USDC" && asset !== "WETH") {
3918
- throw new OwneyError(
3919
- "ASSET_UNSUPPORTED",
3920
- `Yieldseeker does not support asset ${asset} in the Owney rollout.`,
3921
- {
3922
- asset,
3923
- supportedAssets: ["USDC", "WETH"],
3924
- providerAlsoAdvertises: ["cbBTC"]
3925
- },
3926
- this.id
3927
- );
3928
- }
3929
- }
3930
- invalidResponse(operation, details = {}) {
3931
- return new OwneyError(
3932
- "AGENT_INVALID_RESPONSE",
3933
- `Yieldseeker returned an invalid ${operation} response.`,
3934
- details,
3935
- this.id
3936
- );
3937
- }
3938
- };
3939
-
3940
- // src/lib/routing-api.ts
3941
- var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
3942
- async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
3943
- const url = `${baseUrl}/api/v1/agent/org-config`;
3944
- try {
3945
- const res = await fetch(url, {
3946
- method: "GET",
3947
- headers: {
3948
- "Content-Type": "application/json",
3949
- "x-owney-api-key": `${apiKey}`
3950
- }
3951
- });
3952
- if (!res.ok) {
3953
- if (res.status !== 404) {
3954
- console.warn(
3955
- `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
3956
- );
3957
- }
3958
- return null;
3959
- }
3960
- const json = await res.json();
3961
- const policy = json.success ? json.data ?? null : null;
3962
- debugLog(
3963
- "owney-sdk",
3964
- policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
3965
- policy ?? void 0
3966
- );
3967
- return policy;
3968
- } catch (error) {
3969
- console.warn(
3970
- "[owney-sdk] Could not read org agent config (non-fatal):",
3971
- error instanceof Error ? error.message : String(error)
3972
- );
3973
- return null;
3974
- }
3975
- }
3976
- async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
3977
- const url = `${baseUrl}/api/v1/agent/keys`;
3978
- const res = await fetch(url, {
3979
- method: "GET",
3980
- headers: {
3981
- "Content-Type": "application/json",
3982
- "x-owney-api-key": `${apiKey}`
3983
- }
3984
- });
3985
- if (!res.ok) {
3986
- const text = await res.text().catch(() => "");
3987
- throw new OwneyError(
3988
- "API_ROUTING_ERROR",
3989
- `Routing API error ${res.status}: ${text}`,
3990
- { statusCode: res.status, responseBody: text }
3991
- );
3992
- }
3993
- const json = await res.json();
3994
- if (!json.success) {
3995
- throw new OwneyError(
3996
- "API_ROUTING_FAILED",
3997
- `Routing API request failed: ${json.message}`,
3998
- { message: json.message }
3999
- );
4000
- }
4001
- return json.data;
4002
- }
4003
-
4004
- // src/lib/health-report.ts
4005
- var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
4006
- async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL3) {
4007
- try {
4008
- await fetch(`${baseUrl}/api/v1/agent/health-report`, {
4009
- method: "POST",
4010
- headers: {
4011
- "Content-Type": "application/json",
4012
- "x-owney-api-key": apiKey
4013
- },
4014
- body: JSON.stringify({
4015
- agent_type: agentType,
4016
- error_code: errorCode,
4017
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
4018
- })
4019
- });
4020
- } catch (err) {
4021
- console.warn(
4022
- `[owney-sdk] health-report failed for agent "${agentType}":`,
4023
- err instanceof Error ? err.message : err
4024
- );
4025
- }
4026
- }
4027
- async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
4028
- try {
4029
- return await fn();
4030
- } catch (err) {
4031
- const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
4032
- void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
4033
- throw err;
4034
- }
4035
- }
4036
-
4037
- // src/lib/helpers/withdraw-helper.ts
4038
- var import_viem7 = require("viem");
4039
- function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
4040
- const target = asset.toUpperCase();
4041
- return agents.map((agent) => {
4042
- const agentBalance = aggregated[agent.id];
4043
- const tokenBalance = agentBalance?.tokens.find(
4044
- (t) => t.chainId === chainId && t.asset.toUpperCase() === target
4045
- );
4046
- let balance = tokenBalance ? (0, import_viem7.parseUnits)(tokenBalance.amount, decimals) : 0n;
4047
- if (agent.balanceComposition === "tokens-plus-positions") {
4048
- const chainNameById = {
4049
- 1: "ETHEREUM",
4050
- 8453: "BASE",
4051
- 42161: "ARBITRUM"
4052
- };
4053
- const targetChain = chainNameById[chainId];
4054
- for (const position2 of agentBalance?.positions ?? []) {
4055
- const positionChain = position2.chain.trim().toUpperCase();
4056
- const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
4057
- if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
4058
- if (position2.amountRaw !== void 0) {
4059
- try {
4060
- balance += BigInt(position2.amountRaw);
4061
- continue;
4062
- } catch {
4063
- }
4064
- }
4065
- balance += (0, import_viem7.parseUnits)(position2.amount, decimals);
4066
- }
4067
- }
4068
- return { agent, balance };
4069
- });
4070
- }
4071
- function planProportionalShares(balances, requested, totalAvailable) {
4072
- const plans = balances.map(({ agent, balance }) => ({
4073
- agent,
4074
- balance,
4075
- planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
4076
- }));
4077
- const assigned = plans.reduce((s, p) => s + p.planned, 0n);
4078
- let remainder = requested - assigned;
4079
- const byHeadroom = [...plans].sort((a, b) => {
4080
- const diff = b.balance - b.planned - (a.balance - a.planned);
4081
- return diff > 0n ? 1 : diff < 0n ? -1 : 0;
2479
+ async function readErc20Balance(publicClient, token, owner) {
2480
+ return publicClient.readContract({
2481
+ address: token,
2482
+ abi: ERC20_ALLOWANCE_ABI,
2483
+ functionName: "balanceOf",
2484
+ args: [owner]
4082
2485
  });
4083
- for (const p of byHeadroom) {
4084
- if (remainder === 0n) break;
4085
- const headroom = p.balance - p.planned;
4086
- if (headroom <= 0n) continue;
4087
- const take = headroom < remainder ? headroom : remainder;
4088
- p.planned += take;
4089
- remainder -= take;
4090
- }
4091
- return plans;
4092
2486
  }
4093
- function planDisabledDrain(disabled, requested) {
4094
- const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
4095
- (a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
4096
- );
4097
- const plans = [];
4098
- let remaining = requested;
4099
- for (const { agent, balance } of sorted) {
4100
- if (remaining === 0n) {
4101
- plans.push({ agent, balance, planned: 0n });
4102
- continue;
4103
- }
4104
- const take = balance < remaining ? balance : remaining;
4105
- plans.push({ agent, balance, planned: take });
4106
- remaining -= take;
4107
- }
4108
- return { plans, remaining };
2487
+
2488
+ // src/lib/chain-guard.ts
2489
+ var CHAIN_NAMES = {
2490
+ 1: "Ethereum",
2491
+ 8453: "Base",
2492
+ 42161: "Arbitrum"
2493
+ };
2494
+ function chainName(chainId) {
2495
+ return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
4109
2496
  }
4110
- function redistributeShare(plans, fromIndex, amount, candidatePool) {
4111
- const pool = candidatePool ?? plans.slice(fromIndex + 1);
4112
- const candidates = pool.filter((c) => c.balance - c.planned > 0n);
4113
- const totalHeadroom = candidates.reduce(
4114
- (s, c) => s + (c.balance - c.planned),
4115
- 0n
4116
- );
4117
- if (totalHeadroom === 0n) return;
4118
- let distributed = 0n;
4119
- for (const c of candidates) {
4120
- const headroom = c.balance - c.planned;
4121
- const proportional = headroom * amount / totalHeadroom;
4122
- const give = proportional > headroom ? headroom : proportional;
4123
- c.planned += give;
4124
- distributed += give;
2497
+ async function ensureWalletOnChain(pub, wallet, expected) {
2498
+ const actual = await pub.getChainId();
2499
+ if (actual === expected) return;
2500
+ try {
2501
+ await wallet.switchChain({ id: expected });
2502
+ } catch (error) {
2503
+ throw new OwneyError(
2504
+ "CHAIN_MISMATCH",
2505
+ `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2506
+ {
2507
+ expectedChainId: expected,
2508
+ actualChainId: actual,
2509
+ cause: error instanceof Error ? error.message : String(error)
2510
+ }
2511
+ );
4125
2512
  }
4126
- let leftover = amount - distributed;
4127
- for (const c of candidates) {
4128
- if (leftover === 0n) break;
4129
- const headroom = c.balance - c.planned;
4130
- if (headroom <= 0n) continue;
4131
- const take = headroom < leftover ? headroom : leftover;
4132
- c.planned += take;
4133
- leftover -= take;
2513
+ const after = await pub.getChainId();
2514
+ if (after !== expected) {
2515
+ throw new OwneyError(
2516
+ "CHAIN_MISMATCH",
2517
+ `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2518
+ { expectedChainId: expected, actualChainId: after }
2519
+ );
4134
2520
  }
4135
2521
  }
4136
- function sumWithdrawnAmount(results) {
4137
- return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
4138
- }
4139
2522
 
4140
- // src/lib/helpers/account-apy-helper.ts
4141
- function balanceForApyScope(balance, chainId, tokenSymbol) {
4142
- if (!tokenSymbol) {
4143
- const total = Number(balance.totalBalance);
4144
- return Number.isFinite(total) && total > 0 ? total : 0;
4145
- }
4146
- const normalizedToken = tokenSymbol.toUpperCase();
4147
- return balance.tokens.reduce((total, token) => {
4148
- if (Number(token.chainId) !== chainId || String(token.asset).toUpperCase() !== normalizedToken) {
4149
- return total;
4150
- }
4151
- const amount = Number(token.amount);
4152
- return Number.isFinite(amount) && amount > 0 ? total + amount : total;
4153
- }, 0);
4154
- }
4155
- function aggregateApyHistory(agentApys, agentBalances) {
4156
- const byDate = /* @__PURE__ */ new Map();
4157
- for (const [id, accountApy] of Object.entries(agentApys)) {
4158
- const balance = agentBalances[id] ?? 0;
4159
- if (!Number.isFinite(balance) || balance <= 0) continue;
4160
- for (const point of accountApy.history ?? []) {
4161
- const apy = Number(point.apy);
4162
- if (!point.date || !Number.isFinite(apy)) continue;
4163
- const current = byDate.get(point.date) ?? { weightedSum: 0, weight: 0 };
4164
- current.weightedSum += apy * balance;
4165
- current.weight += balance;
4166
- byDate.set(point.date, current);
2523
+ // src/lib/sponsored-deposit.ts
2524
+ var AUTH_WINDOW_SECONDS = 15 * 60;
2525
+ function makeSponsoredDepositCallback(deps) {
2526
+ const post = deps.httpPost ?? postSponsorTransferAuth;
2527
+ return async (smartWallet, chainId, amount) => {
2528
+ const cid = chainId;
2529
+ const token = deps.tokenAddressByChain[cid];
2530
+ if (!token) {
2531
+ throw new OwneyError(
2532
+ "CHAIN_UNSUPPORTED",
2533
+ `No sponsored token configured for chain ${chainId}`
2534
+ );
4167
2535
  }
4168
- }
4169
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
4170
- date,
4171
- apy: value.weightedSum / value.weight
4172
- }));
4173
- }
4174
- function aggregateApyByChainAndAsset(agentApys, agentBalances) {
4175
- const sums = {};
4176
- const weights = {};
4177
- for (const id of Object.keys(agentApys)) {
4178
- const cells = agentApys[id].apyByChainAndAsset;
4179
- const balance = agentBalances[id] ?? 0;
4180
- if (!cells || balance <= 0) continue;
4181
- for (const [chainKey, perAsset] of Object.entries(cells)) {
4182
- if (!perAsset) continue;
4183
- const chainId = Number(chainKey);
4184
- for (const [asset, apyValue] of Object.entries(perAsset)) {
4185
- const apy = Number(apyValue ?? 0);
4186
- if (apy === 0) continue;
4187
- sums[chainId] ??= {};
4188
- weights[chainId] ??= {};
4189
- sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
4190
- weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2536
+ const pub = deps.getPublicClient(cid);
2537
+ const wallet = deps.getWalletClient(cid);
2538
+ await ensureWalletOnChain(pub, wallet, cid);
2539
+ try {
2540
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2541
+ if (balance < BigInt(amount)) {
2542
+ throw new OwneyError(
2543
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2544
+ "Insufficient balance for this deposit.",
2545
+ { token, chainId: cid, balance: balance.toString(), amount }
2546
+ );
4191
2547
  }
2548
+ } catch (err) {
2549
+ if (err instanceof OwneyError) throw err;
2550
+ console.warn(
2551
+ "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2552
+ err instanceof Error ? err.message : String(err)
2553
+ );
4192
2554
  }
4193
- }
4194
- const out = {};
4195
- for (const chainKey of Object.keys(sums)) {
4196
- const chainId = Number(chainKey);
4197
- const perAssetOut = {};
4198
- for (const asset of Object.keys(sums[chainId])) {
4199
- const w = weights[chainId][asset];
4200
- if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
4201
- }
4202
- if (Object.keys(perAssetOut).length > 0) {
4203
- out[chainId] = perAssetOut;
4204
- }
4205
- }
4206
- return out;
2555
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2556
+ const validAfter = 0n;
2557
+ const validBefore = BigInt(
2558
+ Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2559
+ );
2560
+ const nonce = randomAuthNonce();
2561
+ const typedData = buildTransferWithAuthorizationTypedData({
2562
+ token,
2563
+ chainId: cid,
2564
+ tokenName,
2565
+ tokenVersion,
2566
+ message: {
2567
+ from: deps.ownerAddress,
2568
+ to: smartWallet,
2569
+ value: BigInt(amount),
2570
+ validAfter,
2571
+ validBefore,
2572
+ nonce
2573
+ }
2574
+ });
2575
+ const authSignature = await wallet.signTypedData({
2576
+ account: deps.ownerAddress,
2577
+ ...typedData
2578
+ });
2579
+ deps.onApproved?.();
2580
+ const result = await post({
2581
+ baseUrl: deps.baseUrl,
2582
+ apiKey: deps.apiKey,
2583
+ body: {
2584
+ chainId: cid,
2585
+ token,
2586
+ from: deps.ownerAddress,
2587
+ to: smartWallet,
2588
+ value: amount,
2589
+ validAfter: validAfter.toString(),
2590
+ validBefore: validBefore.toString(),
2591
+ nonce,
2592
+ authSignature,
2593
+ tokenName,
2594
+ tokenVersion
2595
+ }
2596
+ });
2597
+ return result.txHash;
2598
+ };
4207
2599
  }
4208
2600
 
4209
- // src/client.ts
4210
- var import_viem9 = require("viem");
4211
- var import_chains4 = require("viem/chains");
4212
-
4213
2601
  // src/lib/sponsored-weth-deposit.ts
4214
2602
  var PERMIT_WINDOW_SECONDS = 15 * 60;
4215
2603
  function makeSponsoredWethCallback(deps) {
4216
2604
  const get = deps.httpGet ?? getSponsorRelayerAddress;
4217
2605
  const post = deps.httpPost ?? postSponsorPermit2Transfer;
4218
- return makeVerificationAwareDepositCallback(
4219
- async (smartWallet, chainId, amount, verification) => {
4220
- const cid = chainId;
4221
- const token = deps.tokenAddressByChain[cid];
4222
- if (!token) {
4223
- throw new OwneyError(
4224
- "CHAIN_UNSUPPORTED",
4225
- `No sponsored WETH configured for chain ${chainId}`
4226
- );
4227
- }
4228
- const amountWei = BigInt(amount);
4229
- const pub = deps.getPublicClient(cid);
4230
- const wallet = deps.getWalletClient(cid);
4231
- await ensureWalletOnChain(pub, wallet, cid);
4232
- try {
4233
- const balance = await readErc20Balance(pub, token, deps.ownerAddress);
4234
- if (balance < amountWei) {
4235
- throw new OwneyError(
4236
- "DEPOSIT_INSUFFICIENT_BALANCE",
4237
- "Insufficient WETH balance for this deposit.",
4238
- { token, chainId: cid, balance: balance.toString(), amount }
4239
- );
4240
- }
4241
- } catch (err) {
4242
- if (err instanceof OwneyError) throw err;
4243
- console.warn(
4244
- "[owney-sdk] WETH balance pre-check failed (non-fatal):",
4245
- err instanceof Error ? err.message : String(err)
4246
- );
4247
- }
4248
- const allowance = await readPermit2Allowance(
4249
- pub,
4250
- token,
4251
- deps.ownerAddress
2606
+ return async (smartWallet, chainId, amount) => {
2607
+ const cid = chainId;
2608
+ const token = deps.tokenAddressByChain[cid];
2609
+ if (!token) {
2610
+ throw new OwneyError(
2611
+ "CHAIN_UNSUPPORTED",
2612
+ `No sponsored WETH configured for chain ${chainId}`
4252
2613
  );
4253
- if (allowance < amountWei) {
2614
+ }
2615
+ const amountWei = BigInt(amount);
2616
+ const pub = deps.getPublicClient(cid);
2617
+ const wallet = deps.getWalletClient(cid);
2618
+ await ensureWalletOnChain(pub, wallet, cid);
2619
+ try {
2620
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2621
+ if (balance < amountWei) {
4254
2622
  throw new OwneyError(
4255
- "PERMIT2_APPROVAL_REQUIRED",
4256
- "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
4257
- { token, chainId: cid, allowance: allowance.toString(), amount }
2623
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2624
+ "Insufficient WETH balance for this deposit.",
2625
+ { token, chainId: cid, balance: balance.toString(), amount }
4258
2626
  );
4259
2627
  }
4260
- const relayer = await get({
4261
- baseUrl: deps.baseUrl,
4262
- apiKey: deps.apiKey,
4263
- chainId: cid
4264
- });
4265
- const nonce = randomPermit2Nonce();
4266
- const deadline = BigInt(
4267
- Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2628
+ } catch (err) {
2629
+ if (err instanceof OwneyError) throw err;
2630
+ console.warn(
2631
+ "[owney-sdk] WETH balance pre-check failed (non-fatal):",
2632
+ err instanceof Error ? err.message : String(err)
4268
2633
  );
4269
- const typedData = buildPermitTransferFromTypedData({
4270
- chainId: cid,
4271
- message: {
4272
- permitted: { token, amount: amountWei },
4273
- spender: relayer,
4274
- nonce,
4275
- deadline
4276
- }
4277
- });
4278
- const signature = await wallet.signTypedData({
4279
- account: deps.ownerAddress,
4280
- ...typedData
4281
- });
4282
- deps.onApproved?.();
4283
- const result = await post({
4284
- baseUrl: deps.baseUrl,
4285
- apiKey: deps.apiKey,
4286
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
4287
- body: {
4288
- chainId: cid,
4289
- token,
4290
- from: deps.ownerAddress,
4291
- to: smartWallet,
4292
- amount,
4293
- nonce: nonce.toString(),
4294
- deadline: deadline.toString(),
4295
- signature,
4296
- ...verification?.agentId === "yieldseeker" ? {
4297
- yieldseekerUserId: verification.userId,
4298
- yieldseekerAgentId: verification.yieldseekerAgentId
4299
- } : {}
4300
- }
4301
- });
4302
- return result.txHash;
4303
2634
  }
4304
- );
2635
+ const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
2636
+ if (allowance < amountWei) {
2637
+ throw new OwneyError(
2638
+ "PERMIT2_APPROVAL_REQUIRED",
2639
+ "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
2640
+ { token, chainId: cid, allowance: allowance.toString(), amount }
2641
+ );
2642
+ }
2643
+ const relayer = await get({
2644
+ baseUrl: deps.baseUrl,
2645
+ apiKey: deps.apiKey,
2646
+ chainId: cid
2647
+ });
2648
+ const nonce = randomPermit2Nonce();
2649
+ const deadline = BigInt(
2650
+ Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2651
+ );
2652
+ const typedData = buildPermitTransferFromTypedData({
2653
+ chainId: cid,
2654
+ message: {
2655
+ permitted: { token, amount: amountWei },
2656
+ spender: relayer,
2657
+ nonce,
2658
+ deadline
2659
+ }
2660
+ });
2661
+ const signature = await wallet.signTypedData({
2662
+ account: deps.ownerAddress,
2663
+ ...typedData
2664
+ });
2665
+ deps.onApproved?.();
2666
+ const result = await post({
2667
+ baseUrl: deps.baseUrl,
2668
+ apiKey: deps.apiKey,
2669
+ body: {
2670
+ chainId: cid,
2671
+ token,
2672
+ from: deps.ownerAddress,
2673
+ to: smartWallet,
2674
+ amount,
2675
+ nonce: nonce.toString(),
2676
+ deadline: deadline.toString(),
2677
+ signature
2678
+ }
2679
+ });
2680
+ return result.txHash;
2681
+ };
4305
2682
  }
4306
2683
 
4307
2684
  // src/lib/sponsored-calls-deposit.ts
4308
- var import_viem8 = require("viem");
2685
+ var import_viem5 = require("viem");
4309
2686
  var DEFAULT_POLL_INTERVAL_MS = 1500;
4310
2687
  var DEFAULT_MAX_POLLS = 30;
4311
2688
  async function paymasterSupported(provider, owner, chainId) {
@@ -4313,7 +2690,7 @@ async function paymasterSupported(provider, owner, chainId) {
4313
2690
  method: "wallet_getCapabilities",
4314
2691
  params: [owner]
4315
2692
  });
4316
- const forChain = caps?.[(0, import_viem8.toHex)(chainId)] ?? caps?.[String(chainId)];
2693
+ const forChain = caps?.[(0, import_viem5.toHex)(chainId)] ?? caps?.[String(chainId)];
4317
2694
  return Boolean(forChain?.paymasterService?.supported);
4318
2695
  }
4319
2696
  function makeSponsoredCallsCallback(deps) {
@@ -4331,7 +2708,7 @@ function makeSponsoredCallsCallback(deps) {
4331
2708
  }
4332
2709
  return new URL(configured, origin).toString();
4333
2710
  };
4334
- return makeVerificationAwareDepositCallback(async (smartWallet, chainId, amount, verification) => {
2711
+ return async (smartWallet, chainId, amount) => {
4335
2712
  const cid = chainId;
4336
2713
  const token = deps.tokenAddressByChain[cid];
4337
2714
  if (!token) {
@@ -4347,48 +2724,22 @@ function makeSponsoredCallsCallback(deps) {
4347
2724
  { chainId }
4348
2725
  );
4349
2726
  }
4350
- const data = (0, import_viem8.encodeFunctionData)({
4351
- abi: import_viem8.erc20Abi,
2727
+ const data = (0, import_viem5.encodeFunctionData)({
2728
+ abi: import_viem5.erc20Abi,
4352
2729
  functionName: "transfer",
4353
2730
  args: [smartWallet, BigInt(amount)]
4354
2731
  });
4355
- let paymasterUrl = absolutePaymasterUrl();
4356
- if (verification?.agentId === "yieldseeker") {
4357
- if (chainId !== 8453) {
4358
- throw new OwneyError(
4359
- "CHAIN_UNSUPPORTED",
4360
- `Yieldseeker Base Account sponsorship is not available on chain ${chainId}.`
4361
- );
4362
- }
4363
- const { intent } = await postPaymasterIntent({
4364
- baseUrl: deps.routingApiBaseUrl,
4365
- apiKey: deps.apiKey,
4366
- yieldseekerSignature: verification.signature,
4367
- body: {
4368
- chainId,
4369
- token,
4370
- from: deps.ownerAddress,
4371
- to: smartWallet,
4372
- amount,
4373
- yieldseekerUserId: verification.userId,
4374
- yieldseekerAgentId: verification.yieldseekerAgentId
4375
- }
4376
- });
4377
- const url = new URL(paymasterUrl);
4378
- url.searchParams.set("owneyIntent", intent);
4379
- paymasterUrl = url.toString();
4380
- }
4381
2732
  const sendResult = await deps.provider.request({
4382
2733
  method: "wallet_sendCalls",
4383
2734
  params: [
4384
2735
  {
4385
2736
  version: "2.0.0",
4386
2737
  from: deps.ownerAddress,
4387
- chainId: (0, import_viem8.toHex)(chainId),
2738
+ chainId: (0, import_viem5.toHex)(chainId),
4388
2739
  atomicRequired: false,
4389
2740
  calls: [{ to: token, value: "0x0", data }],
4390
2741
  capabilities: {
4391
- paymasterService: { url: paymasterUrl }
2742
+ paymasterService: { url: absolutePaymasterUrl() }
4392
2743
  }
4393
2744
  }
4394
2745
  ]
@@ -4418,7 +2769,7 @@ function makeSponsoredCallsCallback(deps) {
4418
2769
  `No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
4419
2770
  { chainId, callsId }
4420
2771
  );
4421
- });
2772
+ };
4422
2773
  }
4423
2774
 
4424
2775
  // src/client.ts
@@ -4448,9 +2799,9 @@ var SPONSORED_USDC_BY_CHAIN = {
4448
2799
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
4449
2800
  };
4450
2801
  var VIEM_CHAIN2 = {
4451
- 8453: import_chains4.base,
4452
- 42161: import_chains4.arbitrum,
4453
- 1: import_chains4.mainnet
2802
+ 8453: import_chains2.base,
2803
+ 42161: import_chains2.arbitrum,
2804
+ 1: import_chains2.mainnet
4454
2805
  };
4455
2806
  var SPONSORED_WETH_BY_CHAIN = {
4456
2807
  8453: "0x4200000000000000000000000000000000000006",
@@ -4478,8 +2829,6 @@ var OwneySDK = class {
4478
2829
  orgAgentConfig;
4479
2830
  orgAgentConfigPromise = null;
4480
2831
  zyfaiRpcUrls;
4481
- yieldseekerApiBaseUrl;
4482
- yieldseekerSiweOrigin;
4483
2832
  routingApiBaseUrl;
4484
2833
  referralSource;
4485
2834
  cachedSponsoredCallback = null;
@@ -4502,8 +2851,6 @@ var OwneySDK = class {
4502
2851
  this.apiKey = config.apiKey;
4503
2852
  if (config.debug) setOwneyDebug(true);
4504
2853
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
4505
- this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
4506
- this.yieldseekerSiweOrigin = config.yieldseekerSiweOrigin;
4507
2854
  this.routingApiBaseUrl = config.routingApiBaseUrl;
4508
2855
  this.paymasterServiceUrl = config.paymasterServiceUrl;
4509
2856
  this.referralSource = config.referralSource;
@@ -4610,14 +2957,14 @@ var OwneySDK = class {
4610
2957
  // Casts work around viem's chain-narrowed Client vs the generic
4611
2958
  // PublicClient/WalletClient param types — structurally identical at
4612
2959
  // runtime, but the two share a name TS treats as unrelated.
4613
- getPublicClient: (cid) => (0, import_viem9.createPublicClient)({
2960
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
4614
2961
  chain: VIEM_CHAIN2[cid],
4615
- transport: (0, import_viem9.custom)(provider)
2962
+ transport: (0, import_viem6.custom)(provider)
4616
2963
  }),
4617
- getWalletClient: (cid) => (0, import_viem9.createWalletClient)({
2964
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
4618
2965
  account: owner,
4619
2966
  chain: VIEM_CHAIN2[cid],
4620
- transport: (0, import_viem9.custom)(provider)
2967
+ transport: (0, import_viem6.custom)(provider)
4621
2968
  })
4622
2969
  });
4623
2970
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -4634,8 +2981,6 @@ var OwneySDK = class {
4634
2981
  if (!onApproved && cached) return cached;
4635
2982
  const provider = this.requireConnectedProvider();
4636
2983
  const callback = makeSponsoredCallsCallback({
4637
- apiKey: this.apiKey,
4638
- routingApiBaseUrl: this.routingApiBaseUrl,
4639
2984
  provider,
4640
2985
  ownerAddress: this.state.walletAddress,
4641
2986
  paymasterServiceUrl: this.paymasterServiceUrl,
@@ -4665,14 +3010,14 @@ var OwneySDK = class {
4665
3010
  // Casts work around viem's chain-narrowed Client vs the generic
4666
3011
  // PublicClient/WalletClient param types — structurally identical at
4667
3012
  // runtime, but the two share a name TS treats as unrelated.
4668
- getPublicClient: (cid) => (0, import_viem9.createPublicClient)({
3013
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
4669
3014
  chain: VIEM_CHAIN2[cid],
4670
- transport: (0, import_viem9.custom)(provider)
3015
+ transport: (0, import_viem6.custom)(provider)
4671
3016
  }),
4672
- getWalletClient: (cid) => (0, import_viem9.createWalletClient)({
3017
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
4673
3018
  account: owner,
4674
3019
  chain: VIEM_CHAIN2[cid],
4675
- transport: (0, import_viem9.custom)(provider)
3020
+ transport: (0, import_viem6.custom)(provider)
4676
3021
  })
4677
3022
  });
4678
3023
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -4703,10 +3048,12 @@ var OwneySDK = class {
4703
3048
  this.orgAgentConfigPromise = fetchOrgAgentConfig(
4704
3049
  this.apiKey,
4705
3050
  this.routingApiBaseUrl
4706
- ).then((config) => {
4707
- this.orgAgentConfig = config;
4708
- return config;
4709
- });
3051
+ ).then(
3052
+ (config) => {
3053
+ this.orgAgentConfig = config;
3054
+ return config;
3055
+ }
3056
+ );
4710
3057
  }
4711
3058
  return this.orgAgentConfigPromise;
4712
3059
  }
@@ -4746,14 +3093,7 @@ var OwneySDK = class {
4746
3093
  this.routingApiBaseUrl
4747
3094
  );
4748
3095
  this.disabledAgents.clear();
4749
- for (const {
4750
- key: key2,
4751
- agent_type,
4752
- is_enabled,
4753
- is_configured
4754
- } of agentKeys) {
4755
- const configured = is_configured ?? Boolean(key2);
4756
- if (!configured) continue;
3096
+ for (const { key: key2, agent_type, is_enabled } of agentKeys) {
4757
3097
  const agent = this.createAgent(agent_type, key2);
4758
3098
  if (!agent) continue;
4759
3099
  this.agents.set(agent_type, agent);
@@ -4777,15 +3117,8 @@ var OwneySDK = class {
4777
3117
  }
4778
3118
  createAgent(agentId, key2) {
4779
3119
  if (agentId === "zyfai") {
4780
- if (!key2) return null;
4781
3120
  return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
4782
3121
  }
4783
- if (agentId === "yieldseeker") {
4784
- return new YieldseekerAgent(this.apiKey, {
4785
- auth: { origin: this.yieldseekerSiweOrigin },
4786
- baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl)
4787
- });
4788
- }
4789
3122
  return null;
4790
3123
  }
4791
3124
  /**
@@ -4830,7 +3163,7 @@ var OwneySDK = class {
4830
3163
  * If provided, ALL specified agents must support the chainId or the call
4831
3164
  * throws before activating any agent.
4832
3165
  */
4833
- async activateAgent(chainId, agentId, asset) {
3166
+ async activateAgent(chainId, agentId) {
4834
3167
  const state = this.requireState();
4835
3168
  await this.ensureAgentsInitialized();
4836
3169
  if (agentId !== void 0) {
@@ -4866,7 +3199,7 @@ var OwneySDK = class {
4866
3199
  this.activeAgents.add(id);
4867
3200
  }
4868
3201
  state.chainId = chainId;
4869
- await this.activateAgentsInTurn(agents, state, chainId, asset);
3202
+ await this.activateAgentsInTurn(agents, state, chainId);
4870
3203
  return;
4871
3204
  }
4872
3205
  const compatible = [...this.agents.values()].filter(
@@ -4887,7 +3220,7 @@ var OwneySDK = class {
4887
3220
  const enabledCompatible = compatible.filter(
4888
3221
  (agent) => !this.isAgentDisabled(agent.id)
4889
3222
  );
4890
- await this.activateAgentsInTurn(enabledCompatible, state, chainId, asset);
3223
+ await this.activateAgentsInTurn(enabledCompatible, state, chainId);
4891
3224
  }
4892
3225
  /**
4893
3226
  * Activate agents ONE AT A TIME, each followed by its org policy.
@@ -4903,25 +3236,17 @@ var OwneySDK = class {
4903
3236
  * at a time anyway.
4904
3237
  *
4905
3238
  * Every agent is attempted even if an earlier one fails, so one declined
4906
- * signature can't deny the remaining agents their turn. Once all agents have
4907
- * had a chance, a partial failure identifies the agents that still need a
4908
- * retry; if none activated, the original provider error is preserved.
3239
+ * signature can't deny the remaining agents their turn. The first failure is
3240
+ * rethrown (matching the previous `Promise.all` rejection) once all agents
3241
+ * have had a chance to activate.
4909
3242
  */
4910
- async activateAgentsInTurn(agents, state, chainId, asset) {
3243
+ async activateAgentsInTurn(agents, state, chainId) {
4911
3244
  let firstError = null;
4912
- const activatedAgentIds = [];
4913
- const failedAgents = [];
4914
3245
  for (const agent of agents) {
4915
3246
  try {
4916
- await agent.activateAgent(state, chainId, asset);
3247
+ await agent.activateAgent(state, chainId);
4917
3248
  await this.applyOrgPolicyTo(agent, state, chainId);
4918
- activatedAgentIds.push(agent.id);
4919
3249
  } catch (error) {
4920
- failedAgents.push({
4921
- agentId: agent.id,
4922
- code: error instanceof OwneyError ? error.code : void 0,
4923
- message: error instanceof Error ? error.message : String(error)
4924
- });
4925
3250
  if (firstError === null) {
4926
3251
  firstError = error;
4927
3252
  } else {
@@ -4929,16 +3254,7 @@ var OwneySDK = class {
4929
3254
  }
4930
3255
  }
4931
3256
  }
4932
- if (firstError === null) return;
4933
- if (activatedAgentIds.length === 0) throw firstError;
4934
- const failedAgentIds = failedAgents.map(({ agentId }) => agentId);
4935
- const activeNames = activatedAgentIds.map(this.formatAgentName).join(", ");
4936
- const remainingNames = failedAgentIds.map(this.formatAgentName).join(", ");
4937
- throw new OwneyError(
4938
- "AGENT_ACTIVATION_PARTIAL_FAILURE",
4939
- `${activeNames} activated, but ${remainingNames} still needs activation. Try again and approve the remaining wallet request.`,
4940
- { activatedAgentIds, failedAgentIds, failures: failedAgents }
4941
- );
3257
+ if (firstError !== null) throw firstError;
4942
3258
  }
4943
3259
  /**
4944
3260
  * Deposit into a specific agent, or distribute across all eligible agents.
@@ -5152,10 +3468,10 @@ var OwneySDK = class {
5152
3468
  agent,
5153
3469
  amount: i === agents.length - 1 ? perAgent + remainder : perAgent
5154
3470
  }));
5155
- const valid2 = splits.filter(
3471
+ const valid = splits.filter(
5156
3472
  (s) => s.amount > 0n && (exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset))
5157
3473
  );
5158
- if (valid2.length === agents.length) {
3474
+ if (valid.length === agents.length) {
5159
3475
  return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
5160
3476
  }
5161
3477
  const targets = agentsRequiringActivation.length > 0 ? agentsRequiringActivation : agents;
@@ -5174,11 +3490,6 @@ var OwneySDK = class {
5174
3490
  )
5175
3491
  }));
5176
3492
  }
5177
- formatAgentName(agentId) {
5178
- if (agentId === "zyfai") return "Zyfai";
5179
- if (agentId === "yieldseeker") return "Yieldseeker";
5180
- return agentId;
5181
- }
5182
3493
  async validateMinDepositAmount(agent, state, chainId, asset, amount) {
5183
3494
  const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
5184
3495
  const parsedAmount = BigInt(amount);
@@ -5210,12 +3521,12 @@ var OwneySDK = class {
5210
3521
  (t) => t.chainId === chainId && t.asset.toLowerCase() === target
5211
3522
  );
5212
3523
  const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
5213
- const position2 = (balance.positions ?? []).find((p) => {
3524
+ const position = (balance.positions ?? []).find((p) => {
5214
3525
  const positionChain = p.chain.trim().toUpperCase();
5215
3526
  const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
5216
3527
  return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
5217
3528
  });
5218
- return !!token && Number(token.amount) > 0 || !!position2;
3529
+ return !!token && Number(token.amount) > 0 || !!position;
5219
3530
  } catch (error) {
5220
3531
  if (requireReliableRead) {
5221
3532
  throw new OwneyError(
@@ -5330,10 +3641,6 @@ var OwneySDK = class {
5330
3641
  }
5331
3642
  const requested = BigInt(amount);
5332
3643
  const aggregated = await this.getBalances();
5333
- const unavailableAgents = eligibleAgents.filter(
5334
- (agent) => !(agent.id in aggregated.agentBalances)
5335
- );
5336
- const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
5337
3644
  const balances = projectAgentBalancesForAsset(
5338
3645
  eligibleAgents,
5339
3646
  aggregated.agentBalances,
@@ -5342,18 +3649,7 @@ var OwneySDK = class {
5342
3649
  assetInfo.decimals
5343
3650
  );
5344
3651
  const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
5345
- if (totalAvailable === 0n && unavailableAgents.length > 0) {
5346
- throw new OwneyError(
5347
- "WITHDRAW_BALANCE_UNAVAILABLE",
5348
- `Cannot safely plan the withdrawal because balance data is unavailable for: ${unavailableAgentIds.join(", ")}.`,
5349
- {
5350
- asset,
5351
- unavailableAgents: unavailableAgentIds,
5352
- agentErrors: aggregated.agentErrors
5353
- }
5354
- );
5355
- }
5356
- if (totalAvailable < requested && unavailableAgents.length === 0) {
3652
+ if (totalAvailable < requested) {
5357
3653
  throw new OwneyError(
5358
3654
  "WITHDRAW_INSUFFICIENT_BALANCE",
5359
3655
  `Requested withdrawal "${amount}" exceeds available balance "${totalAvailable.toString()}" for asset "${asset}".`,
@@ -5364,7 +3660,6 @@ var OwneySDK = class {
5364
3660
  }
5365
3661
  );
5366
3662
  }
5367
- const plannedTarget = totalAvailable < requested ? totalAvailable : requested;
5368
3663
  const disabledBalances = balances.filter(
5369
3664
  (b) => this.isAgentDisabled(b.agent.id)
5370
3665
  );
@@ -5373,7 +3668,7 @@ var OwneySDK = class {
5373
3668
  );
5374
3669
  const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
5375
3670
  disabledBalances,
5376
- plannedTarget
3671
+ requested
5377
3672
  );
5378
3673
  const enabledTotal = enabledBalances.reduce((s, b) => s + b.balance, 0n);
5379
3674
  const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
@@ -5383,9 +3678,7 @@ var OwneySDK = class {
5383
3678
  }));
5384
3679
  const plans = [...disabledPlans, ...enabledPlans];
5385
3680
  const results = {};
5386
- const agentErrors = {
5387
- ...aggregated.agentErrors ?? {}
5388
- };
3681
+ const agentErrors = {};
5389
3682
  for (let i = 0; i < plans.length; i++) {
5390
3683
  const p = plans[i];
5391
3684
  if (p.planned === 0n) continue;
@@ -5432,8 +3725,7 @@ var OwneySDK = class {
5432
3725
  requested: amount,
5433
3726
  withdrawn: withdrawn.toString(),
5434
3727
  partialResults: results,
5435
- agentErrors,
5436
- ...unavailableAgentIds.length > 0 ? { unavailableAgents: unavailableAgentIds } : {}
3728
+ agentErrors
5437
3729
  }
5438
3730
  );
5439
3731
  }
@@ -5451,10 +3743,7 @@ var OwneySDK = class {
5451
3743
  if (agentId) {
5452
3744
  const agent = this.getAgent(agentId);
5453
3745
  const result = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
5454
- return {
5455
- ...result,
5456
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
5457
- };
3746
+ return result;
5458
3747
  }
5459
3748
  let totalBalance = 0;
5460
3749
  const results = {};
@@ -5462,13 +3751,7 @@ var OwneySDK = class {
5462
3751
  const balanceResults = await Promise.allSettled(
5463
3752
  entries.map(async ([id, agent]) => {
5464
3753
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
5465
- return [
5466
- id,
5467
- {
5468
- ...b,
5469
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
5470
- }
5471
- ];
3754
+ return [id, b];
5472
3755
  })
5473
3756
  );
5474
3757
  let successCount = 0;
@@ -5490,7 +3773,6 @@ var OwneySDK = class {
5490
3773
  const retryDelay = rateLimitDelay(reason);
5491
3774
  if (retryDelay !== void 0) agentRetryAt[agentId2] = Date.now() + retryDelay;
5492
3775
  agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
5493
- console.error(`[owney-sdk] Balance fetch failed for agent "${agentId2}":`, reason);
5494
3776
  }
5495
3777
  if (successCount === 0) {
5496
3778
  throw new OwneyError(
@@ -5603,10 +3885,7 @@ var OwneySDK = class {
5603
3885
  Promise.all(
5604
3886
  entries.map(async ([id, agent]) => {
5605
3887
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
5606
- return [
5607
- id,
5608
- balanceForApyScope(b, chainId, tokenSymbol)
5609
- ];
3888
+ return [id, Number(b.totalBalance)];
5610
3889
  })
5611
3890
  )
5612
3891
  ]);
@@ -5634,12 +3913,10 @@ var OwneySDK = class {
5634
3913
  }
5635
3914
  }
5636
3915
  const apyByChainAndAsset = aggregateApyByChainAndAsset(results, balances);
5637
- const history = aggregateApyHistory(results, balances);
5638
3916
  return {
5639
3917
  totalApy: String(totalApy),
5640
3918
  agentApy: results,
5641
- apyByChainAndAsset,
5642
- history
3919
+ apyByChainAndAsset
5643
3920
  };
5644
3921
  }
5645
3922
  /**
@@ -5787,10 +4064,10 @@ var OwneySDK = class {
5787
4064
  );
5788
4065
  }
5789
4066
  const provider = this.requireConnectedProvider();
5790
- const wallet = (0, import_viem9.createWalletClient)({
4067
+ const wallet = (0, import_viem6.createWalletClient)({
5791
4068
  account: state.walletAddress,
5792
4069
  chain: VIEM_CHAIN2[chainId],
5793
- transport: (0, import_viem9.custom)(provider)
4070
+ transport: (0, import_viem6.custom)(provider)
5794
4071
  });
5795
4072
  const hash = await wallet.writeContract({
5796
4073
  address: token,
@@ -5800,9 +4077,9 @@ var OwneySDK = class {
5800
4077
  account: state.walletAddress,
5801
4078
  chain: VIEM_CHAIN2[chainId]
5802
4079
  });
5803
- const publicClient = (0, import_viem9.createPublicClient)({
4080
+ const publicClient = (0, import_viem6.createPublicClient)({
5804
4081
  chain: VIEM_CHAIN2[chainId],
5805
- transport: (0, import_viem9.custom)(provider)
4082
+ transport: (0, import_viem6.custom)(provider)
5806
4083
  });
5807
4084
  const receipt = await publicClient.waitForTransactionReceipt({
5808
4085
  hash,
@@ -5839,9 +4116,7 @@ var OwneySDK = class {
5839
4116
  return this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
5840
4117
  }
5841
4118
  const results = {};
5842
- const agentEntries = [...this.agents.entries()].filter(
5843
- ([id]) => !this.isAgentDisabled(id)
5844
- );
4119
+ const agentEntries = [...this.agents.entries()];
5845
4120
  const apyResults = await Promise.all(
5846
4121
  agentEntries.map(async ([id, agent]) => {
5847
4122
  const apy = await this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
@@ -5916,13 +4191,13 @@ var OwneySDK = class {
5916
4191
  };
5917
4192
 
5918
4193
  // src/agents/zyfai/zyfai.siwx.ts
5919
- var import_viem10 = require("viem");
5920
- var import_siwe2 = require("siwe");
4194
+ var import_viem7 = require("viem");
4195
+ var import_siwe = require("siwe");
5921
4196
  var import_sdk2 = require("@zyfai/sdk");
5922
4197
 
5923
4198
  // src/agents/zyfai/zyfai.siwx-cache.ts
5924
- var KEY_PREFIX4 = "owney.siwx.session";
5925
- var storage4 = () => {
4199
+ var KEY_PREFIX2 = "owney.siwx.session";
4200
+ var storage2 = () => {
5926
4201
  if (typeof window === "undefined") return null;
5927
4202
  try {
5928
4203
  return window.localStorage;
@@ -5930,8 +4205,8 @@ var storage4 = () => {
5930
4205
  return null;
5931
4206
  }
5932
4207
  };
5933
- var buildKey3 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}`;
5934
- var legacyKeyPrefix2 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}:`;
4208
+ var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
4209
+ var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
5935
4210
  var memorySiwxSessions = /* @__PURE__ */ new Map();
5936
4211
  var readLegacySiwxSession = (store, address) => {
5937
4212
  if (!store) return null;
@@ -5962,17 +4237,17 @@ var readLegacySiwxSession = (store, address) => {
5962
4237
  };
5963
4238
  var readSiwxSession = (address, chainId) => {
5964
4239
  if (typeof window === "undefined") return null;
5965
- const key2 = buildKey3(address);
5966
- const store = storage4();
5967
- let raw2 = null;
4240
+ const key2 = buildKey2(address);
4241
+ const store = storage2();
4242
+ let raw = null;
5968
4243
  try {
5969
- raw2 = store?.getItem(key2) ?? null;
4244
+ raw = store?.getItem(key2) ?? null;
5970
4245
  } catch {
5971
- raw2 = null;
4246
+ raw = null;
5972
4247
  }
5973
- if (raw2) {
4248
+ if (raw) {
5974
4249
  try {
5975
- return JSON.parse(raw2);
4250
+ return JSON.parse(raw);
5976
4251
  } catch {
5977
4252
  memorySiwxSessions.delete(key2);
5978
4253
  try {
@@ -5991,18 +4266,18 @@ var readSiwxSession = (address, chainId) => {
5991
4266
  };
5992
4267
  var writeSiwxSession = (address, _chainId, session) => {
5993
4268
  if (typeof window === "undefined") return;
5994
- const key2 = buildKey3(address);
4269
+ const key2 = buildKey2(address);
5995
4270
  memorySiwxSessions.set(key2, session);
5996
- const store = storage4();
4271
+ const store = storage2();
5997
4272
  try {
5998
4273
  store?.setItem(key2, JSON.stringify(session));
5999
4274
  } catch {
6000
4275
  }
6001
4276
  };
6002
4277
  var clearSiwxSession = (address, _chainId) => {
6003
- const key2 = buildKey3(address);
4278
+ const key2 = buildKey2(address);
6004
4279
  memorySiwxSessions.delete(key2);
6005
- const store = storage4();
4280
+ const store = storage2();
6006
4281
  try {
6007
4282
  store?.removeItem(key2);
6008
4283
  } catch {
@@ -6042,8 +4317,8 @@ function buildSIWXConfig(deps) {
6042
4317
  statement: STATEMENT,
6043
4318
  issuedAt,
6044
4319
  toString() {
6045
- return new import_siwe2.SiweMessage({
6046
- address: (0, import_viem10.getAddress)(accountAddress),
4320
+ return new import_siwe.SiweMessage({
4321
+ address: (0, import_viem7.getAddress)(accountAddress),
6047
4322
  chainId: numericChainId(chainId),
6048
4323
  domain,
6049
4324
  uri,
@@ -6085,7 +4360,7 @@ function buildSIWXConfig(deps) {
6085
4360
  const persistSession = async (session) => {
6086
4361
  const address = session.data.accountAddress;
6087
4362
  const id = numericChainId(session.data.chainId);
6088
- const message = new import_siwe2.SiweMessage(session.message);
4363
+ const message = new import_siwe.SiweMessage(session.message);
6089
4364
  const login = await post("/auth/login", {
6090
4365
  message,
6091
4366
  signature: session.signature,
@@ -6134,7 +4409,6 @@ function createOwneySIWX(config) {
6134
4409
  NotConnectedError,
6135
4410
  OwneyError,
6136
4411
  OwneySDK,
6137
- YieldseekerAgent,
6138
4412
  createOwneySIWX,
6139
4413
  setOwneyDebug
6140
4414
  });