@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.js CHANGED
@@ -277,18 +277,18 @@ function tokenDecimals(symbol, explicit) {
277
277
  return explicit;
278
278
  return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
279
279
  }
280
- function mapDeposit(raw2) {
280
+ function mapDeposit(raw) {
281
281
  return {
282
- txHash: raw2.txHash,
283
- smartWallet: raw2.smartWallet,
284
- amount: raw2.amount
282
+ txHash: raw.txHash,
283
+ smartWallet: raw.smartWallet,
284
+ amount: raw.amount
285
285
  };
286
286
  }
287
- function mapWithdraw(raw2) {
287
+ function mapWithdraw(raw) {
288
288
  return {
289
- txHash: raw2.txHash,
290
- type: raw2.type,
291
- amount: raw2.amount
289
+ txHash: raw.txHash,
290
+ type: raw.type,
291
+ amount: raw.amount
292
292
  };
293
293
  }
294
294
  var CHAIN_ID_TO_NAME = {
@@ -307,10 +307,10 @@ function resolveChainId(chain) {
307
307
  if (Number.isFinite(asNum) && asNum > 0) return asNum;
308
308
  return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
309
309
  }
310
- function mapPendingAllocations(raw2) {
311
- if (!Array.isArray(raw2)) return void 0;
310
+ function mapPendingAllocations(raw) {
311
+ if (!Array.isArray(raw)) return void 0;
312
312
  const pending = [];
313
- for (const entry of raw2) {
313
+ for (const entry of raw) {
314
314
  if (typeof entry !== "object" || entry === null) continue;
315
315
  const e = entry;
316
316
  if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
@@ -333,8 +333,8 @@ function mapPendingAllocations(raw2) {
333
333
  }
334
334
  return pending.length > 0 ? pending : void 0;
335
335
  }
336
- function mapBalances(raw2, _chainId, smartWallet) {
337
- const portfolio = raw2.portfolio;
336
+ function mapBalances(raw, _chainId, smartWallet) {
337
+ const portfolio = raw.portfolio;
338
338
  const portfolioByChain = portfolio.portfolioByChain ?? {};
339
339
  let totalBalance = 0;
340
340
  const tokens = [];
@@ -403,8 +403,8 @@ function sumTokenValues(tokens) {
403
403
  function sumTokenEarnings(tokens) {
404
404
  return Object.values(tokens).reduce((sum, val) => sum + Number(val), 0);
405
405
  }
406
- function mapEarnings(raw2, smartWallet) {
407
- const totalEarningsByChain = raw2.data.totalEarningsByChainWithFee ?? raw2.data.totalEarningsByChain ?? {};
406
+ function mapEarnings(raw, smartWallet) {
407
+ const totalEarningsByChain = raw.data.totalEarningsByChainWithFee ?? raw.data.totalEarningsByChain ?? {};
408
408
  const tokens = [];
409
409
  for (const [chainIdKey, tokensBySymbol] of Object.entries(
410
410
  totalEarningsByChain
@@ -423,15 +423,15 @@ function mapEarnings(raw2, smartWallet) {
423
423
  return {
424
424
  smartWallet,
425
425
  lifetimeEarnings: sumTokenEarnings(
426
- raw2.data.totalEarningsByTokenWithFee ?? raw2.data.totalEarningsByToken
426
+ raw.data.totalEarningsByTokenWithFee ?? raw.data.totalEarningsByToken
427
427
  ),
428
428
  tokens
429
429
  };
430
430
  }
431
- function mapWeightedApyByChain(raw2) {
432
- if (!raw2) return void 0;
431
+ function mapWeightedApyByChain(raw) {
432
+ if (!raw) return void 0;
433
433
  const out = {};
434
- for (const [chainKey, tokenApy] of Object.entries(raw2)) {
434
+ for (const [chainKey, tokenApy] of Object.entries(raw)) {
435
435
  const chainId = Number(chainKey);
436
436
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
437
437
  const perAsset = {};
@@ -471,15 +471,15 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
471
471
  }
472
472
  return totalBalance > 0 ? weightedSum / totalBalance : null;
473
473
  }
474
- function mapApyHistory(raw2, chainId, tokenSymbol) {
475
- const history = Object.entries(raw2.history ?? {}).map(([date, entry]) => ({
474
+ function mapApyHistory(raw, chainId, tokenSymbol) {
475
+ const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
476
476
  date,
477
477
  apy: rawPoolApyForChain(entry, chainId, tokenSymbol)
478
478
  })).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
479
479
  return {
480
- walletAddress: raw2.walletAddress,
481
- weightedApyAfterFee: raw2.weightedApyAfterFee ? sumTokenValues(raw2.weightedApyAfterFee) : void 0,
482
- apyByChainAndAsset: mapWeightedApyByChain(raw2.weightedApyAfterFeeByChain),
480
+ walletAddress: raw.walletAddress,
481
+ weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
482
+ apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain),
483
483
  history
484
484
  };
485
485
  }
@@ -575,23 +575,23 @@ function mapEntries(rawEntries, chainId) {
575
575
  };
576
576
  });
577
577
  }
578
- function mapUserProfile(raw2, userAddress) {
578
+ function mapUserProfile(raw, userAddress) {
579
579
  return {
580
580
  address: userAddress,
581
- smartWallet: raw2.smartWallet || "",
582
- chains: raw2.chains || [],
583
- strategy: raw2.strategy,
584
- hasActiveSessionKey: raw2.hasActiveSessionKey || false,
585
- protocols: raw2.protocols || [],
586
- splitting: raw2.splitting,
587
- minSplits: raw2.minSplits
581
+ smartWallet: raw.smartWallet || "",
582
+ chains: raw.chains || [],
583
+ strategy: raw.strategy,
584
+ hasActiveSessionKey: raw.hasActiveSessionKey || false,
585
+ protocols: raw.protocols || [],
586
+ splitting: raw.splitting,
587
+ minSplits: raw.minSplits
588
588
  };
589
589
  }
590
- function mapApyByStrategy(raw2) {
590
+ function mapApyByStrategy(raw) {
591
591
  const apyPerAsset = {};
592
592
  let apySum = 0;
593
593
  let apyCount = 0;
594
- for (const entry of raw2.data) {
594
+ for (const entry of raw.data) {
595
595
  const supported = SupportedAssets.find(
596
596
  (asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
597
597
  );
@@ -762,15 +762,15 @@ var readSession = (address, _chainId) => {
762
762
  if (typeof window === "undefined") return null;
763
763
  const key2 = buildKey(address);
764
764
  const store = storage();
765
- let raw2 = null;
765
+ let raw = null;
766
766
  try {
767
- raw2 = store?.getItem(key2) ?? null;
767
+ raw = store?.getItem(key2) ?? null;
768
768
  } catch {
769
- raw2 = null;
769
+ raw = null;
770
770
  }
771
- if (raw2) {
771
+ if (raw) {
772
772
  try {
773
- const parsed = JSON.parse(raw2);
773
+ const parsed = JSON.parse(raw);
774
774
  if (isFreshSession(parsed)) return parsed;
775
775
  } catch {
776
776
  }
@@ -938,8 +938,8 @@ function buildChainsByProtocol(protocols, dashboardChainIds) {
938
938
  }
939
939
  return result;
940
940
  }
941
- function flattenAvailablePools(raw2) {
942
- const byChain = raw2 ?? {};
941
+ function flattenAvailablePools(raw) {
942
+ const byChain = raw ?? {};
943
943
  const names = [];
944
944
  for (const byToken of Object.values(byChain ?? {})) {
945
945
  for (const entry of Object.values(byToken ?? {})) {
@@ -1440,8 +1440,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
1440
1440
  const poolResults = await Promise.all(
1441
1441
  universe.map(async (protocol) => {
1442
1442
  try {
1443
- const raw2 = await this.sdk.getAvailablePools(protocol.id, strategy);
1444
- return [protocol.id, flattenAvailablePools(raw2)];
1443
+ const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
1444
+ return [protocol.id, flattenAvailablePools(raw)];
1445
1445
  } catch (error) {
1446
1446
  console.warn(
1447
1447
  `[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
@@ -1507,14 +1507,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
1507
1507
  async readWalletState(ownerAddress) {
1508
1508
  try {
1509
1509
  const { portfolio } = await this.sdk.getPositions(ownerAddress);
1510
- const raw2 = portfolio;
1510
+ const raw = portfolio;
1511
1511
  debugLog("zyfai:onboard", "wallet state from getPositions", {
1512
- predeployed: raw2?.predeployed,
1513
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1512
+ predeployed: raw?.predeployed,
1513
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1514
1514
  });
1515
1515
  return {
1516
- predeployed: raw2?.predeployed,
1517
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1516
+ predeployed: raw?.predeployed,
1517
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1518
1518
  };
1519
1519
  } catch (error) {
1520
1520
  console.warn(
@@ -1794,14 +1794,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
1794
1794
  return { txHash, smartWallet, amount };
1795
1795
  }
1796
1796
  await this.ensureWalletDeployed(this.getAddress(), validChainId);
1797
- const raw2 = await this.sdk.depositFunds(
1797
+ const raw = await this.sdk.depositFunds(
1798
1798
  this.getAddress(),
1799
1799
  validChainId,
1800
1800
  amount,
1801
1801
  asset,
1802
1802
  "aggressive"
1803
1803
  );
1804
- return mapDeposit(raw2);
1804
+ return mapDeposit(raw);
1805
1805
  } catch (error) {
1806
1806
  throw error;
1807
1807
  }
@@ -1810,27 +1810,27 @@ var ZyfaiAgent = class _ZyfaiAgent {
1810
1810
  async withdraw(state, chainId, token, amount) {
1811
1811
  const validChainId = isValidChainId(chainId);
1812
1812
  await this.ensureConnected(state, validChainId);
1813
- const raw2 = await this.sdk.withdrawFunds(
1813
+ const raw = await this.sdk.withdrawFunds(
1814
1814
  this.getAddress(),
1815
1815
  validChainId,
1816
1816
  amount,
1817
1817
  token
1818
1818
  );
1819
- if (!raw2.success) {
1819
+ if (!raw.success) {
1820
1820
  throw new OwneyError(
1821
1821
  "WITHDRAW_FAILED",
1822
- raw2.message || "Zyfai withdraw failed.",
1823
- { chainId: validChainId, token, amount, response: raw2 },
1822
+ raw.message || "Zyfai withdraw failed.",
1823
+ { chainId: validChainId, token, amount, response: raw },
1824
1824
  this.id
1825
1825
  );
1826
1826
  }
1827
- return mapWithdraw(raw2);
1827
+ return mapWithdraw(raw);
1828
1828
  }
1829
1829
  // --- IAgent: Portfolio reads ---
1830
1830
  async getBalances(state, chainId) {
1831
1831
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
1832
- const raw2 = await this.sdk.getPortfolio(this.getAddress());
1833
- return mapBalances(raw2, validChainId, smartWallet);
1832
+ const raw = await this.sdk.getPortfolio(this.getAddress());
1833
+ return mapBalances(raw, validChainId, smartWallet);
1834
1834
  }
1835
1835
  earningsKey(state, chainId, smartWallet) {
1836
1836
  return JSON.stringify([
@@ -1843,11 +1843,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
1843
1843
  const existing = this.earningsReads.get(key2);
1844
1844
  if (existing) return existing;
1845
1845
  const generation = this.earningsGeneration;
1846
- const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw2) => {
1846
+ const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw) => {
1847
1847
  if (generation === this.earningsGeneration) {
1848
- this.earningsSnapshot = { key: key2, raw: raw2, at: Date.now() };
1848
+ this.earningsSnapshot = { key: key2, raw, at: Date.now() };
1849
1849
  }
1850
- return raw2;
1850
+ return raw;
1851
1851
  }).finally(() => {
1852
1852
  if (this.earningsReads.get(key2) === pending)
1853
1853
  this.earningsReads.delete(key2);
@@ -1857,11 +1857,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
1857
1857
  }
1858
1858
  async getEarnings(state, chainId) {
1859
1859
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
1860
- const raw2 = await this.readEarnings(
1860
+ const raw = await this.readEarnings(
1861
1861
  this.earningsKey(state, chainId, smartWallet),
1862
1862
  smartWallet
1863
1863
  );
1864
- return mapEarnings(raw2, smartWallet);
1864
+ return mapEarnings(raw, smartWallet);
1865
1865
  }
1866
1866
  async refreshEarnings(state, chainId) {
1867
1867
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
@@ -1888,8 +1888,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
1888
1888
  }
1889
1889
  async getAccountApy(state, chainId, days, tokenSymbol) {
1890
1890
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
1891
- const raw2 = await this.sdk.getDailyApyHistory(smartWallet, days);
1892
- return mapApyHistory(raw2, chainId, tokenSymbol);
1891
+ const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
1892
+ return mapApyHistory(raw, chainId, tokenSymbol);
1893
1893
  }
1894
1894
  /**
1895
1895
  * Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
@@ -1924,7 +1924,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1924
1924
  const matched = [];
1925
1925
  let backendExhausted = false;
1926
1926
  for (let i = 0; i < MAX_BACKEND_CALLS && matched.length < limit; i++) {
1927
- const raw2 = await this.sdk.getHistory(smartWallet, validChainId, {
1927
+ const raw = await this.sdk.getHistory(smartWallet, validChainId, {
1928
1928
  limit: backendPageSize,
1929
1929
  offset,
1930
1930
  fromDate: options?.fromDate,
@@ -1935,13 +1935,13 @@ var ZyfaiAgent = class _ZyfaiAgent {
1935
1935
  // asset's rows and handing back a page that filters to nothing.
1936
1936
  assetType
1937
1937
  });
1938
- raw2.data.forEach((entry, idx) => {
1938
+ raw.data.forEach((entry, idx) => {
1939
1939
  if (entry.chainId === validChainId) {
1940
1940
  matched.push({ entry, rawIdx: offset + idx });
1941
1941
  }
1942
1942
  });
1943
- offset += raw2.data.length;
1944
- if (raw2.data.length < backendPageSize) {
1943
+ offset += raw.data.length;
1944
+ if (raw.data.length < backendPageSize) {
1945
1945
  backendExhausted = true;
1946
1946
  break;
1947
1947
  }
@@ -1963,18 +1963,18 @@ var ZyfaiAgent = class _ZyfaiAgent {
1963
1963
  }
1964
1964
  async getUserProfile(state, chainId) {
1965
1965
  await this.connectAuth(state, chainId);
1966
- const raw2 = await this.sdk.getUserDetails();
1966
+ const raw = await this.sdk.getUserDetails();
1967
1967
  debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
1968
1968
  asset: "USDC (default \u2014 no asset passed)",
1969
- splitting: raw2.splitting,
1970
- minSplits: raw2.minSplits,
1971
- strategy: raw2.strategy,
1972
- chains: raw2.chains,
1973
- protocolCount: raw2.protocols?.length,
1974
- hasActiveSessionKey: raw2.hasActiveSessionKey,
1975
- smartWallet: raw2.smartWallet
1969
+ splitting: raw.splitting,
1970
+ minSplits: raw.minSplits,
1971
+ strategy: raw.strategy,
1972
+ chains: raw.chains,
1973
+ protocolCount: raw.protocols?.length,
1974
+ hasActiveSessionKey: raw.hasActiveSessionKey,
1975
+ smartWallet: raw.smartWallet
1976
1976
  });
1977
- return mapUserProfile(raw2, this.connectedAddress);
1977
+ return mapUserProfile(raw, this.connectedAddress);
1978
1978
  }
1979
1979
  async ensureAutoSelectProtocols(state, chainId, asset) {
1980
1980
  await this.connectAuth(state, chainId);
@@ -1993,64 +1993,238 @@ var ZyfaiAgent = class _ZyfaiAgent {
1993
1993
  }
1994
1994
  // --- IAgent: Discovery (no wallet required) ---
1995
1995
  async getAgentApy(days, options) {
1996
- const raw2 = await this.sdk.getAPYPerStrategy(
1996
+ const raw = await this.sdk.getAPYPerStrategy(
1997
1997
  false,
1998
1998
  DayFilterMapping[days],
1999
1999
  "aggressive",
2000
2000
  options?.chainId,
2001
2001
  options?.tokenSymbol
2002
2002
  );
2003
- return mapApyByStrategy(raw2);
2003
+ return mapApyByStrategy(raw);
2004
2004
  }
2005
2005
  };
2006
2006
 
2007
- // src/agents/yieldseeker/yieldseeker.agent.ts
2008
- import {
2009
- createPublicClient as createPublicClient3,
2010
- createWalletClient as createWalletClient2,
2011
- custom as custom2,
2012
- encodeFunctionData,
2013
- erc20Abi,
2014
- getAddress as getAddress2,
2015
- isAddress as isAddress2
2016
- } from "viem";
2017
- import { base as base3 } from "viem/chains";
2018
-
2019
- // src/lib/chain-guard.ts
2020
- var CHAIN_NAMES = {
2021
- 1: "Ethereum",
2022
- 8453: "Base",
2023
- 42161: "Arbitrum"
2024
- };
2025
- function chainName(chainId) {
2026
- return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
2027
- }
2028
- async function ensureWalletOnChain(pub, wallet, expected) {
2029
- const actual = await pub.getChainId();
2030
- if (actual === expected) return;
2007
+ // src/lib/routing-api.ts
2008
+ var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2009
+ async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
2010
+ const url = `${baseUrl}/api/v1/agent/org-config`;
2031
2011
  try {
2032
- await wallet.switchChain({ id: expected });
2012
+ const res = await fetch(url, {
2013
+ method: "GET",
2014
+ headers: {
2015
+ "Content-Type": "application/json",
2016
+ "x-owney-api-key": `${apiKey}`
2017
+ }
2018
+ });
2019
+ if (!res.ok) {
2020
+ if (res.status !== 404) {
2021
+ console.warn(
2022
+ `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
2023
+ );
2024
+ }
2025
+ return null;
2026
+ }
2027
+ const json = await res.json();
2028
+ const policy = json.success ? json.data ?? null : null;
2029
+ debugLog(
2030
+ "owney-sdk",
2031
+ policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
2032
+ policy ?? void 0
2033
+ );
2034
+ return policy;
2033
2035
  } catch (error) {
2036
+ console.warn(
2037
+ "[owney-sdk] Could not read org agent config (non-fatal):",
2038
+ error instanceof Error ? error.message : String(error)
2039
+ );
2040
+ return null;
2041
+ }
2042
+ }
2043
+ async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
2044
+ const url = `${baseUrl}/api/v1/agent/keys`;
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
+ const text = await res.text().catch(() => "");
2034
2054
  throw new OwneyError(
2035
- "CHAIN_MISMATCH",
2036
- `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2037
- {
2038
- expectedChainId: expected,
2039
- actualChainId: actual,
2040
- cause: error instanceof Error ? error.message : String(error)
2041
- }
2055
+ "API_ROUTING_ERROR",
2056
+ `Routing API error ${res.status}: ${text}`,
2057
+ { statusCode: res.status, responseBody: text }
2042
2058
  );
2043
2059
  }
2044
- const after = await pub.getChainId();
2045
- if (after !== expected) {
2060
+ const json = await res.json();
2061
+ if (!json.success) {
2046
2062
  throw new OwneyError(
2047
- "CHAIN_MISMATCH",
2048
- `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2049
- { expectedChainId: expected, actualChainId: after }
2063
+ "API_ROUTING_FAILED",
2064
+ `Routing API request failed: ${json.message}`,
2065
+ { message: json.message }
2066
+ );
2067
+ }
2068
+ return json.data;
2069
+ }
2070
+
2071
+ // src/lib/health-report.ts
2072
+ var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2073
+ async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
2074
+ try {
2075
+ await fetch(`${baseUrl}/api/v1/agent/health-report`, {
2076
+ method: "POST",
2077
+ headers: {
2078
+ "Content-Type": "application/json",
2079
+ "x-owney-api-key": apiKey
2080
+ },
2081
+ body: JSON.stringify({
2082
+ agent_type: agentType,
2083
+ error_code: errorCode,
2084
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2085
+ })
2086
+ });
2087
+ } catch (err) {
2088
+ console.warn(
2089
+ `[owney-sdk] health-report failed for agent "${agentType}":`,
2090
+ err instanceof Error ? err.message : err
2091
+ );
2092
+ }
2093
+ }
2094
+ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
2095
+ try {
2096
+ return await fn();
2097
+ } catch (err) {
2098
+ const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
2099
+ void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
2100
+ throw err;
2101
+ }
2102
+ }
2103
+
2104
+ // src/lib/helpers/withdraw-helper.ts
2105
+ import { parseUnits } from "viem";
2106
+ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
2107
+ const target = asset.toUpperCase();
2108
+ return agents.map((agent) => {
2109
+ const agentBalance = aggregated[agent.id];
2110
+ const tokenBalance = agentBalance?.tokens.find(
2111
+ (t) => t.chainId === chainId && t.asset.toUpperCase() === target
2050
2112
  );
2113
+ if (!tokenBalance) return { agent, balance: 0n };
2114
+ return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
2115
+ });
2116
+ }
2117
+ function planProportionalShares(balances, requested, totalAvailable) {
2118
+ const plans = balances.map(({ agent, balance }) => ({
2119
+ agent,
2120
+ balance,
2121
+ planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
2122
+ }));
2123
+ const assigned = plans.reduce((s, p) => s + p.planned, 0n);
2124
+ let remainder = requested - assigned;
2125
+ const byHeadroom = [...plans].sort((a, b) => {
2126
+ const diff = b.balance - b.planned - (a.balance - a.planned);
2127
+ return diff > 0n ? 1 : diff < 0n ? -1 : 0;
2128
+ });
2129
+ for (const p of byHeadroom) {
2130
+ if (remainder === 0n) break;
2131
+ const headroom = p.balance - p.planned;
2132
+ if (headroom <= 0n) continue;
2133
+ const take = headroom < remainder ? headroom : remainder;
2134
+ p.planned += take;
2135
+ remainder -= take;
2136
+ }
2137
+ return plans;
2138
+ }
2139
+ function planDisabledDrain(disabled, requested) {
2140
+ const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
2141
+ const plans = [];
2142
+ let remaining = requested;
2143
+ for (const { agent, balance } of sorted) {
2144
+ if (remaining === 0n) {
2145
+ plans.push({ agent, balance, planned: 0n });
2146
+ continue;
2147
+ }
2148
+ const take = balance < remaining ? balance : remaining;
2149
+ plans.push({ agent, balance, planned: take });
2150
+ remaining -= take;
2151
+ }
2152
+ return { plans, remaining };
2153
+ }
2154
+ function redistributeShare(plans, fromIndex, amount, candidatePool) {
2155
+ const pool = candidatePool ?? plans.slice(fromIndex + 1);
2156
+ const candidates = pool.filter((c) => c.balance - c.planned > 0n);
2157
+ const totalHeadroom = candidates.reduce(
2158
+ (s, c) => s + (c.balance - c.planned),
2159
+ 0n
2160
+ );
2161
+ if (totalHeadroom === 0n) return;
2162
+ let distributed = 0n;
2163
+ for (const c of candidates) {
2164
+ const headroom = c.balance - c.planned;
2165
+ const proportional = headroom * amount / totalHeadroom;
2166
+ const give = proportional > headroom ? headroom : proportional;
2167
+ c.planned += give;
2168
+ distributed += give;
2169
+ }
2170
+ let leftover = amount - distributed;
2171
+ for (const c of candidates) {
2172
+ if (leftover === 0n) break;
2173
+ const headroom = c.balance - c.planned;
2174
+ if (headroom <= 0n) continue;
2175
+ const take = headroom < leftover ? headroom : leftover;
2176
+ c.planned += take;
2177
+ leftover -= take;
2178
+ }
2179
+ }
2180
+ function sumWithdrawnAmount(results) {
2181
+ return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
2182
+ }
2183
+
2184
+ // src/lib/helpers/account-apy-helper.ts
2185
+ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
2186
+ const sums = {};
2187
+ const weights = {};
2188
+ for (const id of Object.keys(agentApys)) {
2189
+ const cells = agentApys[id].apyByChainAndAsset;
2190
+ const balance = agentBalances[id] ?? 0;
2191
+ if (!cells || balance <= 0) continue;
2192
+ for (const [chainKey, perAsset] of Object.entries(cells)) {
2193
+ if (!perAsset) continue;
2194
+ const chainId = Number(chainKey);
2195
+ for (const [asset, apyValue] of Object.entries(perAsset)) {
2196
+ const apy = Number(apyValue ?? 0);
2197
+ if (apy === 0) continue;
2198
+ sums[chainId] ??= {};
2199
+ weights[chainId] ??= {};
2200
+ sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
2201
+ weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2202
+ }
2203
+ }
2204
+ }
2205
+ const out = {};
2206
+ for (const chainKey of Object.keys(sums)) {
2207
+ const chainId = Number(chainKey);
2208
+ const perAssetOut = {};
2209
+ for (const asset of Object.keys(sums[chainId])) {
2210
+ const w = weights[chainId][asset];
2211
+ if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
2212
+ }
2213
+ if (Object.keys(perAssetOut).length > 0) {
2214
+ out[chainId] = perAssetOut;
2215
+ }
2051
2216
  }
2217
+ return out;
2052
2218
  }
2053
2219
 
2220
+ // src/client.ts
2221
+ import {
2222
+ createPublicClient as createPublicClient2,
2223
+ createWalletClient,
2224
+ custom
2225
+ } from "viem";
2226
+ import { base as base2, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
2227
+
2054
2228
  // src/lib/transfer-auth.ts
2055
2229
  import { bytesToHex } from "viem";
2056
2230
  var ERC20_META_ABI = [
@@ -2088,25 +2262,24 @@ function randomAuthNonce() {
2088
2262
  }
2089
2263
 
2090
2264
  // src/lib/sponsor-client.ts
2091
- var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2092
- async function postPaymasterIntent(input) {
2093
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2265
+ var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2266
+ async function postSponsorTransferAuth(input) {
2267
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2094
2268
  let res;
2095
2269
  try {
2096
- res = await fetch(`${base5}/api/v1/sponsor/paymaster-intent`, {
2270
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2097
2271
  method: "POST",
2098
2272
  headers: {
2099
2273
  "content-type": "application/json",
2100
- "x-owney-api-key": input.apiKey,
2101
- Authorization: `Signature ${input.yieldseekerSignature}`
2274
+ "x-owney-api-key": input.apiKey
2102
2275
  },
2103
2276
  body: JSON.stringify(input.body)
2104
2277
  });
2105
2278
  } catch (networkError) {
2106
2279
  throw new OwneyError(
2107
2280
  "SPONSOR_REQUEST_FAILED",
2108
- `Paymaster intent network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2109
- { cause: String(networkError), safeToFallback: true }
2281
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2282
+ { cause: String(networkError) }
2110
2283
  );
2111
2284
  }
2112
2285
  const text = await res.text();
@@ -2115,29 +2288,30 @@ async function postPaymasterIntent(input) {
2115
2288
  parsed = JSON.parse(text);
2116
2289
  } catch {
2117
2290
  }
2118
- if (!res.ok || !parsed?.success || typeof parsed.data?.intent !== "string" || typeof parsed.data.expiresAt !== "number") {
2291
+ if (!res.ok || !parsed?.success || !parsed.data) {
2119
2292
  throw new OwneyError(
2120
2293
  "SPONSOR_REQUEST_FAILED",
2121
- `Paymaster intent API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2294
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2122
2295
  {
2123
2296
  statusCode: res.status,
2124
2297
  responseBody: text.slice(0, 500),
2125
- safeToFallback: true
2298
+ // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2299
+ // before broadcast, so it is safe to fall back to a user-paid deposit.
2300
+ safeToFallback: res.status === 503
2126
2301
  }
2127
2302
  );
2128
2303
  }
2129
2304
  return parsed.data;
2130
2305
  }
2131
- async function postSponsorTransferAuth(input) {
2132
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2306
+ async function postSponsorPermit2Transfer(input) {
2307
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2133
2308
  let res;
2134
2309
  try {
2135
- res = await fetch(`${base5}/api/v1/sponsor/erc20-transfer-auth`, {
2310
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2136
2311
  method: "POST",
2137
2312
  headers: {
2138
2313
  "content-type": "application/json",
2139
- "x-owney-api-key": input.apiKey,
2140
- ...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
2314
+ "x-owney-api-key": input.apiKey
2141
2315
  },
2142
2316
  body: JSON.stringify(input.body)
2143
2317
  });
@@ -2145,7 +2319,7 @@ async function postSponsorTransferAuth(input) {
2145
2319
  throw new OwneyError(
2146
2320
  "SPONSOR_REQUEST_FAILED",
2147
2321
  `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2148
- { cause: String(networkError) }
2322
+ { cause: String(networkError), safeToFallback: false }
2149
2323
  );
2150
2324
  }
2151
2325
  const text = await res.text();
@@ -2161,59 +2335,18 @@ async function postSponsorTransferAuth(input) {
2161
2335
  {
2162
2336
  statusCode: res.status,
2163
2337
  responseBody: text.slice(0, 500),
2164
- // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2165
- // before broadcast, so it is safe to fall back to a user-paid deposit.
2166
- safeToFallback: res.status === 503
2338
+ safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
2167
2339
  }
2168
2340
  );
2169
2341
  }
2170
2342
  return parsed.data;
2171
2343
  }
2172
- async function postSponsorPermit2Transfer(input) {
2173
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2174
- let res;
2175
- try {
2176
- res = await fetch(`${base5}/api/v1/sponsor/permit2-transfer`, {
2177
- method: "POST",
2178
- headers: {
2179
- "content-type": "application/json",
2180
- "x-owney-api-key": input.apiKey,
2181
- ...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
2182
- },
2183
- body: JSON.stringify(input.body)
2184
- });
2185
- } catch (networkError) {
2186
- throw new OwneyError(
2187
- "SPONSOR_REQUEST_FAILED",
2188
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2189
- { cause: String(networkError), safeToFallback: false }
2190
- );
2191
- }
2192
- const text = await res.text();
2193
- let parsed = null;
2194
- try {
2195
- parsed = JSON.parse(text);
2196
- } catch {
2197
- }
2198
- if (!res.ok || !parsed?.success || !parsed.data) {
2199
- throw new OwneyError(
2200
- "SPONSOR_REQUEST_FAILED",
2201
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2202
- {
2203
- statusCode: res.status,
2204
- responseBody: text.slice(0, 500),
2205
- safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
2206
- }
2207
- );
2208
- }
2209
- return parsed.data;
2210
- }
2211
- async function getSponsorRelayerAddress(input) {
2212
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2344
+ async function getSponsorRelayerAddress(input) {
2345
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2213
2346
  let res;
2214
2347
  try {
2215
2348
  res = await fetch(
2216
- `${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2349
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2217
2350
  {
2218
2351
  headers: { "x-owney-api-key": input.apiKey }
2219
2352
  }
@@ -2311,1984 +2444,216 @@ async function readPermit2Allowance(publicClient, token, owner) {
2311
2444
  address: token,
2312
2445
  abi: ERC20_ALLOWANCE_ABI,
2313
2446
  functionName: "allowance",
2314
- args: [owner, PERMIT2_ADDRESS]
2315
- });
2316
- }
2317
- async function readErc20Balance(publicClient, token, owner) {
2318
- return publicClient.readContract({
2319
- address: token,
2320
- abi: ERC20_ALLOWANCE_ABI,
2321
- functionName: "balanceOf",
2322
- args: [owner]
2323
- });
2324
- }
2325
-
2326
- // src/lib/sponsored-deposit.ts
2327
- var AUTH_WINDOW_SECONDS = 15 * 60;
2328
- var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
2329
- function provideDepositVerificationContext(callback, context) {
2330
- callback[verificationSetter]?.(context);
2331
- }
2332
- function makeVerificationAwareDepositCallback(implementation) {
2333
- let nextVerification;
2334
- const callback = async (smartWallet, chainId, amount) => {
2335
- const verification = nextVerification;
2336
- nextVerification = void 0;
2337
- return implementation(smartWallet, chainId, amount, verification);
2338
- };
2339
- Object.defineProperty(callback, verificationSetter, {
2340
- value: (context) => {
2341
- nextVerification = context;
2342
- }
2343
- });
2344
- return callback;
2345
- }
2346
- function makeSponsoredDepositCallback(deps) {
2347
- const post = deps.httpPost ?? postSponsorTransferAuth;
2348
- return makeVerificationAwareDepositCallback(
2349
- async (smartWallet, chainId, amount, verification) => {
2350
- const cid = chainId;
2351
- const token = deps.tokenAddressByChain[cid];
2352
- if (!token) {
2353
- throw new OwneyError(
2354
- "CHAIN_UNSUPPORTED",
2355
- `No sponsored token configured for chain ${chainId}`
2356
- );
2357
- }
2358
- const pub = deps.getPublicClient(cid);
2359
- const wallet = deps.getWalletClient(cid);
2360
- await ensureWalletOnChain(pub, wallet, cid);
2361
- try {
2362
- const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2363
- if (balance < BigInt(amount)) {
2364
- throw new OwneyError(
2365
- "DEPOSIT_INSUFFICIENT_BALANCE",
2366
- "Insufficient balance for this deposit.",
2367
- { token, chainId: cid, balance: balance.toString(), amount }
2368
- );
2369
- }
2370
- } catch (err) {
2371
- if (err instanceof OwneyError) throw err;
2372
- console.warn(
2373
- "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2374
- err instanceof Error ? err.message : String(err)
2375
- );
2376
- }
2377
- const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2378
- const validAfter = 0n;
2379
- const validBefore = BigInt(
2380
- Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2381
- );
2382
- const nonce = randomAuthNonce();
2383
- const typedData = buildTransferWithAuthorizationTypedData({
2384
- token,
2385
- chainId: cid,
2386
- tokenName,
2387
- tokenVersion,
2388
- message: {
2389
- from: deps.ownerAddress,
2390
- to: smartWallet,
2391
- value: BigInt(amount),
2392
- validAfter,
2393
- validBefore,
2394
- nonce
2395
- }
2396
- });
2397
- const authSignature = await wallet.signTypedData({
2398
- account: deps.ownerAddress,
2399
- ...typedData
2400
- });
2401
- deps.onApproved?.();
2402
- const result = await post({
2403
- baseUrl: deps.baseUrl,
2404
- apiKey: deps.apiKey,
2405
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
2406
- body: {
2407
- chainId: cid,
2408
- token,
2409
- from: deps.ownerAddress,
2410
- to: smartWallet,
2411
- value: amount,
2412
- validAfter: validAfter.toString(),
2413
- validBefore: validBefore.toString(),
2414
- nonce,
2415
- authSignature,
2416
- tokenName,
2417
- tokenVersion,
2418
- ...verification?.agentId === "yieldseeker" ? {
2419
- yieldseekerUserId: verification.userId,
2420
- yieldseekerAgentId: verification.yieldseekerAgentId
2421
- } : {}
2422
- }
2423
- });
2424
- return result.txHash;
2425
- }
2426
- );
2427
- }
2428
-
2429
- // src/agents/yieldseeker/yieldseeker.auth.ts
2430
- import { SiweMessage, generateNonce } from "siwe";
2431
- import {
2432
- createPublicClient as createPublicClient2,
2433
- createWalletClient,
2434
- custom,
2435
- getAddress
2436
- } from "viem";
2437
- import { base as base2 } from "viem/chains";
2438
-
2439
- // src/agents/yieldseeker/yieldseeker.auth-cache.ts
2440
- var KEY_PREFIX2 = "owney.yieldseeker.session.v5";
2441
- var INVALIDATED_KEY_PREFIXES = [
2442
- "owney.yieldseeker.session",
2443
- "owney.yieldseeker.session.v3",
2444
- "owney.yieldseeker.session.v4"
2445
- ];
2446
- var storage2 = () => {
2447
- if (typeof window === "undefined") return null;
2448
- try {
2449
- return window.localStorage;
2450
- } catch {
2451
- return null;
2452
- }
2453
- };
2454
- var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2455
- var invalidatedKeys = (address, chainId) => INVALIDATED_KEY_PREFIXES.map(
2456
- (prefix) => `${prefix}:${address.toLowerCase()}:${chainId}`
2457
- );
2458
- var clearInvalidatedSessions = (store, address, chainId) => {
2459
- for (const key2 of invalidatedKeys(address, chainId)) {
2460
- memorySessions2.delete(key2);
2461
- try {
2462
- store?.removeItem(key2);
2463
- } catch {
2464
- }
2465
- }
2466
- };
2467
- var memorySessions2 = /* @__PURE__ */ new Map();
2468
- var isValidSession = (session) => {
2469
- if (!session?.token) return false;
2470
- try {
2471
- const parsed = JSON.parse(atob(session.token));
2472
- return typeof parsed.message === "string" && typeof parsed.signature === "string" && parsed.signature.startsWith("0x");
2473
- } catch {
2474
- return false;
2475
- }
2476
- };
2477
- var readYieldseekerSession = (address, chainId) => {
2478
- if (typeof window === "undefined") return null;
2479
- const key2 = buildKey2(address, chainId);
2480
- const store = storage2();
2481
- clearInvalidatedSessions(store, address, chainId);
2482
- let raw2 = null;
2483
- try {
2484
- raw2 = store?.getItem(key2) ?? null;
2485
- } catch {
2486
- raw2 = null;
2487
- }
2488
- if (raw2) {
2489
- try {
2490
- const parsed = JSON.parse(raw2);
2491
- if (isValidSession(parsed)) return parsed.token;
2492
- } catch {
2493
- }
2494
- memorySessions2.delete(key2);
2495
- try {
2496
- store?.removeItem(key2);
2497
- } catch {
2498
- }
2499
- return null;
2500
- }
2501
- const cached = memorySessions2.get(key2);
2502
- if (isValidSession(cached)) return cached.token;
2503
- if (cached) memorySessions2.delete(key2);
2504
- return null;
2505
- };
2506
- var writeYieldseekerSession = (address, chainId, token) => {
2507
- if (typeof window === "undefined") return;
2508
- const session = { token };
2509
- if (!isValidSession(session)) return;
2510
- const key2 = buildKey2(address, chainId);
2511
- memorySessions2.set(key2, session);
2512
- const store = storage2();
2513
- try {
2514
- store?.setItem(key2, JSON.stringify(session));
2515
- } catch {
2516
- }
2517
- };
2518
- var clearYieldseekerSession = (address, chainId) => {
2519
- const key2 = buildKey2(address, chainId);
2520
- memorySessions2.delete(key2);
2521
- const store = storage2();
2522
- clearInvalidatedSessions(store, address, chainId);
2523
- try {
2524
- store?.removeItem(key2);
2525
- } catch {
2526
- }
2527
- };
2528
-
2529
- // src/agents/yieldseeker/yieldseeker.auth.ts
2530
- function resolveSiweOrigin(override) {
2531
- const origin = override?.trim() || (typeof window !== "undefined" ? window.location?.origin : void 0);
2532
- if (!origin || origin === "null") {
2533
- throw new Error("Yieldseeker sign-in requires the requesting app's browser origin.");
2534
- }
2535
- const url = new URL(origin);
2536
- if (url.protocol !== "https:" && url.protocol !== "http:") {
2537
- throw new Error("Yieldseeker sign-in requires an HTTP or HTTPS app origin.");
2538
- }
2539
- if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
2540
- throw new Error("Yieldseeker SIWE override must be an origin without credentials, path, query, or fragment.");
2541
- }
2542
- return url;
2543
- }
2544
- function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
2545
- const url = resolveSiweOrigin(dependencies.origin);
2546
- return new SiweMessage({
2547
- scheme: url.protocol.slice(0, -1),
2548
- domain: url.host,
2549
- address: getAddress(address),
2550
- uri: url.origin,
2551
- version: "1",
2552
- chainId,
2553
- nonce: (dependencies.nonce ?? generateNonce)(),
2554
- issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
2555
- }).prepareMessage();
2556
- }
2557
- function encodeYieldseekerAuthToken(token) {
2558
- const bytes = new TextEncoder().encode(JSON.stringify(token));
2559
- let binary = "";
2560
- for (const byte of bytes) binary += String.fromCharCode(byte);
2561
- return btoa(binary);
2562
- }
2563
- var YieldseekerAuth = class {
2564
- constructor(dependencies = {}) {
2565
- this.dependencies = dependencies;
2566
- }
2567
- dependencies;
2568
- tokens = /* @__PURE__ */ new Map();
2569
- pending = /* @__PURE__ */ new Map();
2570
- scopes = /* @__PURE__ */ new Map();
2571
- key(state, chainId) {
2572
- return `${state.walletAddress.toLowerCase()}:${chainId}:${resolveSiweOrigin(this.dependencies.origin).origin}`;
2573
- }
2574
- async getToken(state, chainId) {
2575
- const key2 = this.key(state, chainId);
2576
- const scope = { address: state.walletAddress, chainId };
2577
- this.scopes.set(key2, scope);
2578
- const cached = this.tokens.get(key2);
2579
- if (cached) return cached;
2580
- const persisted = readYieldseekerSession(scope.address, scope.chainId);
2581
- if (persisted && this.matchesOrigin(persisted)) {
2582
- this.tokens.set(key2, persisted);
2583
- return persisted;
2584
- }
2585
- if (persisted) clearYieldseekerSession(scope.address, scope.chainId);
2586
- const inFlight = this.pending.get(key2);
2587
- if (inFlight) return inFlight;
2588
- const request = this.sign(state, chainId).then((token) => {
2589
- this.tokens.set(key2, token);
2590
- writeYieldseekerSession(scope.address, scope.chainId, token);
2591
- return token;
2592
- });
2593
- this.pending.set(key2, request);
2594
- try {
2595
- return await request;
2596
- } finally {
2597
- this.pending.delete(key2);
2598
- }
2599
- }
2600
- matchesOrigin(token) {
2601
- try {
2602
- const message = new SiweMessage(JSON.parse(atob(token)).message);
2603
- const url = resolveSiweOrigin(this.dependencies.origin);
2604
- return message.domain === url.host && message.uri === url.origin && message.scheme === url.protocol.slice(0, -1);
2605
- } catch {
2606
- return false;
2607
- }
2608
- }
2609
- clear(state, chainId) {
2610
- if (!state || chainId === void 0) {
2611
- for (const scope of this.scopes.values()) {
2612
- clearYieldseekerSession(scope.address, scope.chainId);
2613
- }
2614
- this.tokens.clear();
2615
- this.pending.clear();
2616
- this.scopes.clear();
2617
- return;
2618
- }
2619
- const key2 = this.key(state, chainId);
2620
- this.tokens.delete(key2);
2621
- this.pending.delete(key2);
2622
- this.scopes.delete(key2);
2623
- clearYieldseekerSession(state.walletAddress, chainId);
2624
- }
2625
- async sign(state, chainId) {
2626
- const account = getAddress(state.walletAddress);
2627
- const publicClient = createPublicClient2({
2628
- chain: base2,
2629
- transport: custom(state.provider)
2630
- });
2631
- const walletClient = createWalletClient({
2632
- account,
2633
- chain: base2,
2634
- transport: custom(state.provider)
2635
- });
2636
- await ensureWalletOnChain(
2637
- publicClient,
2638
- walletClient,
2639
- 8453
2640
- );
2641
- const message = createYieldseekerSiweMessage(
2642
- account,
2643
- chainId,
2644
- this.dependencies
2645
- );
2646
- const signature = await walletClient.signMessage({ account, message });
2647
- return encodeYieldseekerAuthToken({ message, signature });
2648
- }
2649
- };
2650
-
2651
- // src/agents/yieldseeker/yieldseeker.identity-cache.ts
2652
- var KEY_PREFIX3 = "owney.yieldseeker.identity.v1";
2653
- var YIELDSEEKER_IDENTITY_TTL_MS = 24 * 60 * 60 * 1e3;
2654
- var memoryIdentities = /* @__PURE__ */ new Map();
2655
- var storage3 = () => {
2656
- if (typeof window === "undefined") return null;
2657
- try {
2658
- return window.localStorage;
2659
- } catch {
2660
- return null;
2661
- }
2662
- };
2663
- var keyFor = (walletAddress, chainId) => `${KEY_PREFIX3}:${walletAddress.toLowerCase()}:${chainId}`;
2664
- function valid(value, walletAddress, chainId, now) {
2665
- return Boolean(
2666
- 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
2667
- );
2668
- }
2669
- function readYieldseekerIdentity(walletAddress, chainId, now = Date.now()) {
2670
- if (typeof window === "undefined") return null;
2671
- const key2 = keyFor(walletAddress, chainId);
2672
- const store = storage3();
2673
- let parsed = null;
2674
- try {
2675
- const raw2 = store?.getItem(key2);
2676
- parsed = raw2 ? JSON.parse(raw2) : null;
2677
- } catch {
2678
- parsed = null;
2679
- }
2680
- const candidate = parsed ?? memoryIdentities.get(key2);
2681
- if (valid(candidate, walletAddress, chainId, now)) {
2682
- memoryIdentities.set(key2, candidate);
2683
- return { userId: candidate.userId };
2684
- }
2685
- memoryIdentities.delete(key2);
2686
- try {
2687
- store?.removeItem(key2);
2688
- } catch {
2689
- }
2690
- return null;
2691
- }
2692
- function writeYieldseekerIdentity(walletAddress, chainId, userId, now = Date.now()) {
2693
- if (typeof window === "undefined") return;
2694
- const identity = {
2695
- userId,
2696
- walletAddress,
2697
- chainId,
2698
- expiresAt: now + YIELDSEEKER_IDENTITY_TTL_MS
2699
- };
2700
- if (!valid(identity, walletAddress, chainId, now)) return;
2701
- const key2 = keyFor(walletAddress, chainId);
2702
- memoryIdentities.set(key2, identity);
2703
- try {
2704
- storage3()?.setItem(key2, JSON.stringify(identity));
2705
- } catch {
2706
- }
2707
- }
2708
- function clearYieldseekerIdentity(walletAddress, chainId) {
2709
- const key2 = keyFor(walletAddress, chainId);
2710
- memoryIdentities.delete(key2);
2711
- try {
2712
- storage3()?.removeItem(key2);
2713
- } catch {
2714
- }
2715
- }
2716
-
2717
- // src/agents/yieldseeker/yieldseeker.client.ts
2718
- var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2719
- function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
2720
- return `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/agent/yieldseeker`;
2721
- }
2722
- var YIELDSEEKER_API_BASE_URL = getYieldseekerProxyBaseUrl();
2723
- var YieldseekerApiError = class extends Error {
2724
- constructor(status, providerCode, responseFields) {
2725
- super(`Yieldseeker request failed (${status}): ${providerCode}`);
2726
- this.status = status;
2727
- this.providerCode = providerCode;
2728
- this.responseFields = responseFields;
2729
- this.name = "YieldseekerApiError";
2730
- }
2731
- status;
2732
- providerCode;
2733
- responseFields;
2734
- get isAuthenticationError() {
2735
- return this.status === 401 || this.status === 403;
2736
- }
2737
- };
2738
- function providerError(body, fallback) {
2739
- if (!body || typeof body !== "object") return { code: fallback };
2740
- const record = body;
2741
- return {
2742
- code: typeof record.message === "string" ? record.message : fallback,
2743
- fields: record.fields && typeof record.fields === "object" ? record.fields : void 0
2744
- };
2745
- }
2746
- var YieldseekerApiClient = class {
2747
- constructor(owneyApiKey, baseUrl = YIELDSEEKER_API_BASE_URL, fetchFn = fetch) {
2748
- this.owneyApiKey = owneyApiKey;
2749
- this.baseUrl = baseUrl;
2750
- this.fetchFn = fetchFn;
2751
- }
2752
- owneyApiKey;
2753
- baseUrl;
2754
- fetchFn;
2755
- async request(path, options = {}) {
2756
- const controller = new AbortController();
2757
- const timer = setTimeout(
2758
- () => controller.abort(),
2759
- options.timeoutMs ?? 15e3
2760
- );
2761
- try {
2762
- const response = await this.fetchFn(`${this.baseUrl}${path}`, {
2763
- method: options.method ?? "GET",
2764
- headers: {
2765
- "Content-Type": "application/json",
2766
- "x-owney-api-key": this.owneyApiKey,
2767
- ...options.signature ? { Authorization: `Signature ${options.signature}` } : {}
2768
- },
2769
- body: options.body ? JSON.stringify(options.body) : void 0,
2770
- signal: controller.signal
2771
- });
2772
- const payload = await response.json().catch(() => null);
2773
- if (!response.ok) {
2774
- const error = providerError(payload, `HTTP_${response.status}`);
2775
- throw new YieldseekerApiError(
2776
- response.status,
2777
- error.code,
2778
- error.fields
2779
- );
2780
- }
2781
- if (payload && typeof payload === "object" && payload.success === true && "data" in payload) {
2782
- return payload.data;
2783
- }
2784
- return payload;
2785
- } catch (error) {
2786
- if (error instanceof YieldseekerApiError) throw error;
2787
- if (error instanceof DOMException && error.name === "AbortError") {
2788
- throw new YieldseekerApiError(408, "REQUEST_TIMEOUT");
2789
- }
2790
- throw new YieldseekerApiError(0, "NETWORK_ERROR", {
2791
- cause: error instanceof Error ? error.message : String(error)
2792
- });
2793
- } finally {
2794
- clearTimeout(timer);
2795
- }
2796
- }
2797
- };
2798
-
2799
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2800
- import { formatUnits, isAddress } from "viem";
2801
-
2802
- // src/agents/yieldseeker/yieldseeker.types.ts
2803
- var YIELDSEEKER_ASSET_METADATA = {
2804
- USDC: {
2805
- address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
2806
- decimals: 6
2807
- },
2808
- WETH: {
2809
- address: "0x4200000000000000000000000000000000000006",
2810
- decimals: 18
2811
- }
2812
- };
2813
-
2814
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2815
- function invalid(endpoint, detail) {
2816
- throw new OwneyError(
2817
- "AGENT_INVALID_RESPONSE",
2818
- `Yieldseeker returned an invalid ${endpoint} response: ${detail}.`,
2819
- { endpoint, detail },
2820
- "yieldseeker"
2821
- );
2822
- }
2823
- function raw(value, endpoint) {
2824
- if (typeof value !== "string" || !/^-?[0-9]+$/.test(value)) {
2825
- return invalid(endpoint, "expected a base-10 integer string");
2826
- }
2827
- return BigInt(value);
2828
- }
2829
- function decimal(value, decimals, endpoint) {
2830
- return formatUnits(raw(value, endpoint), decimals);
2831
- }
2832
- function usd(rawAmount, decimals, price) {
2833
- return Number(formatUnits(rawAmount, decimals)) * price;
2834
- }
2835
- function percent(value) {
2836
- const result = Number(value);
2837
- return Number.isFinite(result) ? result * 100 : 0;
2838
- }
2839
- var YIELDSEEKER_POSITIVE_YIELD_FEE_RATE = 0.1;
2840
- function publicApyAfterYieldseekerFee(value) {
2841
- const grossPercent = percent(value);
2842
- if (grossPercent <= 0) return grossPercent;
2843
- const netPercent = grossPercent * (1 - YIELDSEEKER_POSITIVE_YIELD_FEE_RATE);
2844
- return Math.round(netPercent * 1e12) / 1e12;
2845
- }
2846
- function riskAdjustedApyForDays(option, days) {
2847
- if (days === "7D") return option.riskAdjustedApy7dAverage;
2848
- if (days === "30D") return option.riskAdjustedApy30dAverage;
2849
- return (option.riskAdjustedApy7dAverage + option.riskAdjustedApy30dAverage) / 2;
2850
- }
2851
- function assetAddressValue(record, address) {
2852
- const entry = Object.entries(record).find(
2853
- ([key2]) => key2.toLowerCase() === address.toLowerCase()
2854
- );
2855
- return entry?.[1] ?? "0";
2856
- }
2857
- function position(value, asset, baseAssetDecimals) {
2858
- const option = value?.yieldOption;
2859
- if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !isAddress(option.address)) {
2860
- return invalid("yield positions", "missing vault metadata");
2861
- }
2862
- return {
2863
- chain: "BASE",
2864
- protocol: option.provider,
2865
- protocolId: option.address,
2866
- pool: option.name,
2867
- asset,
2868
- // `assetsRaw` is the ERC-4626 vault-share quantity, whose decimals can
2869
- // differ from the underlying asset. Yieldseeker already converts it to
2870
- // underlying base-asset units in `assetsBase`; pair that value with the
2871
- // snapshot's corresponding `baseAssetDecimals` for display. Keep the raw
2872
- // share quantity separately because withdraw-from-position expects it.
2873
- amount: decimal(
2874
- value.assetsBase,
2875
- baseAssetDecimals,
2876
- "yield positions"
2877
- ),
2878
- amountRaw: String(value.assetsRaw),
2879
- apy: percent(option.riskAdjustedApy),
2880
- tvl: Number(option.totalDepositsUsd),
2881
- liquidity: Number(option.withdrawableDepositsUsd)
2882
- };
2883
- }
2884
- function mapYieldseekerBalances(contexts) {
2885
- const tokens = [];
2886
- const assetBalances = [];
2887
- const positions = [];
2888
- let totalUsd = 0;
2889
- for (const context of contexts) {
2890
- const metadata = YIELDSEEKER_ASSET_METADATA[context.asset];
2891
- assetBalances.push({
2892
- chain: "BASE",
2893
- chainId: 8453,
2894
- asset: context.asset,
2895
- amount: decimal(context.snapshot.totalValueBase, context.snapshot.baseAssetDecimals, "snapshot")
2896
- });
2897
- const idle = assetAddressValue(
2898
- context.snapshot.tokenBalances,
2899
- metadata.address
2900
- );
2901
- tokens.push({
2902
- chain: "BASE",
2903
- chainId: 8453,
2904
- asset: context.asset,
2905
- amount: decimal(idle, metadata.decimals, "snapshot")
2906
- });
2907
- positions.push(
2908
- ...context.positions.map(
2909
- (entry) => position(
2910
- entry,
2911
- context.asset,
2912
- context.snapshot.baseAssetDecimals
2913
- )
2914
- )
2915
- );
2916
- totalUsd += usd(
2917
- raw(context.snapshot.totalValueBase, "snapshot"),
2918
- context.snapshot.baseAssetDecimals,
2919
- context.snapshot.baseAssetPriceUsd
2920
- );
2921
- }
2922
- return {
2923
- ...contexts.length === 1 ? { smartWallet: contexts[0].wallet.walletAddress } : {},
2924
- totalBalance: String(totalUsd),
2925
- totalBalanceAsset: "usdc",
2926
- assetBalances,
2927
- tokens,
2928
- positions
2929
- };
2930
- }
2931
- function mapYieldseekerEarnings(contexts) {
2932
- const tokens = [];
2933
- let lifetimeEarnings = 0;
2934
- for (const context of contexts) {
2935
- const amount = raw(context.snapshot.cumulativeYieldBase, "snapshot");
2936
- tokens.push({
2937
- chain: "BASE",
2938
- chainId: 8453,
2939
- asset: context.asset,
2940
- amount: formatUnits(amount, context.snapshot.baseAssetDecimals)
2941
- });
2942
- lifetimeEarnings += usd(
2943
- amount,
2944
- context.snapshot.baseAssetDecimals,
2945
- context.snapshot.baseAssetPriceUsd
2946
- );
2947
- }
2948
- return {
2949
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
2950
- lifetimeEarnings,
2951
- tokens
2952
- };
2953
- }
2954
- function apyForDays(snapshot, days) {
2955
- if (days === "7D") return percent(snapshot.apy7d);
2956
- if (days === "30D") return percent(snapshot.apy30d);
2957
- return percent((snapshot.apy7d + snapshot.apy30d) / 2);
2958
- }
2959
- function dailyApy(point) {
2960
- const total = raw(point.totalValueBase, "historic position");
2961
- const earned = raw(point.dailyYieldBase, "historic position");
2962
- const principal = total - earned;
2963
- if (principal <= 0n || earned === 0n) return 0;
2964
- return Number(earned) / Number(principal) * 365 * 100;
2965
- }
2966
- function aggregateHistory(contexts, dayCount) {
2967
- const byDate = /* @__PURE__ */ new Map();
2968
- for (const context of contexts) {
2969
- const points = context.historic?.dailyYieldSnapshots ?? [];
2970
- for (const point of points.slice(-dayCount)) {
2971
- const valueUsd = usd(
2972
- raw(point.totalValueBase, "historic position"),
2973
- point.baseAssetDecimals,
2974
- point.baseAssetPriceUsd
2975
- );
2976
- const current = byDate.get(point.date) ?? { weighted: 0, valueUsd: 0 };
2977
- current.weighted += dailyApy(point) * valueUsd;
2978
- current.valueUsd += valueUsd;
2979
- byDate.set(point.date, current);
2980
- }
2981
- }
2982
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
2983
- date,
2984
- apy: value.valueUsd > 0 ? value.weighted / value.valueUsd : 0
2985
- }));
2986
- }
2987
- function mapYieldseekerApy(walletAddress, contexts, days) {
2988
- let weighted = 0;
2989
- let totalUsd = 0;
2990
- const byAsset = {};
2991
- for (const context of contexts) {
2992
- const valueUsd = usd(
2993
- raw(context.snapshot.totalValueBase, "snapshot"),
2994
- context.snapshot.baseAssetDecimals,
2995
- context.snapshot.baseAssetPriceUsd
2996
- );
2997
- const apy = apyForDays(context.snapshot, days);
2998
- weighted += apy * valueUsd;
2999
- totalUsd += valueUsd;
3000
- byAsset[context.asset] = apy;
3001
- }
3002
- const dayCount = Number(days.slice(0, -1));
3003
- return {
3004
- walletAddress,
3005
- weightedApyAfterFee: totalUsd > 0 ? weighted / totalUsd : 0,
3006
- apyByChainAndAsset: { 8453: byAsset },
3007
- history: aggregateHistory(contexts, dayCount)
3008
- };
3009
- }
3010
- function actionType(value) {
3011
- const normalized = value.toLowerCase();
3012
- if (normalized.includes("deposit")) return "Deposit";
3013
- if (normalized.includes("withdraw")) return "Withdraw";
3014
- if (normalized.includes("yield") || normalized.includes("earn"))
3015
- return "Earned";
3016
- return "Rebalance";
3017
- }
3018
- function transactionHashes(details) {
3019
- if (!details) return [];
3020
- const values = [
3021
- details.transactionHash,
3022
- details.txHash,
3023
- ...Array.isArray(details.transactionHashes) ? details.transactionHashes : [],
3024
- ...Array.isArray(details.txHashes) ? details.txHashes : []
3025
- ];
3026
- return values.filter(
3027
- (value) => typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value)
3028
- ).filter((value, index, all) => all.indexOf(value) === index);
3029
- }
3030
- function actionEntry(action) {
3031
- if (action.actionType.toLowerCase().includes("withdraw")) return void 0;
3032
- return {
3033
- agent: "yieldseeker",
3034
- action: actionType(action.actionType),
3035
- date: action.createdDate,
3036
- oldApy: null,
3037
- newApy: null,
3038
- transactions: [
3039
- {
3040
- txHashes: transactionHashes(action.details),
3041
- chainId: 8453
3042
- }
3043
- ],
3044
- rebalanceLog: []
3045
- };
3046
- }
3047
- function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddresses) {
3048
- const from = movement.fromAddress.toLowerCase();
3049
- const to = movement.toAddress.toLowerCase();
3050
- const owner = ownerAddress.toLowerCase();
3051
- const agentWallet = wallet.walletAddress.toLowerCase();
3052
- const baseAsset = agent.assetAddress.toLowerCase();
3053
- if (movement.chainId !== agent.chainId || movement.assetAddress.toLowerCase() !== baseAsset) {
3054
- return void 0;
3055
- }
3056
- let action;
3057
- if (from === owner && to === agentWallet) {
3058
- action = "Top up";
3059
- } else if (from === agentWallet && to === owner) {
3060
- action = "Withdraw";
3061
- } else if (from === agentWallet && vaultAddresses.has(to)) {
3062
- action = "Deposit";
3063
- }
3064
- if (!action) return void 0;
3065
- return {
3066
- agent: "yieldseeker",
3067
- action,
3068
- date: movement.blockDate,
3069
- oldApy: null,
3070
- newApy: null,
3071
- transactions: [
3072
- {
3073
- txHashes: [movement.transactionHash],
3074
- chainId: agent.chainId,
3075
- tokenSymbol: asset,
3076
- amount: decimal(
3077
- movement.assetAmount,
3078
- YIELDSEEKER_ASSET_METADATA[asset].decimals,
3079
- "historic position"
3080
- )
3081
- }
3082
- ],
3083
- rebalanceLog: []
3084
- };
3085
- }
3086
- function mapYieldseekerHistory(contexts, options) {
3087
- const entries = contexts.flatMap((context) => {
3088
- const vaultAddresses = new Set(
3089
- context.positions.map(
3090
- (position2) => position2.yieldOption.address.toLowerCase()
3091
- )
3092
- );
3093
- return [
3094
- ...(context.historic?.movements ?? []).map(
3095
- (movement) => movementEntry(
3096
- movement,
3097
- context.wallet,
3098
- context.agent,
3099
- context.asset,
3100
- options.ownerAddress,
3101
- vaultAddresses
3102
- )
3103
- ),
3104
- ...(context.actions ?? []).map(actionEntry)
3105
- ].filter((entry) => entry !== void 0);
3106
- });
3107
- const filtered = entries.filter(
3108
- (entry) => (!options.fromDate || entry.date >= options.fromDate) && (!options.toDate || entry.date <= options.toDate)
3109
- ).filter((entry, index, all) => {
3110
- const transactionHash = entry.transactions[0]?.txHashes[0];
3111
- if (!transactionHash) return true;
3112
- return all.findIndex(
3113
- (candidate) => candidate.action === entry.action && candidate.transactions[0]?.txHashes[0] === transactionHash
3114
- ) === index;
3115
- }).sort((left, right) => right.date.localeCompare(left.date));
3116
- return {
3117
- data: filtered.slice(0, options.limit),
3118
- // v1 returns the whole action/movement collection and defines no cursor.
3119
- // Report a terminal page so callers never loop over the same prefix.
3120
- hasMore: false
3121
- };
3122
- }
3123
- function mapYieldseekerProfile(address, contexts) {
3124
- const protocols = /* @__PURE__ */ new Set();
3125
- for (const context of contexts) {
3126
- for (const current of context.positions) {
3127
- if (current.yieldOption?.provider) {
3128
- protocols.add(String(current.yieldOption.provider));
3129
- }
3130
- }
3131
- }
3132
- return {
3133
- address,
3134
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
3135
- chains: contexts.length > 0 ? [8453] : [],
3136
- hasActiveSessionKey: contexts.some(
3137
- (context) => context.wallet.initializedDate != null
3138
- ),
3139
- protocols: [...protocols]
3140
- };
3141
- }
3142
- function mapYieldseekerAgentApy(options, days) {
3143
- const perAsset = {};
3144
- const all = [];
3145
- for (const entry of options) {
3146
- const apys = entry.yieldOptions.map(
3147
- (option) => publicApyAfterYieldseekerFee(riskAdjustedApyForDays(option, days))
3148
- ).filter(Number.isFinite);
3149
- if (apys.length === 0) continue;
3150
- const average = apys.reduce((sum, value) => sum + value, 0) / apys.length;
3151
- perAsset[entry.asset] = average;
3152
- all.push(average);
3153
- }
3154
- return {
3155
- averageApy: all.length > 0 ? all.reduce((sum, value) => sum + value, 0) / all.length : 0,
3156
- detailedApys: { apyPerAsset: { 8453: perAsset } }
3157
- };
3158
- }
3159
-
3160
- // src/agents/yieldseeker/yieldseeker.agent.ts
3161
- var OWNEY_AGENT_NAME = "owney";
3162
- var YIELDSEEKER_USERNAME_PREFIX = "owney_";
3163
- var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
3164
- var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
3165
- function generateYieldseekerUsername() {
3166
- const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
3167
- return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
3168
- }
3169
- function isUsernameConflict(error) {
3170
- if (!(error instanceof YieldseekerApiError)) return false;
3171
- const code = error.providerCode.toUpperCase();
3172
- return code.includes("USERNAME") && (code.includes("TAKEN") || code.includes("EXIST") || code.includes("UNAVAILABLE") || code.includes("IN_USE"));
3173
- }
3174
- var YIELDSEEKER_AGENT_WALLET_ABI = [
3175
- {
3176
- type: "function",
3177
- name: "withdrawAssetToUser",
3178
- stateMutability: "nonpayable",
3179
- inputs: [
3180
- { name: "recipient", type: "address" },
3181
- { name: "asset", type: "address" },
3182
- { name: "amount", type: "uint256" }
3183
- ],
3184
- outputs: []
3185
- },
3186
- {
3187
- type: "function",
3188
- name: "withdrawAllAssetToUser",
3189
- stateMutability: "nonpayable",
3190
- inputs: [
3191
- { name: "recipient", type: "address" },
3192
- { name: "asset", type: "address" }
3193
- ],
3194
- outputs: []
3195
- }
3196
- ];
3197
- function query(params) {
3198
- const search = new URLSearchParams();
3199
- for (const [key2, value] of Object.entries(params)) {
3200
- if (value !== void 0) search.set(key2, String(value));
3201
- }
3202
- const encoded = search.toString();
3203
- return encoded ? `?${encoded}` : "";
3204
- }
3205
- var YieldseekerAgent = class {
3206
- id = "yieldseeker";
3207
- balanceComposition = "tokens-plus-positions";
3208
- supportedChainIds = [8453];
3209
- supportedAssets = [
3210
- {
3211
- chainId: 8453,
3212
- chain: "BASE",
3213
- assets: [
3214
- { symbol: "USDC", minDepositAmount: "10000000" },
3215
- { symbol: "WETH", minDepositAmount: "1" }
3216
- ]
3217
- }
3218
- ];
3219
- api;
3220
- auth;
3221
- transactionExecutor;
3222
- unwindReceiptWaiter;
3223
- agentContexts = /* @__PURE__ */ new Map();
3224
- users = /* @__PURE__ */ new Map();
3225
- pendingAgents = /* @__PURE__ */ new Map();
3226
- constructor(owneyApiKey, options = {}) {
3227
- this.api = new YieldseekerApiClient(
3228
- owneyApiKey,
3229
- options.baseUrl ?? getYieldseekerProxyBaseUrl(),
3230
- options.fetchFn
3231
- );
3232
- this.auth = new YieldseekerAuth(options.auth);
3233
- this.transactionExecutor = options.transactionExecutor;
3234
- this.unwindReceiptWaiter = options.unwindReceiptWaiter;
3235
- }
3236
- async disconnect() {
3237
- this.auth.clear();
3238
- for (const key2 of this.users.keys()) {
3239
- const [walletAddress, chainId] = key2.split(":");
3240
- clearYieldseekerIdentity(walletAddress, Number(chainId));
3241
- }
3242
- this.users.clear();
3243
- this.agentContexts.clear();
3244
- this.pendingAgents.clear();
3245
- }
3246
- async activateAgent(state, chainId, asset) {
3247
- this.assertChain(chainId);
3248
- const targetAsset = asset ?? "USDC";
3249
- this.assertAsset(targetAsset);
3250
- await this.ensureAgent(state, chainId, targetAsset);
3251
- }
3252
- async deposit(state, chainId, amount, asset, depositCallback) {
3253
- this.assertChain(chainId);
3254
- this.assertAsset(asset);
3255
- if (BigInt(amount) <= 0n) {
3256
- throw new OwneyError(
3257
- "DEPOSIT_AMOUNT_BELOW_MINIMUM",
3258
- "Yieldseeker deposits must be greater than zero.",
3259
- { amount, minDepositAmount: "1" },
3260
- this.id
3261
- );
3262
- }
3263
- const context = await this.ensureAgent(state, chainId, asset);
3264
- let txHash;
3265
- try {
3266
- if (depositCallback) {
3267
- provideDepositVerificationContext(depositCallback, {
3268
- agentId: "yieldseeker",
3269
- signature: await this.auth.getToken(state, chainId),
3270
- userId: context.user.userId,
3271
- yieldseekerAgentId: context.agent.agentId
3272
- });
3273
- txHash = await depositCallback(
3274
- context.wallet.walletAddress,
3275
- chainId,
3276
- amount
3277
- );
3278
- await this.waitForReceipt(state, chainId, txHash);
3279
- } else {
3280
- txHash = await this.submitTransaction(state, chainId, {
3281
- from: getAddress2(state.walletAddress),
3282
- to: YIELDSEEKER_ASSET_METADATA[asset].address,
3283
- data: encodeFunctionData({
3284
- abi: erc20Abi,
3285
- functionName: "transfer",
3286
- args: [getAddress2(context.wallet.walletAddress), BigInt(amount)]
3287
- }),
3288
- value: "0",
3289
- chainId
3290
- });
3291
- }
3292
- await this.deployAfterFunding(state, chainId, context);
3293
- } finally {
3294
- await this.refreshSnapshotAfterMovement(
3295
- state,
3296
- chainId,
3297
- context,
3298
- "deposit"
3299
- );
3300
- }
3301
- return {
3302
- txHash,
3303
- smartWallet: context.wallet.walletAddress,
3304
- amount
3305
- };
3306
- }
3307
- async withdraw(state, chainId, asset, amount) {
3308
- this.assertChain(chainId);
3309
- this.assertAsset(asset);
3310
- if (amount !== void 0 && BigInt(amount) <= 0n) {
3311
- throw new OwneyError(
3312
- "WITHDRAW_FAILED",
3313
- "Yieldseeker withdrawals must be greater than zero.",
3314
- { amount },
3315
- this.id
3316
- );
3317
- }
3318
- const context = await this.findAgent(state, chainId, asset);
3319
- if (!context) {
3320
- throw new OwneyError(
3321
- "WITHDRAW_INSUFFICIENT_BALANCE",
3322
- `No Yieldseeker ${asset} agent exists for this wallet.`,
3323
- { asset, available: "0" },
3324
- this.id
3325
- );
3326
- }
3327
- try {
3328
- const portfolio = await this.loadPortfolioContext(
3329
- state,
3330
- chainId,
3331
- context
3332
- );
3333
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3334
- const idleEntry = Object.entries(portfolio.snapshot.tokenBalances).find(
3335
- ([address]) => address.toLowerCase() === metadata.address.toLowerCase()
3336
- );
3337
- const idle = BigInt(idleEntry?.[1] ?? "0");
3338
- const deployed = portfolio.positions.reduce(
3339
- (total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
3340
- 0n
3341
- );
3342
- const totalAvailable = idle + deployed;
3343
- const requested = amount === void 0 ? totalAvailable : BigInt(amount);
3344
- if (requested > totalAvailable) {
3345
- throw new OwneyError(
3346
- "WITHDRAW_INSUFFICIENT_BALANCE",
3347
- `Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
3348
- {
3349
- asset,
3350
- requested: requested.toString(),
3351
- available: totalAvailable.toString()
3352
- },
3353
- this.id
3354
- );
3355
- }
3356
- let remaining = requested > idle ? requested - idle : 0n;
3357
- for (const position2 of portfolio.positions) {
3358
- if (remaining === 0n) break;
3359
- const available = BigInt(position2.withdrawableAssetsRaw);
3360
- if (available <= 0n) continue;
3361
- const assetsRaw = available < remaining ? available : remaining;
3362
- const response = await this.walletRequest(
3363
- state,
3364
- chainId,
3365
- this.agentPath(context, "withdraw-from-position"),
3366
- {
3367
- method: "POST",
3368
- body: {
3369
- chainId,
3370
- vaultAddress: position2.yieldOption.address,
3371
- assetsRaw: assetsRaw.toString()
3372
- }
3373
- }
3374
- );
3375
- if (!this.isTransactionHash(response?.transactionHash)) {
3376
- throw this.invalidResponse("position withdrawal");
3377
- }
3378
- await this.waitForReceipt(state, chainId, response.transactionHash);
3379
- remaining -= assetsRaw;
3380
- }
3381
- if (remaining > 0n) {
3382
- throw this.invalidResponse("yield positions", {
3383
- reason: "Withdrawable positions could not cover the request.",
3384
- remaining: remaining.toString()
3385
- });
3386
- }
3387
- const account = getAddress2(state.walletAddress);
3388
- const txHash = await this.submitTransaction(state, chainId, {
3389
- from: account,
3390
- to: getAddress2(context.wallet.walletAddress),
3391
- data: amount === void 0 ? encodeFunctionData({
3392
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3393
- functionName: "withdrawAllAssetToUser",
3394
- args: [account, metadata.address]
3395
- }) : encodeFunctionData({
3396
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3397
- functionName: "withdrawAssetToUser",
3398
- args: [account, metadata.address, requested]
3399
- }),
3400
- value: "0",
3401
- chainId
3402
- });
3403
- return {
3404
- txHash,
3405
- type: amount === void 0 ? "full" : "partial",
3406
- amount: requested.toString()
3407
- };
3408
- } finally {
3409
- await this.refreshSnapshotAfterMovement(
3410
- state,
3411
- chainId,
3412
- context,
3413
- "withdrawal"
3414
- );
3415
- }
3416
- }
3417
- async getBalances(state, chainId) {
3418
- this.assertChain(chainId);
3419
- return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, {}));
3420
- }
3421
- async getEarnings(state, chainId) {
3422
- this.assertChain(chainId);
3423
- return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
3424
- }
3425
- async getAccountApy(state, chainId, days, tokenSymbol) {
3426
- this.assertChain(chainId);
3427
- const asset = tokenSymbol?.toUpperCase();
3428
- if (asset !== void 0) this.assertAsset(asset);
3429
- const contexts = await this.loadPortfolio(state, chainId, {
3430
- ...asset ? { asset } : {},
3431
- historic: true
3432
- });
3433
- return mapYieldseekerApy(state.walletAddress, contexts, days);
3434
- }
3435
- async getHistory(state, chainId, options) {
3436
- this.assertChain(chainId);
3437
- const asset = options?.tokenSymbol?.toUpperCase();
3438
- if (asset !== void 0) this.assertAsset(asset);
3439
- const contexts = await this.loadPortfolio(state, chainId, {
3440
- ...asset ? { asset } : {},
3441
- historic: true,
3442
- actions: true
3443
- });
3444
- return mapYieldseekerHistory(contexts, {
3445
- limit: options?.limit ?? 10,
3446
- ownerAddress: state.walletAddress,
3447
- ...options?.fromDate ? { fromDate: options.fromDate } : {},
3448
- ...options?.toDate ? { toDate: options.toDate } : {}
3449
- });
3450
- }
3451
- async getUserProfile(state, chainId) {
3452
- this.assertChain(chainId);
3453
- return mapYieldseekerProfile(
3454
- state.walletAddress,
3455
- await this.loadPortfolio(state, chainId, {})
3456
- );
3457
- }
3458
- async getAgentApy(days, options) {
3459
- this.assertOptionalChain(options?.chainId);
3460
- const requested = options?.tokenSymbol?.toUpperCase();
3461
- if (requested !== void 0) this.assertAsset(requested);
3462
- const assets = requested ? [requested] : ["USDC", "WETH"];
3463
- const values = await Promise.all(
3464
- assets.map(async (asset) => {
3465
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3466
- const response = await this.api.request(
3467
- `/chains/8453/assets/${metadata.address}/yield-options`
3468
- );
3469
- if (!Array.isArray(response?.yieldOptions)) {
3470
- throw this.invalidResponse("yield options");
3471
- }
3472
- return { asset, yieldOptions: response.yieldOptions };
3473
- })
3474
- );
3475
- return mapYieldseekerAgentApy(values, days);
3476
- }
3477
- userKey(state, chainId) {
3478
- return `${state.walletAddress.toLowerCase()}:${chainId}`;
3479
- }
3480
- contextKey(state, chainId, asset) {
3481
- return `${this.userKey(state, chainId)}:${asset}`;
3482
- }
3483
- async resolveUser(state, chainId) {
3484
- const key2 = this.userKey(state, chainId);
3485
- const inMemory = this.users.get(key2);
3486
- if (inMemory) return inMemory;
3487
- const persisted = readYieldseekerIdentity(state.walletAddress, chainId);
3488
- if (persisted) {
3489
- this.users.set(key2, persisted);
3490
- return persisted;
3491
- }
3492
- const walletAddress = getAddress2(state.walletAddress);
3493
- let user = null;
3494
- try {
3495
- const login = await this.providerRequest(
3496
- state,
3497
- chainId,
3498
- "/users/login-with-wallet",
3499
- { method: "POST", body: { walletAddress } }
3500
- );
3501
- user = login?.user ?? null;
3502
- if (!user) {
3503
- throw this.invalidResponse("wallet login", {
3504
- reason: "A successful login returned no user."
3505
- });
3506
- }
3507
- } catch (error) {
3508
- if (!(error instanceof YieldseekerApiError) || error.providerCode !== "NO_USER") {
3509
- if (error instanceof OwneyError) throw error;
3510
- throw this.mapApiError(error);
3511
- }
3512
- let created;
3513
- for (let attempt = 0; attempt < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS; attempt += 1) {
3514
- try {
3515
- created = await this.providerRequest(
3516
- state,
3517
- chainId,
3518
- "/users",
3519
- {
3520
- method: "POST",
3521
- body: {
3522
- walletAddress,
3523
- username: generateYieldseekerUsername()
3524
- }
3525
- }
3526
- );
3527
- break;
3528
- } catch (createError) {
3529
- const canRetry = isUsernameConflict(createError) && attempt + 1 < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS;
3530
- if (canRetry) continue;
3531
- throw this.mapApiError(createError);
3532
- }
3533
- }
3534
- user = created?.user ?? null;
3535
- }
3536
- if (!user || !/^[a-zA-Z0-9_-]{1,128}$/.test(user.userId)) {
3537
- throw this.invalidResponse("wallet identity");
3538
- }
3539
- const resolved = { userId: user.userId };
3540
- this.users.set(key2, resolved);
3541
- writeYieldseekerIdentity(state.walletAddress, chainId, resolved.userId);
3542
- return resolved;
3543
- }
3544
- forgetUser(state, chainId) {
3545
- this.users.delete(this.userKey(state, chainId));
3546
- clearYieldseekerIdentity(state.walletAddress, chainId);
3547
- }
3548
- async ensureAgent(state, chainId, asset) {
3549
- const key2 = this.contextKey(state, chainId, asset);
3550
- const cached = this.agentContexts.get(key2);
3551
- if (cached) return cached;
3552
- const pending = this.pendingAgents.get(key2);
3553
- if (pending) return pending;
3554
- const request = this.resolveAgent(state, chainId, asset, true).then(
3555
- (context) => {
3556
- if (!context) throw this.invalidResponse("agent creation");
3557
- this.agentContexts.set(key2, context);
3558
- return context;
3559
- }
3560
- );
3561
- this.pendingAgents.set(key2, request);
3562
- try {
3563
- return await request;
3564
- } finally {
3565
- this.pendingAgents.delete(key2);
3566
- }
3567
- }
3568
- async findAgent(state, chainId, asset) {
3569
- const key2 = this.contextKey(state, chainId, asset);
3570
- const cached = this.agentContexts.get(key2);
3571
- if (cached) return cached;
3572
- const context = await this.resolveAgent(state, chainId, asset, false);
3573
- if (context) this.agentContexts.set(key2, context);
3574
- return context;
3575
- }
3576
- async resolveAgent(state, chainId, asset, createIfMissing) {
3577
- const user = await this.resolveUser(state, chainId);
3578
- const response = await this.walletRequest(
3579
- state,
3580
- chainId,
3581
- `/users/${user.userId}/agents`
3582
- );
3583
- if (!Array.isArray(response?.agents)) {
3584
- throw this.invalidResponse("agent list");
3585
- }
3586
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3587
- let agent = response.agents.find(
3588
- (candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
3589
- );
3590
- if (!agent && createIfMissing) {
3591
- const created = await this.walletRequest(
3592
- state,
3593
- chainId,
3594
- `/users/${user.userId}/agents`,
3595
- {
3596
- method: "POST",
3597
- body: {
3598
- name: OWNEY_AGENT_NAME,
3599
- emoji: "\u{1F989}",
3600
- chainId,
3601
- assetAddress: metadata.address,
3602
- type: "vault",
3603
- rulePreset: null
3604
- }
3605
- }
3606
- );
3607
- agent = created?.agent;
3608
- }
3609
- if (!agent) return null;
3610
- this.assertAgent(agent);
3611
- const walletResponse = await this.walletRequest(
3612
- state,
3613
- chainId,
3614
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3615
- );
3616
- if (!walletResponse?.agentWallet || !isAddress2(walletResponse.agentWallet.walletAddress)) {
3617
- throw this.invalidResponse("agent wallet");
3618
- }
3619
- return { user, agent, wallet: walletResponse.agentWallet, asset };
3620
- }
3621
- async loadPortfolio(state, chainId, options) {
3622
- const user = await this.resolveUser(state, chainId);
3623
- const response = await this.walletRequest(
3624
- state,
3625
- chainId,
3626
- `/users/${user.userId}/agents`
3627
- );
3628
- if (!Array.isArray(response?.agents)) {
3629
- throw this.invalidResponse("agent list");
3630
- }
3631
- const contexts = [];
3632
- for (const agent of response.agents) {
3633
- const asset = this.assetForAgent(agent);
3634
- if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
3635
- continue;
3636
- }
3637
- this.assertAgent(agent);
3638
- const walletResponse = await this.walletRequest(
3639
- state,
3640
- chainId,
3641
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3642
- );
3643
- if (!walletResponse?.agentWallet || !isAddress2(walletResponse.agentWallet.walletAddress)) {
3644
- throw this.invalidResponse("agent wallet");
3645
- }
3646
- const context = {
3647
- user,
3648
- agent,
3649
- wallet: walletResponse.agentWallet,
3650
- asset
3651
- };
3652
- this.agentContexts.set(this.contextKey(state, chainId, asset), context);
3653
- contexts.push(context);
3654
- }
3655
- return Promise.all(
3656
- contexts.map(
3657
- (context) => this.loadPortfolioContext(state, chainId, context, options)
3658
- )
3659
- );
3660
- }
3661
- async loadPortfolioContext(state, chainId, context, options = {}) {
3662
- const [snapshot, positions, historic, actions] = await Promise.all([
3663
- this.walletRequest(
3664
- state,
3665
- chainId,
3666
- `${this.agentPath(context, "snapshot")}${query({
3667
- shouldOnlyUseRecentValue: true,
3668
- shouldAllowStaleOnError: true
3669
- })}`
3670
- ),
3671
- this.walletRequest(
3672
- state,
3673
- chainId,
3674
- this.agentPath(context, "yield-positions")
3675
- ),
3676
- options.historic ? this.walletRequest(
3677
- state,
3678
- chainId,
3679
- this.agentPath(context, "wallet/historic-position")
3680
- ) : Promise.resolve(void 0),
3681
- options.actions ? this.walletRequest(
3682
- state,
3683
- chainId,
3684
- this.agentPath(context, "actions")
3685
- ) : Promise.resolve(void 0)
3686
- ]);
3687
- if (!snapshot?.agentSnapshot) {
3688
- throw this.invalidResponse("agent snapshot");
3689
- }
3690
- if (!Array.isArray(positions?.yieldPositions)) {
3691
- throw this.invalidResponse("yield positions");
3692
- }
3693
- return {
3694
- ...context,
3695
- snapshot: snapshot.agentSnapshot,
3696
- positions: positions.yieldPositions,
3697
- ...historic?.position ? { historic: historic.position } : {},
3698
- ...actions?.actions ? { actions: actions.actions } : {}
3699
- };
3700
- }
3701
- async deployAfterFunding(state, chainId, context) {
3702
- if (context.wallet.initializedDate != null) return;
3703
- try {
3704
- const deployed = await this.walletRequest(
3705
- state,
3706
- chainId,
3707
- this.agentPath(context, "deploy"),
3708
- { method: "POST", body: {} }
3709
- );
3710
- if (deployed?.agentWallet) {
3711
- context.wallet = deployed.agentWallet;
3712
- }
3713
- } catch (error) {
3714
- console.warn(
3715
- "[owney-sdk] Yieldseeker deposit is funded but not deployable yet:",
3716
- error
3717
- );
3718
- }
3719
- }
3720
- async refreshSnapshotAfterMovement(state, chainId, context, movement) {
3721
- try {
3722
- const response = await this.walletRequest(
3723
- state,
3724
- chainId,
3725
- `${this.agentPath(context, "snapshot")}${query({
3726
- shouldForceRefresh: true
3727
- })}`
3728
- );
3729
- if (!response?.agentSnapshot) {
3730
- throw this.invalidResponse("agent snapshot refresh");
3731
- }
3732
- } catch (error) {
3733
- console.warn(
3734
- `[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
3735
- error
3736
- );
3737
- }
3738
- }
3739
- agentPath(context, suffix) {
3740
- return `/users/${context.user.userId}/agents/${context.agent.agentId}/${suffix}`;
3741
- }
3742
- async walletRequest(state, chainId, path, options = {}) {
3743
- try {
3744
- return await this.providerRequest(state, chainId, path, options);
3745
- } catch (error) {
3746
- throw this.mapApiError(error);
3747
- }
3748
- }
3749
- async providerRequest(state, chainId, path, options = {}) {
3750
- this.assertChain(chainId);
3751
- const request = (signature2) => this.api.request(path, {
3752
- ...options,
3753
- signature: signature2
3754
- });
3755
- let signature = await this.auth.getToken(state, chainId);
3756
- try {
3757
- return await request(signature);
3758
- } catch (error) {
3759
- if (!(error instanceof YieldseekerApiError)) throw error;
3760
- if (error.providerCode === "NO_USER") throw error;
3761
- if (!error.isAuthenticationError) throw error;
3762
- this.auth.clear(state, chainId);
3763
- signature = await this.auth.getToken(state, chainId);
3764
- try {
3765
- return await request(signature);
3766
- } catch (retryError) {
3767
- if (retryError instanceof YieldseekerApiError && retryError.isAuthenticationError) {
3768
- this.forgetUser(state, chainId);
3769
- }
3770
- throw retryError;
3771
- }
3772
- }
3773
- }
3774
- mapApiError(error) {
3775
- if (!(error instanceof YieldseekerApiError)) {
3776
- return new OwneyError(
3777
- "AGENT_API_ERROR",
3778
- "Yieldseeker request failed.",
3779
- { cause: error instanceof Error ? error.message : String(error) },
3780
- this.id
3781
- );
3782
- }
3783
- const code = error.isAuthenticationError ? "AGENT_AUTH_FAILED" : error.providerCode === "REQUEST_TIMEOUT" ? "AGENT_TIMEOUT" : "AGENT_API_ERROR";
3784
- return new OwneyError(
3785
- code,
3786
- `Yieldseeker request failed: ${error.providerCode}.`,
3787
- {
3788
- statusCode: error.status,
3789
- providerCode: error.providerCode,
3790
- ...error.responseFields ? { fields: error.responseFields } : {}
3791
- },
3792
- this.id
3793
- );
3794
- }
3795
- async submitTransaction(state, chainId, transaction) {
3796
- if (this.transactionExecutor) {
3797
- return this.transactionExecutor(state, chainId, transaction);
3798
- }
3799
- this.assertTransaction(transaction, state, chainId);
3800
- const account = getAddress2(state.walletAddress);
3801
- const walletClient = createWalletClient2({
3802
- account,
3803
- chain: base3,
3804
- transport: custom2(state.provider)
3805
- });
3806
- const publicClient = createPublicClient3({
3807
- chain: base3,
3808
- transport: custom2(state.provider)
3809
- });
3810
- await ensureWalletOnChain(
3811
- publicClient,
3812
- walletClient,
3813
- 8453
3814
- );
3815
- const hash = await walletClient.sendTransaction({
3816
- account,
3817
- chain: base3,
3818
- to: getAddress2(transaction.to),
3819
- data: transaction.data,
3820
- value: BigInt(transaction.value)
3821
- });
3822
- const receipt = await publicClient.waitForTransactionReceipt({
3823
- hash,
3824
- confirmations: 1
3825
- });
3826
- if (receipt.status !== "success") {
3827
- throw new OwneyError(
3828
- "AGENT_TRANSACTION_REVERTED",
3829
- `Yieldseeker transaction reverted (${hash}).`,
3830
- { transactionHash: hash },
3831
- this.id
3832
- );
3833
- }
3834
- return hash;
3835
- }
3836
- async waitForReceipt(state, chainId, transactionHash) {
3837
- if (this.unwindReceiptWaiter) {
3838
- await this.unwindReceiptWaiter(state, chainId, transactionHash);
3839
- return;
3840
- }
3841
- const publicClient = createPublicClient3({
3842
- chain: base3,
3843
- transport: custom2(state.provider)
3844
- });
3845
- const receipt = await publicClient.waitForTransactionReceipt({
3846
- hash: transactionHash,
3847
- confirmations: 1
3848
- });
3849
- if (receipt.status !== "success") {
3850
- throw new OwneyError(
3851
- "AGENT_TRANSACTION_REVERTED",
3852
- `Yieldseeker transaction reverted (${transactionHash}).`,
3853
- { transactionHash },
3854
- this.id
3855
- );
3856
- }
3857
- }
3858
- assertTransaction(transaction, state, chainId) {
3859
- if (!transaction || typeof transaction.from !== "string" || !isAddress2(transaction.from) || typeof transaction.to !== "string" || !isAddress2(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 || getAddress2(transaction.from) !== getAddress2(state.walletAddress)) {
3860
- throw this.invalidResponse("transaction");
3861
- }
3862
- }
3863
- assertAgent(agent) {
3864
- if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !isAddress2(agent.assetAddress) || agent.chainId !== 8453) {
3865
- throw this.invalidResponse("agent");
3866
- }
3867
- }
3868
- isOwneyAgent(agent) {
3869
- return typeof agent.name === "string" && agent.name.trim().toLowerCase() === OWNEY_AGENT_NAME;
3870
- }
3871
- assetForAgent(agent) {
3872
- for (const asset of ["USDC", "WETH"]) {
3873
- if (agent.assetAddress.toLowerCase() === YIELDSEEKER_ASSET_METADATA[asset].address.toLowerCase()) {
3874
- return asset;
3875
- }
3876
- }
3877
- return null;
3878
- }
3879
- isTransactionHash(value) {
3880
- return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
3881
- }
3882
- assertChain(chainId) {
3883
- if (chainId !== 8453) {
3884
- throw new OwneyError(
3885
- "CHAIN_UNSUPPORTED",
3886
- `Yieldseeker does not support chain ${chainId}.`,
3887
- { chainId, supportedChainIds: [8453] },
3888
- this.id
3889
- );
3890
- }
3891
- }
3892
- assertOptionalChain(chainId) {
3893
- if (chainId !== void 0) this.assertChain(chainId);
3894
- }
3895
- assertAsset(asset) {
3896
- if (asset !== "USDC" && asset !== "WETH") {
3897
- throw new OwneyError(
3898
- "ASSET_UNSUPPORTED",
3899
- `Yieldseeker does not support asset ${asset} in the Owney rollout.`,
3900
- {
3901
- asset,
3902
- supportedAssets: ["USDC", "WETH"],
3903
- providerAlsoAdvertises: ["cbBTC"]
3904
- },
3905
- this.id
3906
- );
3907
- }
3908
- }
3909
- invalidResponse(operation, details = {}) {
3910
- return new OwneyError(
3911
- "AGENT_INVALID_RESPONSE",
3912
- `Yieldseeker returned an invalid ${operation} response.`,
3913
- details,
3914
- this.id
3915
- );
3916
- }
3917
- };
3918
-
3919
- // src/lib/routing-api.ts
3920
- var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
3921
- async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
3922
- const url = `${baseUrl}/api/v1/agent/org-config`;
3923
- try {
3924
- const res = await fetch(url, {
3925
- method: "GET",
3926
- headers: {
3927
- "Content-Type": "application/json",
3928
- "x-owney-api-key": `${apiKey}`
3929
- }
3930
- });
3931
- if (!res.ok) {
3932
- if (res.status !== 404) {
3933
- console.warn(
3934
- `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
3935
- );
3936
- }
3937
- return null;
3938
- }
3939
- const json = await res.json();
3940
- const policy = json.success ? json.data ?? null : null;
3941
- debugLog(
3942
- "owney-sdk",
3943
- policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
3944
- policy ?? void 0
3945
- );
3946
- return policy;
3947
- } catch (error) {
3948
- console.warn(
3949
- "[owney-sdk] Could not read org agent config (non-fatal):",
3950
- error instanceof Error ? error.message : String(error)
3951
- );
3952
- return null;
3953
- }
3954
- }
3955
- async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
3956
- const url = `${baseUrl}/api/v1/agent/keys`;
3957
- const res = await fetch(url, {
3958
- method: "GET",
3959
- headers: {
3960
- "Content-Type": "application/json",
3961
- "x-owney-api-key": `${apiKey}`
3962
- }
3963
- });
3964
- if (!res.ok) {
3965
- const text = await res.text().catch(() => "");
3966
- throw new OwneyError(
3967
- "API_ROUTING_ERROR",
3968
- `Routing API error ${res.status}: ${text}`,
3969
- { statusCode: res.status, responseBody: text }
3970
- );
3971
- }
3972
- const json = await res.json();
3973
- if (!json.success) {
3974
- throw new OwneyError(
3975
- "API_ROUTING_FAILED",
3976
- `Routing API request failed: ${json.message}`,
3977
- { message: json.message }
3978
- );
3979
- }
3980
- return json.data;
3981
- }
3982
-
3983
- // src/lib/health-report.ts
3984
- var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
3985
- async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL3) {
3986
- try {
3987
- await fetch(`${baseUrl}/api/v1/agent/health-report`, {
3988
- method: "POST",
3989
- headers: {
3990
- "Content-Type": "application/json",
3991
- "x-owney-api-key": apiKey
3992
- },
3993
- body: JSON.stringify({
3994
- agent_type: agentType,
3995
- error_code: errorCode,
3996
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
3997
- })
3998
- });
3999
- } catch (err) {
4000
- console.warn(
4001
- `[owney-sdk] health-report failed for agent "${agentType}":`,
4002
- err instanceof Error ? err.message : err
4003
- );
4004
- }
4005
- }
4006
- async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
4007
- try {
4008
- return await fn();
4009
- } catch (err) {
4010
- const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
4011
- void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
4012
- throw err;
4013
- }
4014
- }
4015
-
4016
- // src/lib/helpers/withdraw-helper.ts
4017
- import { parseUnits } from "viem";
4018
- function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
4019
- const target = asset.toUpperCase();
4020
- return agents.map((agent) => {
4021
- const agentBalance = aggregated[agent.id];
4022
- const tokenBalance = agentBalance?.tokens.find(
4023
- (t) => t.chainId === chainId && t.asset.toUpperCase() === target
4024
- );
4025
- let balance = tokenBalance ? parseUnits(tokenBalance.amount, decimals) : 0n;
4026
- if (agent.balanceComposition === "tokens-plus-positions") {
4027
- const chainNameById = {
4028
- 1: "ETHEREUM",
4029
- 8453: "BASE",
4030
- 42161: "ARBITRUM"
4031
- };
4032
- const targetChain = chainNameById[chainId];
4033
- for (const position2 of agentBalance?.positions ?? []) {
4034
- const positionChain = position2.chain.trim().toUpperCase();
4035
- const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
4036
- if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
4037
- if (position2.amountRaw !== void 0) {
4038
- try {
4039
- balance += BigInt(position2.amountRaw);
4040
- continue;
4041
- } catch {
4042
- }
4043
- }
4044
- balance += parseUnits(position2.amount, decimals);
4045
- }
4046
- }
4047
- return { agent, balance };
2447
+ args: [owner, PERMIT2_ADDRESS]
4048
2448
  });
4049
2449
  }
4050
- function planProportionalShares(balances, requested, totalAvailable) {
4051
- const plans = balances.map(({ agent, balance }) => ({
4052
- agent,
4053
- balance,
4054
- planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
4055
- }));
4056
- const assigned = plans.reduce((s, p) => s + p.planned, 0n);
4057
- let remainder = requested - assigned;
4058
- const byHeadroom = [...plans].sort((a, b) => {
4059
- const diff = b.balance - b.planned - (a.balance - a.planned);
4060
- return diff > 0n ? 1 : diff < 0n ? -1 : 0;
2450
+ async function readErc20Balance(publicClient, token, owner) {
2451
+ return publicClient.readContract({
2452
+ address: token,
2453
+ abi: ERC20_ALLOWANCE_ABI,
2454
+ functionName: "balanceOf",
2455
+ args: [owner]
4061
2456
  });
4062
- for (const p of byHeadroom) {
4063
- if (remainder === 0n) break;
4064
- const headroom = p.balance - p.planned;
4065
- if (headroom <= 0n) continue;
4066
- const take = headroom < remainder ? headroom : remainder;
4067
- p.planned += take;
4068
- remainder -= take;
4069
- }
4070
- return plans;
4071
2457
  }
4072
- function planDisabledDrain(disabled, requested) {
4073
- const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
4074
- (a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
4075
- );
4076
- const plans = [];
4077
- let remaining = requested;
4078
- for (const { agent, balance } of sorted) {
4079
- if (remaining === 0n) {
4080
- plans.push({ agent, balance, planned: 0n });
4081
- continue;
4082
- }
4083
- const take = balance < remaining ? balance : remaining;
4084
- plans.push({ agent, balance, planned: take });
4085
- remaining -= take;
4086
- }
4087
- return { plans, remaining };
2458
+
2459
+ // src/lib/chain-guard.ts
2460
+ var CHAIN_NAMES = {
2461
+ 1: "Ethereum",
2462
+ 8453: "Base",
2463
+ 42161: "Arbitrum"
2464
+ };
2465
+ function chainName(chainId) {
2466
+ return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
4088
2467
  }
4089
- function redistributeShare(plans, fromIndex, amount, candidatePool) {
4090
- const pool = candidatePool ?? plans.slice(fromIndex + 1);
4091
- const candidates = pool.filter((c) => c.balance - c.planned > 0n);
4092
- const totalHeadroom = candidates.reduce(
4093
- (s, c) => s + (c.balance - c.planned),
4094
- 0n
4095
- );
4096
- if (totalHeadroom === 0n) return;
4097
- let distributed = 0n;
4098
- for (const c of candidates) {
4099
- const headroom = c.balance - c.planned;
4100
- const proportional = headroom * amount / totalHeadroom;
4101
- const give = proportional > headroom ? headroom : proportional;
4102
- c.planned += give;
4103
- distributed += give;
2468
+ async function ensureWalletOnChain(pub, wallet, expected) {
2469
+ const actual = await pub.getChainId();
2470
+ if (actual === expected) return;
2471
+ try {
2472
+ await wallet.switchChain({ id: expected });
2473
+ } catch (error) {
2474
+ throw new OwneyError(
2475
+ "CHAIN_MISMATCH",
2476
+ `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2477
+ {
2478
+ expectedChainId: expected,
2479
+ actualChainId: actual,
2480
+ cause: error instanceof Error ? error.message : String(error)
2481
+ }
2482
+ );
4104
2483
  }
4105
- let leftover = amount - distributed;
4106
- for (const c of candidates) {
4107
- if (leftover === 0n) break;
4108
- const headroom = c.balance - c.planned;
4109
- if (headroom <= 0n) continue;
4110
- const take = headroom < leftover ? headroom : leftover;
4111
- c.planned += take;
4112
- leftover -= take;
2484
+ const after = await pub.getChainId();
2485
+ if (after !== expected) {
2486
+ throw new OwneyError(
2487
+ "CHAIN_MISMATCH",
2488
+ `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2489
+ { expectedChainId: expected, actualChainId: after }
2490
+ );
4113
2491
  }
4114
2492
  }
4115
- function sumWithdrawnAmount(results) {
4116
- return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
4117
- }
4118
2493
 
4119
- // src/lib/helpers/account-apy-helper.ts
4120
- function balanceForApyScope(balance, chainId, tokenSymbol) {
4121
- if (!tokenSymbol) {
4122
- const total = Number(balance.totalBalance);
4123
- return Number.isFinite(total) && total > 0 ? total : 0;
4124
- }
4125
- const normalizedToken = tokenSymbol.toUpperCase();
4126
- return balance.tokens.reduce((total, token) => {
4127
- if (Number(token.chainId) !== chainId || String(token.asset).toUpperCase() !== normalizedToken) {
4128
- return total;
4129
- }
4130
- const amount = Number(token.amount);
4131
- return Number.isFinite(amount) && amount > 0 ? total + amount : total;
4132
- }, 0);
4133
- }
4134
- function aggregateApyHistory(agentApys, agentBalances) {
4135
- const byDate = /* @__PURE__ */ new Map();
4136
- for (const [id, accountApy] of Object.entries(agentApys)) {
4137
- const balance = agentBalances[id] ?? 0;
4138
- if (!Number.isFinite(balance) || balance <= 0) continue;
4139
- for (const point of accountApy.history ?? []) {
4140
- const apy = Number(point.apy);
4141
- if (!point.date || !Number.isFinite(apy)) continue;
4142
- const current = byDate.get(point.date) ?? { weightedSum: 0, weight: 0 };
4143
- current.weightedSum += apy * balance;
4144
- current.weight += balance;
4145
- byDate.set(point.date, current);
2494
+ // src/lib/sponsored-deposit.ts
2495
+ var AUTH_WINDOW_SECONDS = 15 * 60;
2496
+ function makeSponsoredDepositCallback(deps) {
2497
+ const post = deps.httpPost ?? postSponsorTransferAuth;
2498
+ return async (smartWallet, chainId, amount) => {
2499
+ const cid = chainId;
2500
+ const token = deps.tokenAddressByChain[cid];
2501
+ if (!token) {
2502
+ throw new OwneyError(
2503
+ "CHAIN_UNSUPPORTED",
2504
+ `No sponsored token configured for chain ${chainId}`
2505
+ );
4146
2506
  }
4147
- }
4148
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
4149
- date,
4150
- apy: value.weightedSum / value.weight
4151
- }));
4152
- }
4153
- function aggregateApyByChainAndAsset(agentApys, agentBalances) {
4154
- const sums = {};
4155
- const weights = {};
4156
- for (const id of Object.keys(agentApys)) {
4157
- const cells = agentApys[id].apyByChainAndAsset;
4158
- const balance = agentBalances[id] ?? 0;
4159
- if (!cells || balance <= 0) continue;
4160
- for (const [chainKey, perAsset] of Object.entries(cells)) {
4161
- if (!perAsset) continue;
4162
- const chainId = Number(chainKey);
4163
- for (const [asset, apyValue] of Object.entries(perAsset)) {
4164
- const apy = Number(apyValue ?? 0);
4165
- if (apy === 0) continue;
4166
- sums[chainId] ??= {};
4167
- weights[chainId] ??= {};
4168
- sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
4169
- weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2507
+ const pub = deps.getPublicClient(cid);
2508
+ const wallet = deps.getWalletClient(cid);
2509
+ await ensureWalletOnChain(pub, wallet, cid);
2510
+ try {
2511
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2512
+ if (balance < BigInt(amount)) {
2513
+ throw new OwneyError(
2514
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2515
+ "Insufficient balance for this deposit.",
2516
+ { token, chainId: cid, balance: balance.toString(), amount }
2517
+ );
4170
2518
  }
2519
+ } catch (err) {
2520
+ if (err instanceof OwneyError) throw err;
2521
+ console.warn(
2522
+ "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2523
+ err instanceof Error ? err.message : String(err)
2524
+ );
4171
2525
  }
4172
- }
4173
- const out = {};
4174
- for (const chainKey of Object.keys(sums)) {
4175
- const chainId = Number(chainKey);
4176
- const perAssetOut = {};
4177
- for (const asset of Object.keys(sums[chainId])) {
4178
- const w = weights[chainId][asset];
4179
- if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
4180
- }
4181
- if (Object.keys(perAssetOut).length > 0) {
4182
- out[chainId] = perAssetOut;
4183
- }
4184
- }
4185
- return out;
2526
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2527
+ const validAfter = 0n;
2528
+ const validBefore = BigInt(
2529
+ Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2530
+ );
2531
+ const nonce = randomAuthNonce();
2532
+ const typedData = buildTransferWithAuthorizationTypedData({
2533
+ token,
2534
+ chainId: cid,
2535
+ tokenName,
2536
+ tokenVersion,
2537
+ message: {
2538
+ from: deps.ownerAddress,
2539
+ to: smartWallet,
2540
+ value: BigInt(amount),
2541
+ validAfter,
2542
+ validBefore,
2543
+ nonce
2544
+ }
2545
+ });
2546
+ const authSignature = await wallet.signTypedData({
2547
+ account: deps.ownerAddress,
2548
+ ...typedData
2549
+ });
2550
+ deps.onApproved?.();
2551
+ const result = await post({
2552
+ baseUrl: deps.baseUrl,
2553
+ apiKey: deps.apiKey,
2554
+ body: {
2555
+ chainId: cid,
2556
+ token,
2557
+ from: deps.ownerAddress,
2558
+ to: smartWallet,
2559
+ value: amount,
2560
+ validAfter: validAfter.toString(),
2561
+ validBefore: validBefore.toString(),
2562
+ nonce,
2563
+ authSignature,
2564
+ tokenName,
2565
+ tokenVersion
2566
+ }
2567
+ });
2568
+ return result.txHash;
2569
+ };
4186
2570
  }
4187
2571
 
4188
- // src/client.ts
4189
- import {
4190
- createPublicClient as createPublicClient4,
4191
- createWalletClient as createWalletClient3,
4192
- custom as custom3
4193
- } from "viem";
4194
- import { base as base4, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
4195
-
4196
2572
  // src/lib/sponsored-weth-deposit.ts
4197
2573
  var PERMIT_WINDOW_SECONDS = 15 * 60;
4198
2574
  function makeSponsoredWethCallback(deps) {
4199
2575
  const get = deps.httpGet ?? getSponsorRelayerAddress;
4200
2576
  const post = deps.httpPost ?? postSponsorPermit2Transfer;
4201
- return makeVerificationAwareDepositCallback(
4202
- async (smartWallet, chainId, amount, verification) => {
4203
- const cid = chainId;
4204
- const token = deps.tokenAddressByChain[cid];
4205
- if (!token) {
4206
- throw new OwneyError(
4207
- "CHAIN_UNSUPPORTED",
4208
- `No sponsored WETH configured for chain ${chainId}`
4209
- );
4210
- }
4211
- const amountWei = BigInt(amount);
4212
- const pub = deps.getPublicClient(cid);
4213
- const wallet = deps.getWalletClient(cid);
4214
- await ensureWalletOnChain(pub, wallet, cid);
4215
- try {
4216
- const balance = await readErc20Balance(pub, token, deps.ownerAddress);
4217
- if (balance < amountWei) {
4218
- throw new OwneyError(
4219
- "DEPOSIT_INSUFFICIENT_BALANCE",
4220
- "Insufficient WETH balance for this deposit.",
4221
- { token, chainId: cid, balance: balance.toString(), amount }
4222
- );
4223
- }
4224
- } catch (err) {
4225
- if (err instanceof OwneyError) throw err;
4226
- console.warn(
4227
- "[owney-sdk] WETH balance pre-check failed (non-fatal):",
4228
- err instanceof Error ? err.message : String(err)
4229
- );
4230
- }
4231
- const allowance = await readPermit2Allowance(
4232
- pub,
4233
- token,
4234
- deps.ownerAddress
2577
+ return async (smartWallet, chainId, amount) => {
2578
+ const cid = chainId;
2579
+ const token = deps.tokenAddressByChain[cid];
2580
+ if (!token) {
2581
+ throw new OwneyError(
2582
+ "CHAIN_UNSUPPORTED",
2583
+ `No sponsored WETH configured for chain ${chainId}`
4235
2584
  );
4236
- if (allowance < amountWei) {
2585
+ }
2586
+ const amountWei = BigInt(amount);
2587
+ const pub = deps.getPublicClient(cid);
2588
+ const wallet = deps.getWalletClient(cid);
2589
+ await ensureWalletOnChain(pub, wallet, cid);
2590
+ try {
2591
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2592
+ if (balance < amountWei) {
4237
2593
  throw new OwneyError(
4238
- "PERMIT2_APPROVAL_REQUIRED",
4239
- "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
4240
- { token, chainId: cid, allowance: allowance.toString(), amount }
2594
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2595
+ "Insufficient WETH balance for this deposit.",
2596
+ { token, chainId: cid, balance: balance.toString(), amount }
4241
2597
  );
4242
2598
  }
4243
- const relayer = await get({
4244
- baseUrl: deps.baseUrl,
4245
- apiKey: deps.apiKey,
4246
- chainId: cid
4247
- });
4248
- const nonce = randomPermit2Nonce();
4249
- const deadline = BigInt(
4250
- Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2599
+ } catch (err) {
2600
+ if (err instanceof OwneyError) throw err;
2601
+ console.warn(
2602
+ "[owney-sdk] WETH balance pre-check failed (non-fatal):",
2603
+ err instanceof Error ? err.message : String(err)
4251
2604
  );
4252
- const typedData = buildPermitTransferFromTypedData({
4253
- chainId: cid,
4254
- message: {
4255
- permitted: { token, amount: amountWei },
4256
- spender: relayer,
4257
- nonce,
4258
- deadline
4259
- }
4260
- });
4261
- const signature = await wallet.signTypedData({
4262
- account: deps.ownerAddress,
4263
- ...typedData
4264
- });
4265
- deps.onApproved?.();
4266
- const result = await post({
4267
- baseUrl: deps.baseUrl,
4268
- apiKey: deps.apiKey,
4269
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
4270
- body: {
4271
- chainId: cid,
4272
- token,
4273
- from: deps.ownerAddress,
4274
- to: smartWallet,
4275
- amount,
4276
- nonce: nonce.toString(),
4277
- deadline: deadline.toString(),
4278
- signature,
4279
- ...verification?.agentId === "yieldseeker" ? {
4280
- yieldseekerUserId: verification.userId,
4281
- yieldseekerAgentId: verification.yieldseekerAgentId
4282
- } : {}
4283
- }
4284
- });
4285
- return result.txHash;
4286
2605
  }
4287
- );
2606
+ const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
2607
+ if (allowance < amountWei) {
2608
+ throw new OwneyError(
2609
+ "PERMIT2_APPROVAL_REQUIRED",
2610
+ "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
2611
+ { token, chainId: cid, allowance: allowance.toString(), amount }
2612
+ );
2613
+ }
2614
+ const relayer = await get({
2615
+ baseUrl: deps.baseUrl,
2616
+ apiKey: deps.apiKey,
2617
+ chainId: cid
2618
+ });
2619
+ const nonce = randomPermit2Nonce();
2620
+ const deadline = BigInt(
2621
+ Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2622
+ );
2623
+ const typedData = buildPermitTransferFromTypedData({
2624
+ chainId: cid,
2625
+ message: {
2626
+ permitted: { token, amount: amountWei },
2627
+ spender: relayer,
2628
+ nonce,
2629
+ deadline
2630
+ }
2631
+ });
2632
+ const signature = await wallet.signTypedData({
2633
+ account: deps.ownerAddress,
2634
+ ...typedData
2635
+ });
2636
+ deps.onApproved?.();
2637
+ const result = await post({
2638
+ baseUrl: deps.baseUrl,
2639
+ apiKey: deps.apiKey,
2640
+ body: {
2641
+ chainId: cid,
2642
+ token,
2643
+ from: deps.ownerAddress,
2644
+ to: smartWallet,
2645
+ amount,
2646
+ nonce: nonce.toString(),
2647
+ deadline: deadline.toString(),
2648
+ signature
2649
+ }
2650
+ });
2651
+ return result.txHash;
2652
+ };
4288
2653
  }
4289
2654
 
4290
2655
  // src/lib/sponsored-calls-deposit.ts
4291
- import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi2, toHex } from "viem";
2656
+ import { encodeFunctionData, erc20Abi, toHex } from "viem";
4292
2657
  var DEFAULT_POLL_INTERVAL_MS = 1500;
4293
2658
  var DEFAULT_MAX_POLLS = 30;
4294
2659
  async function paymasterSupported(provider, owner, chainId) {
@@ -4314,7 +2679,7 @@ function makeSponsoredCallsCallback(deps) {
4314
2679
  }
4315
2680
  return new URL(configured, origin).toString();
4316
2681
  };
4317
- return makeVerificationAwareDepositCallback(async (smartWallet, chainId, amount, verification) => {
2682
+ return async (smartWallet, chainId, amount) => {
4318
2683
  const cid = chainId;
4319
2684
  const token = deps.tokenAddressByChain[cid];
4320
2685
  if (!token) {
@@ -4330,37 +2695,11 @@ function makeSponsoredCallsCallback(deps) {
4330
2695
  { chainId }
4331
2696
  );
4332
2697
  }
4333
- const data = encodeFunctionData2({
4334
- abi: erc20Abi2,
2698
+ const data = encodeFunctionData({
2699
+ abi: erc20Abi,
4335
2700
  functionName: "transfer",
4336
2701
  args: [smartWallet, BigInt(amount)]
4337
2702
  });
4338
- let paymasterUrl = absolutePaymasterUrl();
4339
- if (verification?.agentId === "yieldseeker") {
4340
- if (chainId !== 8453) {
4341
- throw new OwneyError(
4342
- "CHAIN_UNSUPPORTED",
4343
- `Yieldseeker Base Account sponsorship is not available on chain ${chainId}.`
4344
- );
4345
- }
4346
- const { intent } = await postPaymasterIntent({
4347
- baseUrl: deps.routingApiBaseUrl,
4348
- apiKey: deps.apiKey,
4349
- yieldseekerSignature: verification.signature,
4350
- body: {
4351
- chainId,
4352
- token,
4353
- from: deps.ownerAddress,
4354
- to: smartWallet,
4355
- amount,
4356
- yieldseekerUserId: verification.userId,
4357
- yieldseekerAgentId: verification.yieldseekerAgentId
4358
- }
4359
- });
4360
- const url = new URL(paymasterUrl);
4361
- url.searchParams.set("owneyIntent", intent);
4362
- paymasterUrl = url.toString();
4363
- }
4364
2703
  const sendResult = await deps.provider.request({
4365
2704
  method: "wallet_sendCalls",
4366
2705
  params: [
@@ -4371,7 +2710,7 @@ function makeSponsoredCallsCallback(deps) {
4371
2710
  atomicRequired: false,
4372
2711
  calls: [{ to: token, value: "0x0", data }],
4373
2712
  capabilities: {
4374
- paymasterService: { url: paymasterUrl }
2713
+ paymasterService: { url: absolutePaymasterUrl() }
4375
2714
  }
4376
2715
  }
4377
2716
  ]
@@ -4401,7 +2740,7 @@ function makeSponsoredCallsCallback(deps) {
4401
2740
  `No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
4402
2741
  { chainId, callsId }
4403
2742
  );
4404
- });
2743
+ };
4405
2744
  }
4406
2745
 
4407
2746
  // src/client.ts
@@ -4431,7 +2770,7 @@ var SPONSORED_USDC_BY_CHAIN = {
4431
2770
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
4432
2771
  };
4433
2772
  var VIEM_CHAIN2 = {
4434
- 8453: base4,
2773
+ 8453: base2,
4435
2774
  42161: arbitrum2,
4436
2775
  1: mainnet2
4437
2776
  };
@@ -4461,8 +2800,6 @@ var OwneySDK = class {
4461
2800
  orgAgentConfig;
4462
2801
  orgAgentConfigPromise = null;
4463
2802
  zyfaiRpcUrls;
4464
- yieldseekerApiBaseUrl;
4465
- yieldseekerSiweOrigin;
4466
2803
  routingApiBaseUrl;
4467
2804
  referralSource;
4468
2805
  cachedSponsoredCallback = null;
@@ -4485,8 +2822,6 @@ var OwneySDK = class {
4485
2822
  this.apiKey = config.apiKey;
4486
2823
  if (config.debug) setOwneyDebug(true);
4487
2824
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
4488
- this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
4489
- this.yieldseekerSiweOrigin = config.yieldseekerSiweOrigin;
4490
2825
  this.routingApiBaseUrl = config.routingApiBaseUrl;
4491
2826
  this.paymasterServiceUrl = config.paymasterServiceUrl;
4492
2827
  this.referralSource = config.referralSource;
@@ -4593,14 +2928,14 @@ var OwneySDK = class {
4593
2928
  // Casts work around viem's chain-narrowed Client vs the generic
4594
2929
  // PublicClient/WalletClient param types — structurally identical at
4595
2930
  // runtime, but the two share a name TS treats as unrelated.
4596
- getPublicClient: (cid) => createPublicClient4({
2931
+ getPublicClient: (cid) => createPublicClient2({
4597
2932
  chain: VIEM_CHAIN2[cid],
4598
- transport: custom3(provider)
2933
+ transport: custom(provider)
4599
2934
  }),
4600
- getWalletClient: (cid) => createWalletClient3({
2935
+ getWalletClient: (cid) => createWalletClient({
4601
2936
  account: owner,
4602
2937
  chain: VIEM_CHAIN2[cid],
4603
- transport: custom3(provider)
2938
+ transport: custom(provider)
4604
2939
  })
4605
2940
  });
4606
2941
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -4617,8 +2952,6 @@ var OwneySDK = class {
4617
2952
  if (!onApproved && cached) return cached;
4618
2953
  const provider = this.requireConnectedProvider();
4619
2954
  const callback = makeSponsoredCallsCallback({
4620
- apiKey: this.apiKey,
4621
- routingApiBaseUrl: this.routingApiBaseUrl,
4622
2955
  provider,
4623
2956
  ownerAddress: this.state.walletAddress,
4624
2957
  paymasterServiceUrl: this.paymasterServiceUrl,
@@ -4648,14 +2981,14 @@ var OwneySDK = class {
4648
2981
  // Casts work around viem's chain-narrowed Client vs the generic
4649
2982
  // PublicClient/WalletClient param types — structurally identical at
4650
2983
  // runtime, but the two share a name TS treats as unrelated.
4651
- getPublicClient: (cid) => createPublicClient4({
2984
+ getPublicClient: (cid) => createPublicClient2({
4652
2985
  chain: VIEM_CHAIN2[cid],
4653
- transport: custom3(provider)
2986
+ transport: custom(provider)
4654
2987
  }),
4655
- getWalletClient: (cid) => createWalletClient3({
2988
+ getWalletClient: (cid) => createWalletClient({
4656
2989
  account: owner,
4657
2990
  chain: VIEM_CHAIN2[cid],
4658
- transport: custom3(provider)
2991
+ transport: custom(provider)
4659
2992
  })
4660
2993
  });
4661
2994
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -4686,10 +3019,12 @@ var OwneySDK = class {
4686
3019
  this.orgAgentConfigPromise = fetchOrgAgentConfig(
4687
3020
  this.apiKey,
4688
3021
  this.routingApiBaseUrl
4689
- ).then((config) => {
4690
- this.orgAgentConfig = config;
4691
- return config;
4692
- });
3022
+ ).then(
3023
+ (config) => {
3024
+ this.orgAgentConfig = config;
3025
+ return config;
3026
+ }
3027
+ );
4693
3028
  }
4694
3029
  return this.orgAgentConfigPromise;
4695
3030
  }
@@ -4729,14 +3064,7 @@ var OwneySDK = class {
4729
3064
  this.routingApiBaseUrl
4730
3065
  );
4731
3066
  this.disabledAgents.clear();
4732
- for (const {
4733
- key: key2,
4734
- agent_type,
4735
- is_enabled,
4736
- is_configured
4737
- } of agentKeys) {
4738
- const configured = is_configured ?? Boolean(key2);
4739
- if (!configured) continue;
3067
+ for (const { key: key2, agent_type, is_enabled } of agentKeys) {
4740
3068
  const agent = this.createAgent(agent_type, key2);
4741
3069
  if (!agent) continue;
4742
3070
  this.agents.set(agent_type, agent);
@@ -4760,15 +3088,8 @@ var OwneySDK = class {
4760
3088
  }
4761
3089
  createAgent(agentId, key2) {
4762
3090
  if (agentId === "zyfai") {
4763
- if (!key2) return null;
4764
3091
  return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
4765
3092
  }
4766
- if (agentId === "yieldseeker") {
4767
- return new YieldseekerAgent(this.apiKey, {
4768
- auth: { origin: this.yieldseekerSiweOrigin },
4769
- baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl)
4770
- });
4771
- }
4772
3093
  return null;
4773
3094
  }
4774
3095
  /**
@@ -4813,7 +3134,7 @@ var OwneySDK = class {
4813
3134
  * If provided, ALL specified agents must support the chainId or the call
4814
3135
  * throws before activating any agent.
4815
3136
  */
4816
- async activateAgent(chainId, agentId, asset) {
3137
+ async activateAgent(chainId, agentId) {
4817
3138
  const state = this.requireState();
4818
3139
  await this.ensureAgentsInitialized();
4819
3140
  if (agentId !== void 0) {
@@ -4849,7 +3170,7 @@ var OwneySDK = class {
4849
3170
  this.activeAgents.add(id);
4850
3171
  }
4851
3172
  state.chainId = chainId;
4852
- await this.activateAgentsInTurn(agents, state, chainId, asset);
3173
+ await this.activateAgentsInTurn(agents, state, chainId);
4853
3174
  return;
4854
3175
  }
4855
3176
  const compatible = [...this.agents.values()].filter(
@@ -4870,7 +3191,7 @@ var OwneySDK = class {
4870
3191
  const enabledCompatible = compatible.filter(
4871
3192
  (agent) => !this.isAgentDisabled(agent.id)
4872
3193
  );
4873
- await this.activateAgentsInTurn(enabledCompatible, state, chainId, asset);
3194
+ await this.activateAgentsInTurn(enabledCompatible, state, chainId);
4874
3195
  }
4875
3196
  /**
4876
3197
  * Activate agents ONE AT A TIME, each followed by its org policy.
@@ -4886,25 +3207,17 @@ var OwneySDK = class {
4886
3207
  * at a time anyway.
4887
3208
  *
4888
3209
  * Every agent is attempted even if an earlier one fails, so one declined
4889
- * signature can't deny the remaining agents their turn. Once all agents have
4890
- * had a chance, a partial failure identifies the agents that still need a
4891
- * retry; if none activated, the original provider error is preserved.
3210
+ * signature can't deny the remaining agents their turn. The first failure is
3211
+ * rethrown (matching the previous `Promise.all` rejection) once all agents
3212
+ * have had a chance to activate.
4892
3213
  */
4893
- async activateAgentsInTurn(agents, state, chainId, asset) {
3214
+ async activateAgentsInTurn(agents, state, chainId) {
4894
3215
  let firstError = null;
4895
- const activatedAgentIds = [];
4896
- const failedAgents = [];
4897
3216
  for (const agent of agents) {
4898
3217
  try {
4899
- await agent.activateAgent(state, chainId, asset);
3218
+ await agent.activateAgent(state, chainId);
4900
3219
  await this.applyOrgPolicyTo(agent, state, chainId);
4901
- activatedAgentIds.push(agent.id);
4902
3220
  } catch (error) {
4903
- failedAgents.push({
4904
- agentId: agent.id,
4905
- code: error instanceof OwneyError ? error.code : void 0,
4906
- message: error instanceof Error ? error.message : String(error)
4907
- });
4908
3221
  if (firstError === null) {
4909
3222
  firstError = error;
4910
3223
  } else {
@@ -4912,16 +3225,7 @@ var OwneySDK = class {
4912
3225
  }
4913
3226
  }
4914
3227
  }
4915
- if (firstError === null) return;
4916
- if (activatedAgentIds.length === 0) throw firstError;
4917
- const failedAgentIds = failedAgents.map(({ agentId }) => agentId);
4918
- const activeNames = activatedAgentIds.map(this.formatAgentName).join(", ");
4919
- const remainingNames = failedAgentIds.map(this.formatAgentName).join(", ");
4920
- throw new OwneyError(
4921
- "AGENT_ACTIVATION_PARTIAL_FAILURE",
4922
- `${activeNames} activated, but ${remainingNames} still needs activation. Try again and approve the remaining wallet request.`,
4923
- { activatedAgentIds, failedAgentIds, failures: failedAgents }
4924
- );
3228
+ if (firstError !== null) throw firstError;
4925
3229
  }
4926
3230
  /**
4927
3231
  * Deposit into a specific agent, or distribute across all eligible agents.
@@ -5135,10 +3439,10 @@ var OwneySDK = class {
5135
3439
  agent,
5136
3440
  amount: i === agents.length - 1 ? perAgent + remainder : perAgent
5137
3441
  }));
5138
- const valid2 = splits.filter(
3442
+ const valid = splits.filter(
5139
3443
  (s) => s.amount > 0n && (exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset))
5140
3444
  );
5141
- if (valid2.length === agents.length) {
3445
+ if (valid.length === agents.length) {
5142
3446
  return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
5143
3447
  }
5144
3448
  const targets = agentsRequiringActivation.length > 0 ? agentsRequiringActivation : agents;
@@ -5157,11 +3461,6 @@ var OwneySDK = class {
5157
3461
  )
5158
3462
  }));
5159
3463
  }
5160
- formatAgentName(agentId) {
5161
- if (agentId === "zyfai") return "Zyfai";
5162
- if (agentId === "yieldseeker") return "Yieldseeker";
5163
- return agentId;
5164
- }
5165
3464
  async validateMinDepositAmount(agent, state, chainId, asset, amount) {
5166
3465
  const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
5167
3466
  const parsedAmount = BigInt(amount);
@@ -5193,12 +3492,12 @@ var OwneySDK = class {
5193
3492
  (t) => t.chainId === chainId && t.asset.toLowerCase() === target
5194
3493
  );
5195
3494
  const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
5196
- const position2 = (balance.positions ?? []).find((p) => {
3495
+ const position = (balance.positions ?? []).find((p) => {
5197
3496
  const positionChain = p.chain.trim().toUpperCase();
5198
3497
  const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
5199
3498
  return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
5200
3499
  });
5201
- return !!token && Number(token.amount) > 0 || !!position2;
3500
+ return !!token && Number(token.amount) > 0 || !!position;
5202
3501
  } catch (error) {
5203
3502
  if (requireReliableRead) {
5204
3503
  throw new OwneyError(
@@ -5313,10 +3612,6 @@ var OwneySDK = class {
5313
3612
  }
5314
3613
  const requested = BigInt(amount);
5315
3614
  const aggregated = await this.getBalances();
5316
- const unavailableAgents = eligibleAgents.filter(
5317
- (agent) => !(agent.id in aggregated.agentBalances)
5318
- );
5319
- const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
5320
3615
  const balances = projectAgentBalancesForAsset(
5321
3616
  eligibleAgents,
5322
3617
  aggregated.agentBalances,
@@ -5325,18 +3620,7 @@ var OwneySDK = class {
5325
3620
  assetInfo.decimals
5326
3621
  );
5327
3622
  const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
5328
- if (totalAvailable === 0n && unavailableAgents.length > 0) {
5329
- throw new OwneyError(
5330
- "WITHDRAW_BALANCE_UNAVAILABLE",
5331
- `Cannot safely plan the withdrawal because balance data is unavailable for: ${unavailableAgentIds.join(", ")}.`,
5332
- {
5333
- asset,
5334
- unavailableAgents: unavailableAgentIds,
5335
- agentErrors: aggregated.agentErrors
5336
- }
5337
- );
5338
- }
5339
- if (totalAvailable < requested && unavailableAgents.length === 0) {
3623
+ if (totalAvailable < requested) {
5340
3624
  throw new OwneyError(
5341
3625
  "WITHDRAW_INSUFFICIENT_BALANCE",
5342
3626
  `Requested withdrawal "${amount}" exceeds available balance "${totalAvailable.toString()}" for asset "${asset}".`,
@@ -5347,7 +3631,6 @@ var OwneySDK = class {
5347
3631
  }
5348
3632
  );
5349
3633
  }
5350
- const plannedTarget = totalAvailable < requested ? totalAvailable : requested;
5351
3634
  const disabledBalances = balances.filter(
5352
3635
  (b) => this.isAgentDisabled(b.agent.id)
5353
3636
  );
@@ -5356,7 +3639,7 @@ var OwneySDK = class {
5356
3639
  );
5357
3640
  const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
5358
3641
  disabledBalances,
5359
- plannedTarget
3642
+ requested
5360
3643
  );
5361
3644
  const enabledTotal = enabledBalances.reduce((s, b) => s + b.balance, 0n);
5362
3645
  const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
@@ -5366,9 +3649,7 @@ var OwneySDK = class {
5366
3649
  }));
5367
3650
  const plans = [...disabledPlans, ...enabledPlans];
5368
3651
  const results = {};
5369
- const agentErrors = {
5370
- ...aggregated.agentErrors ?? {}
5371
- };
3652
+ const agentErrors = {};
5372
3653
  for (let i = 0; i < plans.length; i++) {
5373
3654
  const p = plans[i];
5374
3655
  if (p.planned === 0n) continue;
@@ -5415,8 +3696,7 @@ var OwneySDK = class {
5415
3696
  requested: amount,
5416
3697
  withdrawn: withdrawn.toString(),
5417
3698
  partialResults: results,
5418
- agentErrors,
5419
- ...unavailableAgentIds.length > 0 ? { unavailableAgents: unavailableAgentIds } : {}
3699
+ agentErrors
5420
3700
  }
5421
3701
  );
5422
3702
  }
@@ -5434,10 +3714,7 @@ var OwneySDK = class {
5434
3714
  if (agentId) {
5435
3715
  const agent = this.getAgent(agentId);
5436
3716
  const result = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
5437
- return {
5438
- ...result,
5439
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
5440
- };
3717
+ return result;
5441
3718
  }
5442
3719
  let totalBalance = 0;
5443
3720
  const results = {};
@@ -5445,13 +3722,7 @@ var OwneySDK = class {
5445
3722
  const balanceResults = await Promise.allSettled(
5446
3723
  entries.map(async ([id, agent]) => {
5447
3724
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
5448
- return [
5449
- id,
5450
- {
5451
- ...b,
5452
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
5453
- }
5454
- ];
3725
+ return [id, b];
5455
3726
  })
5456
3727
  );
5457
3728
  let successCount = 0;
@@ -5473,7 +3744,6 @@ var OwneySDK = class {
5473
3744
  const retryDelay = rateLimitDelay(reason);
5474
3745
  if (retryDelay !== void 0) agentRetryAt[agentId2] = Date.now() + retryDelay;
5475
3746
  agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
5476
- console.error(`[owney-sdk] Balance fetch failed for agent "${agentId2}":`, reason);
5477
3747
  }
5478
3748
  if (successCount === 0) {
5479
3749
  throw new OwneyError(
@@ -5586,10 +3856,7 @@ var OwneySDK = class {
5586
3856
  Promise.all(
5587
3857
  entries.map(async ([id, agent]) => {
5588
3858
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
5589
- return [
5590
- id,
5591
- balanceForApyScope(b, chainId, tokenSymbol)
5592
- ];
3859
+ return [id, Number(b.totalBalance)];
5593
3860
  })
5594
3861
  )
5595
3862
  ]);
@@ -5617,12 +3884,10 @@ var OwneySDK = class {
5617
3884
  }
5618
3885
  }
5619
3886
  const apyByChainAndAsset = aggregateApyByChainAndAsset(results, balances);
5620
- const history = aggregateApyHistory(results, balances);
5621
3887
  return {
5622
3888
  totalApy: String(totalApy),
5623
3889
  agentApy: results,
5624
- apyByChainAndAsset,
5625
- history
3890
+ apyByChainAndAsset
5626
3891
  };
5627
3892
  }
5628
3893
  /**
@@ -5770,10 +4035,10 @@ var OwneySDK = class {
5770
4035
  );
5771
4036
  }
5772
4037
  const provider = this.requireConnectedProvider();
5773
- const wallet = createWalletClient3({
4038
+ const wallet = createWalletClient({
5774
4039
  account: state.walletAddress,
5775
4040
  chain: VIEM_CHAIN2[chainId],
5776
- transport: custom3(provider)
4041
+ transport: custom(provider)
5777
4042
  });
5778
4043
  const hash = await wallet.writeContract({
5779
4044
  address: token,
@@ -5783,9 +4048,9 @@ var OwneySDK = class {
5783
4048
  account: state.walletAddress,
5784
4049
  chain: VIEM_CHAIN2[chainId]
5785
4050
  });
5786
- const publicClient = createPublicClient4({
4051
+ const publicClient = createPublicClient2({
5787
4052
  chain: VIEM_CHAIN2[chainId],
5788
- transport: custom3(provider)
4053
+ transport: custom(provider)
5789
4054
  });
5790
4055
  const receipt = await publicClient.waitForTransactionReceipt({
5791
4056
  hash,
@@ -5822,9 +4087,7 @@ var OwneySDK = class {
5822
4087
  return this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
5823
4088
  }
5824
4089
  const results = {};
5825
- const agentEntries = [...this.agents.entries()].filter(
5826
- ([id]) => !this.isAgentDisabled(id)
5827
- );
4090
+ const agentEntries = [...this.agents.entries()];
5828
4091
  const apyResults = await Promise.all(
5829
4092
  agentEntries.map(async ([id, agent]) => {
5830
4093
  const apy = await this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
@@ -5899,13 +4162,13 @@ var OwneySDK = class {
5899
4162
  };
5900
4163
 
5901
4164
  // src/agents/zyfai/zyfai.siwx.ts
5902
- import { getAddress as getAddress3 } from "viem";
5903
- import { SiweMessage as SiweMessage2 } from "siwe";
4165
+ import { getAddress } from "viem";
4166
+ import { SiweMessage } from "siwe";
5904
4167
  import { ZyfaiSDK as ZyfaiSDK2 } from "@zyfai/sdk";
5905
4168
 
5906
4169
  // src/agents/zyfai/zyfai.siwx-cache.ts
5907
- var KEY_PREFIX4 = "owney.siwx.session";
5908
- var storage4 = () => {
4170
+ var KEY_PREFIX2 = "owney.siwx.session";
4171
+ var storage2 = () => {
5909
4172
  if (typeof window === "undefined") return null;
5910
4173
  try {
5911
4174
  return window.localStorage;
@@ -5913,8 +4176,8 @@ var storage4 = () => {
5913
4176
  return null;
5914
4177
  }
5915
4178
  };
5916
- var buildKey3 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}`;
5917
- var legacyKeyPrefix2 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}:`;
4179
+ var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
4180
+ var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
5918
4181
  var memorySiwxSessions = /* @__PURE__ */ new Map();
5919
4182
  var readLegacySiwxSession = (store, address) => {
5920
4183
  if (!store) return null;
@@ -5945,17 +4208,17 @@ var readLegacySiwxSession = (store, address) => {
5945
4208
  };
5946
4209
  var readSiwxSession = (address, chainId) => {
5947
4210
  if (typeof window === "undefined") return null;
5948
- const key2 = buildKey3(address);
5949
- const store = storage4();
5950
- let raw2 = null;
4211
+ const key2 = buildKey2(address);
4212
+ const store = storage2();
4213
+ let raw = null;
5951
4214
  try {
5952
- raw2 = store?.getItem(key2) ?? null;
4215
+ raw = store?.getItem(key2) ?? null;
5953
4216
  } catch {
5954
- raw2 = null;
4217
+ raw = null;
5955
4218
  }
5956
- if (raw2) {
4219
+ if (raw) {
5957
4220
  try {
5958
- return JSON.parse(raw2);
4221
+ return JSON.parse(raw);
5959
4222
  } catch {
5960
4223
  memorySiwxSessions.delete(key2);
5961
4224
  try {
@@ -5974,18 +4237,18 @@ var readSiwxSession = (address, chainId) => {
5974
4237
  };
5975
4238
  var writeSiwxSession = (address, _chainId, session) => {
5976
4239
  if (typeof window === "undefined") return;
5977
- const key2 = buildKey3(address);
4240
+ const key2 = buildKey2(address);
5978
4241
  memorySiwxSessions.set(key2, session);
5979
- const store = storage4();
4242
+ const store = storage2();
5980
4243
  try {
5981
4244
  store?.setItem(key2, JSON.stringify(session));
5982
4245
  } catch {
5983
4246
  }
5984
4247
  };
5985
4248
  var clearSiwxSession = (address, _chainId) => {
5986
- const key2 = buildKey3(address);
4249
+ const key2 = buildKey2(address);
5987
4250
  memorySiwxSessions.delete(key2);
5988
- const store = storage4();
4251
+ const store = storage2();
5989
4252
  try {
5990
4253
  store?.removeItem(key2);
5991
4254
  } catch {
@@ -6025,8 +4288,8 @@ function buildSIWXConfig(deps) {
6025
4288
  statement: STATEMENT,
6026
4289
  issuedAt,
6027
4290
  toString() {
6028
- return new SiweMessage2({
6029
- address: getAddress3(accountAddress),
4291
+ return new SiweMessage({
4292
+ address: getAddress(accountAddress),
6030
4293
  chainId: numericChainId(chainId),
6031
4294
  domain,
6032
4295
  uri,
@@ -6068,7 +4331,7 @@ function buildSIWXConfig(deps) {
6068
4331
  const persistSession = async (session) => {
6069
4332
  const address = session.data.accountAddress;
6070
4333
  const id = numericChainId(session.data.chainId);
6071
- const message = new SiweMessage2(session.message);
4334
+ const message = new SiweMessage(session.message);
6072
4335
  const login = await post("/auth/login", {
6073
4336
  message,
6074
4337
  signature: session.signature,
@@ -6116,7 +4379,6 @@ export {
6116
4379
  NotConnectedError,
6117
4380
  OwneyError,
6118
4381
  OwneySDK,
6119
- YieldseekerAgent,
6120
4382
  createOwneySIWX,
6121
4383
  setOwneyDebug
6122
4384
  };