@owney/sdk 0.7.16-beta.1 → 0.7.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -26,7 +26,6 @@ __export(index_exports, {
26
26
  NotConnectedError: () => NotConnectedError,
27
27
  OwneyError: () => OwneyError,
28
28
  OwneySDK: () => OwneySDK,
29
- YieldseekerAgent: () => YieldseekerAgent,
30
29
  createOwneySIWX: () => createOwneySIWX,
31
30
  setOwneyDebug: () => setOwneyDebug
32
31
  });
@@ -84,6 +83,23 @@ var SupportedAssets = [
84
83
  }
85
84
  ];
86
85
 
86
+ // src/lib/debug.ts
87
+ var configuredDebug = false;
88
+ function setOwneyDebug(enabled) {
89
+ configuredDebug = enabled;
90
+ }
91
+ function isOwneyDebug() {
92
+ return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
93
+ }
94
+ function debugLog(scope, message, data) {
95
+ if (!isOwneyDebug()) return;
96
+ if (data === void 0) {
97
+ console.log(`[${scope}] ${message}`);
98
+ } else {
99
+ console.log(`[${scope}] ${message}`, data);
100
+ }
101
+ }
102
+
87
103
  // src/errors.ts
88
104
  var OwneyError = class extends Error {
89
105
  code;
@@ -283,7 +299,7 @@ function mapBalances(raw, _chainId, smartWallet) {
283
299
  )
284
300
  )
285
301
  ),
286
- apy: p.pool_apy,
302
+ apy: netApy(p.pool_apy_withFee, p.pool_apy, "pool_apy_withFee"),
287
303
  tvl: p.pool_tvl,
288
304
  // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
289
305
  // structural read keeps it undefined today and auto-populates later.
@@ -340,14 +356,27 @@ function mapWeightedApyByChain(raw) {
340
356
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
341
357
  const perAsset = {};
342
358
  for (const [symbol, apy] of Object.entries(tokenApy)) {
343
- const token2 = symbol;
344
- if (!SUPPORTED_TOKENS.includes(token2)) continue;
345
- perAsset[token2] = apy;
359
+ const token = symbol;
360
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
361
+ perAsset[token] = apy;
346
362
  }
347
363
  if (Object.keys(perAsset).length > 0) out[chainId] = perAsset;
348
364
  }
349
365
  return Object.keys(out).length > 0 ? out : void 0;
350
366
  }
367
+ var warnedGrossApyFallbacks = /* @__PURE__ */ new Set();
368
+ function netApy(net, gross, field) {
369
+ if (net !== void 0 && net !== null) return net;
370
+ if (gross === void 0 || gross === null) return void 0;
371
+ if (!warnedGrossApyFallbacks.has(field)) {
372
+ warnedGrossApyFallbacks.add(field);
373
+ console.warn(
374
+ `[owney] @zyfai/sdk omitted "${field}"; falling back to the gross APY, which does not deduct Zyfai's performance fee and so reads high.`
375
+ );
376
+ }
377
+ debugLog("zyfai:apy", `gross fallback for ${field}`, { gross });
378
+ return gross;
379
+ }
351
380
  function rawPoolApyForChain(entry, chainId, tokenSymbol) {
352
381
  let weightedSum = 0;
353
382
  let totalBalance = 0;
@@ -355,8 +384,9 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
355
384
  if (p.chainId !== chainId) continue;
356
385
  if (tokenSymbol && p.tokenSymbol !== tokenSymbol) continue;
357
386
  const balance = p.balance ?? 0;
358
- if (balance <= 0 || typeof p.apy !== "number") continue;
359
- weightedSum += p.apy * balance;
387
+ const apy = netApy(p.apy_withFee, p.apy, "apy_withFee");
388
+ if (balance <= 0 || typeof apy !== "number") continue;
389
+ weightedSum += apy * balance;
360
390
  totalBalance += balance;
361
391
  }
362
392
  return totalBalance > 0 ? weightedSum / totalBalance : null;
@@ -404,8 +434,12 @@ function mapEntries(rawEntries, chainId) {
404
434
  const matched = positions.find(
405
435
  (p) => p.protocol_name ? rawLog.newOpportunity.includes(`${p.protocol_name} (${p.pool})`) : false
406
436
  );
407
- oldApy = Number(rawLog.oldApy);
408
- newApy = Number(rawLog.newApy);
437
+ oldApy = Number(
438
+ netApy(rawLog.oldApy_withFee, rawLog.oldApy, "oldApy_withFee")
439
+ );
440
+ newApy = Number(
441
+ netApy(rawLog.newApy_withFee, rawLog.newApy, "newApy_withFee")
442
+ );
409
443
  const from = splitOpportunity(rawLog.oldOpportunity);
410
444
  const to = splitOpportunity(rawLog.newOpportunity);
411
445
  rebalanceLog = [
@@ -485,7 +519,11 @@ function mapApyByStrategy(raw) {
485
519
  const chainKey = supported.chainId;
486
520
  const symbolKey = supported.symbol;
487
521
  const bucket = apyPerAsset[chainKey] ?? {};
488
- const apy = entry.average_apy_with_fee ?? entry.average_apy;
522
+ const apy = netApy(
523
+ entry.average_apy_withFee,
524
+ entry.average_apy,
525
+ "average_apy_withFee"
526
+ ) ?? entry.average_apy;
489
527
  bucket[symbolKey] = apy;
490
528
  apyPerAsset[chainKey] = bucket;
491
529
  apySum += apy;
@@ -511,23 +549,23 @@ function computeAllocationApy(positions) {
511
549
  weightedSum += apy * value;
512
550
  totalValue += value;
513
551
  const chainId = resolveChainId(p.chain);
514
- const token2 = p.asset;
552
+ const token = p.asset;
515
553
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
516
- if (!SUPPORTED_TOKENS.includes(token2)) continue;
554
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
517
555
  const perAsset = buckets[chainId] ?? {};
518
- const cell = perAsset[token2] ?? { weightedSum: 0, value: 0 };
556
+ const cell = perAsset[token] ?? { weightedSum: 0, value: 0 };
519
557
  cell.weightedSum += apy * value;
520
558
  cell.value += value;
521
- perAsset[token2] = cell;
559
+ perAsset[token] = cell;
522
560
  buckets[chainId] = perAsset;
523
561
  }
524
562
  const apyByChainAndAsset = {};
525
563
  for (const [chainKey, perAsset] of Object.entries(buckets)) {
526
564
  const chainId = Number(chainKey);
527
565
  const out = {};
528
- for (const [token2, cell] of Object.entries(perAsset ?? {})) {
566
+ for (const [token, cell] of Object.entries(perAsset ?? {})) {
529
567
  if (cell && cell.value > 0) {
530
- out[token2] = cell.weightedSum / cell.value;
568
+ out[token] = cell.weightedSum / cell.value;
531
569
  }
532
570
  }
533
571
  if (Object.keys(out).length > 0) apyByChainAndAsset[chainId] = out;
@@ -541,9 +579,9 @@ var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4d
541
579
  function topicToAddress(topic) {
542
580
  return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
543
581
  }
544
- function extractWithdrawnAmount(logs, recipient, token2, decimals) {
582
+ function extractWithdrawnAmount(logs, recipient, token, decimals) {
545
583
  const wantRecipient = recipient.toLowerCase();
546
- const wantToken = token2.toLowerCase();
584
+ const wantToken = token.toLowerCase();
547
585
  let total = 0n;
548
586
  let matched = false;
549
587
  for (const log of logs) {
@@ -569,11 +607,11 @@ var InvalidHistoryCursorError = class extends Error {
569
607
  function encodeHistoryCursor(payload) {
570
608
  return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
571
609
  }
572
- function decodeHistoryCursor(token2) {
573
- if (!token2) throw new InvalidHistoryCursorError("Cursor is empty.");
610
+ function decodeHistoryCursor(token) {
611
+ if (!token) throw new InvalidHistoryCursorError("Cursor is empty.");
574
612
  let parsed;
575
613
  try {
576
- const json = Buffer.from(token2, "base64").toString("utf8");
614
+ const json = Buffer.from(token, "base64").toString("utf8");
577
615
  parsed = JSON.parse(json);
578
616
  } catch {
579
617
  throw new InvalidHistoryCursorError("Cursor is not valid base64 JSON.");
@@ -596,8 +634,8 @@ var storage = () => {
596
634
  };
597
635
  var buildKey = (address) => `${KEY_PREFIX}:${address.toLowerCase()}`;
598
636
  var legacyKeyPrefix = (address) => `${KEY_PREFIX}:${address.toLowerCase()}:`;
599
- var isJwtExpired = (token2) => {
600
- const parts = token2.split(".");
637
+ var isJwtExpired = (token) => {
638
+ const parts = token.split(".");
601
639
  if (parts.length !== 3) return false;
602
640
  try {
603
641
  const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
@@ -845,23 +883,6 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
845
883
  return !protocolListsEqual(current.protocols, desiredProtocols);
846
884
  }
847
885
 
848
- // src/lib/debug.ts
849
- var configuredDebug = false;
850
- function setOwneyDebug(enabled) {
851
- configuredDebug = enabled;
852
- }
853
- function isOwneyDebug() {
854
- return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
855
- }
856
- function debugLog(scope, message, data) {
857
- if (!isOwneyDebug()) return;
858
- if (data === void 0) {
859
- console.log(`[${scope}] ${message}`);
860
- } else {
861
- console.log(`[${scope}] ${message}`, data);
862
- }
863
- }
864
-
865
886
  // src/agents/zyfai/zyfai.agent.ts
866
887
  var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem.parseAbi)([
867
888
  "function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
@@ -1699,20 +1720,20 @@ var ZyfaiAgent = class _ZyfaiAgent {
1699
1720
  }
1700
1721
  }
1701
1722
  // --- IAgent: Fund operations ---
1702
- async withdraw(state, chainId, token2, amount) {
1723
+ async withdraw(state, chainId, token, amount) {
1703
1724
  const validChainId = isValidChainId(chainId);
1704
1725
  await this.ensureConnected(state, validChainId);
1705
1726
  const raw = await this.sdk.withdrawFunds(
1706
1727
  this.getAddress(),
1707
1728
  validChainId,
1708
1729
  amount,
1709
- token2
1730
+ token
1710
1731
  );
1711
1732
  if (!raw.success) {
1712
1733
  throw new OwneyError(
1713
1734
  "WITHDRAW_FAILED",
1714
1735
  raw.message || "Zyfai withdraw failed.",
1715
- { chainId: validChainId, token: token2, amount, response: raw },
1736
+ { chainId: validChainId, token, amount, response: raw },
1716
1737
  this.id
1717
1738
  );
1718
1739
  }
@@ -1863,183 +1884,359 @@ var ZyfaiAgent = class _ZyfaiAgent {
1863
1884
  }
1864
1885
  };
1865
1886
 
1866
- // src/agents/yieldseeker/yieldseeker.agent.ts
1867
- var import_viem6 = require("viem");
1868
- var import_chains3 = require("viem/chains");
1869
-
1870
- // src/lib/chain-guard.ts
1871
- var CHAIN_NAMES = {
1872
- 1: "Ethereum",
1873
- 8453: "Base",
1874
- 42161: "Arbitrum"
1875
- };
1876
- function chainName(chainId) {
1877
- return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
1878
- }
1879
- async function ensureWalletOnChain(pub, wallet, expected) {
1880
- const actual = await pub.getChainId();
1881
- if (actual === expected) return;
1887
+ // src/lib/routing-api.ts
1888
+ var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
1889
+ async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
1890
+ const url = `${baseUrl}/api/v1/agent/org-config`;
1882
1891
  try {
1883
- await wallet.switchChain({ id: expected });
1884
- } catch (error) {
1885
- throw new OwneyError(
1886
- "CHAIN_MISMATCH",
1887
- `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
1888
- {
1889
- expectedChainId: expected,
1890
- actualChainId: actual,
1891
- cause: error instanceof Error ? error.message : String(error)
1892
+ const res = await fetch(url, {
1893
+ method: "GET",
1894
+ headers: {
1895
+ "Content-Type": "application/json",
1896
+ "x-owney-api-key": `${apiKey}`
1897
+ }
1898
+ });
1899
+ if (!res.ok) {
1900
+ if (res.status !== 404) {
1901
+ console.warn(
1902
+ `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
1903
+ );
1892
1904
  }
1905
+ return null;
1906
+ }
1907
+ const json = await res.json();
1908
+ const policy = json.success ? json.data ?? null : null;
1909
+ debugLog(
1910
+ "owney-sdk",
1911
+ policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
1912
+ policy ?? void 0
1893
1913
  );
1894
- }
1895
- const after = await pub.getChainId();
1896
- if (after !== expected) {
1897
- throw new OwneyError(
1898
- "CHAIN_MISMATCH",
1899
- `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
1900
- { expectedChainId: expected, actualChainId: after }
1914
+ return policy;
1915
+ } catch (error) {
1916
+ console.warn(
1917
+ "[owney-sdk] Could not read org agent config (non-fatal):",
1918
+ error instanceof Error ? error.message : String(error)
1901
1919
  );
1920
+ return null;
1902
1921
  }
1903
1922
  }
1904
-
1905
- // src/lib/transfer-auth.ts
1906
- var import_viem2 = require("viem");
1907
- var ERC20_META_ABI = [
1908
- { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
1909
- { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
1910
- ];
1911
- function buildTransferWithAuthorizationTypedData(input) {
1912
- return {
1913
- domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
1914
- types: {
1915
- TransferWithAuthorization: [
1916
- { name: "from", type: "address" },
1917
- { name: "to", type: "address" },
1918
- { name: "value", type: "uint256" },
1919
- { name: "validAfter", type: "uint256" },
1920
- { name: "validBefore", type: "uint256" },
1921
- { name: "nonce", type: "bytes32" }
1922
- ]
1923
- },
1924
- primaryType: "TransferWithAuthorization",
1925
- message: input.message
1926
- };
1927
- }
1928
- async function readTokenMeta(publicClient, token2) {
1929
- const [tokenName, tokenVersion] = await Promise.all([
1930
- publicClient.readContract({ address: token2, abi: ERC20_META_ABI, functionName: "name" }),
1931
- publicClient.readContract({ address: token2, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
1932
- ]);
1933
- return { tokenName, tokenVersion };
1934
- }
1935
- function randomAuthNonce() {
1936
- const bytes = new Uint8Array(32);
1937
- globalThis.crypto.getRandomValues(bytes);
1938
- return (0, import_viem2.bytesToHex)(bytes);
1939
- }
1940
-
1941
- // src/lib/sponsor-client.ts
1942
- var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
1943
- async function postSponsorTransferAuth(input) {
1944
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
1945
- let res;
1946
- try {
1947
- res = await fetch(`${base5}/api/v1/sponsor/erc20-transfer-auth`, {
1948
- method: "POST",
1949
- headers: {
1950
- "content-type": "application/json",
1951
- "x-owney-api-key": input.apiKey,
1952
- ...input.yieldseekerSignature ? { "x-signature": input.yieldseekerSignature } : {}
1953
- },
1954
- body: JSON.stringify(input.body)
1955
- });
1956
- } catch (networkError) {
1923
+ async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
1924
+ const url = `${baseUrl}/api/v1/agent/keys`;
1925
+ const res = await fetch(url, {
1926
+ method: "GET",
1927
+ headers: {
1928
+ "Content-Type": "application/json",
1929
+ "x-owney-api-key": `${apiKey}`
1930
+ }
1931
+ });
1932
+ if (!res.ok) {
1933
+ const text = await res.text().catch(() => "");
1957
1934
  throw new OwneyError(
1958
- "SPONSOR_REQUEST_FAILED",
1959
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
1960
- { cause: String(networkError) }
1935
+ "API_ROUTING_ERROR",
1936
+ `Routing API error ${res.status}: ${text}`,
1937
+ { statusCode: res.status, responseBody: text }
1961
1938
  );
1962
1939
  }
1963
- const text = await res.text();
1964
- let parsed = null;
1965
- try {
1966
- parsed = JSON.parse(text);
1967
- } catch {
1968
- }
1969
- if (!res.ok || !parsed?.success || !parsed.data) {
1940
+ const json = await res.json();
1941
+ if (!json.success) {
1970
1942
  throw new OwneyError(
1971
- "SPONSOR_REQUEST_FAILED",
1972
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1973
- {
1974
- statusCode: res.status,
1975
- responseBody: text.slice(0, 500),
1976
- // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
1977
- // before broadcast, so it is safe to fall back to a user-paid deposit.
1978
- safeToFallback: res.status === 503
1979
- }
1943
+ "API_ROUTING_FAILED",
1944
+ `Routing API request failed: ${json.message}`,
1945
+ { message: json.message }
1980
1946
  );
1981
1947
  }
1982
- return parsed.data;
1948
+ return json.data;
1983
1949
  }
1984
- async function postSponsorPermit2Transfer(input) {
1985
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
1986
- let res;
1950
+
1951
+ // src/lib/health-report.ts
1952
+ var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
1953
+ async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
1987
1954
  try {
1988
- res = await fetch(`${base5}/api/v1/sponsor/permit2-transfer`, {
1955
+ await fetch(`${baseUrl}/api/v1/agent/health-report`, {
1989
1956
  method: "POST",
1990
1957
  headers: {
1991
- "content-type": "application/json",
1992
- "x-owney-api-key": input.apiKey,
1993
- ...input.yieldseekerSignature ? { "x-signature": input.yieldseekerSignature } : {}
1958
+ "Content-Type": "application/json",
1959
+ "x-owney-api-key": apiKey
1994
1960
  },
1995
- body: JSON.stringify(input.body)
1961
+ body: JSON.stringify({
1962
+ agent_type: agentType,
1963
+ error_code: errorCode,
1964
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1965
+ })
1996
1966
  });
1997
- } catch (networkError) {
1998
- throw new OwneyError(
1999
- "SPONSOR_REQUEST_FAILED",
2000
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2001
- { cause: String(networkError), safeToFallback: false }
1967
+ } catch (err) {
1968
+ console.warn(
1969
+ `[owney-sdk] health-report failed for agent "${agentType}":`,
1970
+ err instanceof Error ? err.message : err
2002
1971
  );
2003
1972
  }
2004
- const text = await res.text();
2005
- let parsed = null;
1973
+ }
1974
+ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
2006
1975
  try {
2007
- parsed = JSON.parse(text);
2008
- } catch {
2009
- }
2010
- if (!res.ok || !parsed?.success || !parsed.data) {
2011
- throw new OwneyError(
2012
- "SPONSOR_REQUEST_FAILED",
2013
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2014
- {
2015
- statusCode: res.status,
2016
- responseBody: text.slice(0, 500),
2017
- safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
2018
- }
2019
- );
1976
+ return await fn();
1977
+ } catch (err) {
1978
+ const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
1979
+ void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
1980
+ throw err;
2020
1981
  }
2021
- return parsed.data;
2022
1982
  }
2023
- async function getSponsorRelayerAddress(input) {
2024
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2025
- let res;
2026
- try {
2027
- res = await fetch(
2028
- `${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2029
- {
2030
- headers: { "x-owney-api-key": input.apiKey }
2031
- }
2032
- );
2033
- } catch (networkError) {
2034
- throw new OwneyError(
2035
- "SPONSOR_REQUEST_FAILED",
2036
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2037
- { cause: String(networkError), safeToFallback: true }
1983
+
1984
+ // src/lib/helpers/withdraw-helper.ts
1985
+ var import_viem2 = require("viem");
1986
+ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
1987
+ const target = asset.toUpperCase();
1988
+ return agents.map((agent) => {
1989
+ const agentBalance = aggregated[agent.id];
1990
+ const tokenBalance = agentBalance?.tokens.find(
1991
+ (t) => t.chainId === chainId && t.asset.toUpperCase() === target
2038
1992
  );
2039
- }
2040
- const text = await res.text();
2041
- let parsed = null;
2042
- try {
1993
+ if (!tokenBalance) return { agent, balance: 0n };
1994
+ return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
1995
+ });
1996
+ }
1997
+ function planProportionalShares(balances, requested, totalAvailable) {
1998
+ const plans = balances.map(({ agent, balance }) => ({
1999
+ agent,
2000
+ balance,
2001
+ planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
2002
+ }));
2003
+ const assigned = plans.reduce((s, p) => s + p.planned, 0n);
2004
+ let remainder = requested - assigned;
2005
+ const byHeadroom = [...plans].sort((a, b) => {
2006
+ const diff = b.balance - b.planned - (a.balance - a.planned);
2007
+ return diff > 0n ? 1 : diff < 0n ? -1 : 0;
2008
+ });
2009
+ for (const p of byHeadroom) {
2010
+ if (remainder === 0n) break;
2011
+ const headroom = p.balance - p.planned;
2012
+ if (headroom <= 0n) continue;
2013
+ const take = headroom < remainder ? headroom : remainder;
2014
+ p.planned += take;
2015
+ remainder -= take;
2016
+ }
2017
+ return plans;
2018
+ }
2019
+ function planDisabledDrain(disabled, requested) {
2020
+ const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
2021
+ const plans = [];
2022
+ let remaining = requested;
2023
+ for (const { agent, balance } of sorted) {
2024
+ if (remaining === 0n) {
2025
+ plans.push({ agent, balance, planned: 0n });
2026
+ continue;
2027
+ }
2028
+ const take = balance < remaining ? balance : remaining;
2029
+ plans.push({ agent, balance, planned: take });
2030
+ remaining -= take;
2031
+ }
2032
+ return { plans, remaining };
2033
+ }
2034
+ function redistributeShare(plans, fromIndex, amount, candidatePool) {
2035
+ const pool = candidatePool ?? plans.slice(fromIndex + 1);
2036
+ const candidates = pool.filter((c) => c.balance - c.planned > 0n);
2037
+ const totalHeadroom = candidates.reduce(
2038
+ (s, c) => s + (c.balance - c.planned),
2039
+ 0n
2040
+ );
2041
+ if (totalHeadroom === 0n) return;
2042
+ let distributed = 0n;
2043
+ for (const c of candidates) {
2044
+ const headroom = c.balance - c.planned;
2045
+ const proportional = headroom * amount / totalHeadroom;
2046
+ const give = proportional > headroom ? headroom : proportional;
2047
+ c.planned += give;
2048
+ distributed += give;
2049
+ }
2050
+ let leftover = amount - distributed;
2051
+ for (const c of candidates) {
2052
+ if (leftover === 0n) break;
2053
+ const headroom = c.balance - c.planned;
2054
+ if (headroom <= 0n) continue;
2055
+ const take = headroom < leftover ? headroom : leftover;
2056
+ c.planned += take;
2057
+ leftover -= take;
2058
+ }
2059
+ }
2060
+ function sumWithdrawnAmount(results) {
2061
+ return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
2062
+ }
2063
+
2064
+ // src/lib/helpers/account-apy-helper.ts
2065
+ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
2066
+ const sums = {};
2067
+ const weights = {};
2068
+ for (const id of Object.keys(agentApys)) {
2069
+ const cells = agentApys[id].apyByChainAndAsset;
2070
+ const balance = agentBalances[id] ?? 0;
2071
+ if (!cells || balance <= 0) continue;
2072
+ for (const [chainKey, perAsset] of Object.entries(cells)) {
2073
+ if (!perAsset) continue;
2074
+ const chainId = Number(chainKey);
2075
+ for (const [asset, apyValue] of Object.entries(perAsset)) {
2076
+ const apy = Number(apyValue ?? 0);
2077
+ if (apy === 0) continue;
2078
+ sums[chainId] ??= {};
2079
+ weights[chainId] ??= {};
2080
+ sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
2081
+ weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2082
+ }
2083
+ }
2084
+ }
2085
+ const out = {};
2086
+ for (const chainKey of Object.keys(sums)) {
2087
+ const chainId = Number(chainKey);
2088
+ const perAssetOut = {};
2089
+ for (const asset of Object.keys(sums[chainId])) {
2090
+ const w = weights[chainId][asset];
2091
+ if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
2092
+ }
2093
+ if (Object.keys(perAssetOut).length > 0) {
2094
+ out[chainId] = perAssetOut;
2095
+ }
2096
+ }
2097
+ return out;
2098
+ }
2099
+
2100
+ // src/client.ts
2101
+ var import_viem6 = require("viem");
2102
+ var import_chains2 = require("viem/chains");
2103
+
2104
+ // src/lib/transfer-auth.ts
2105
+ var import_viem3 = require("viem");
2106
+ var ERC20_META_ABI = [
2107
+ { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
2108
+ { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
2109
+ ];
2110
+ function buildTransferWithAuthorizationTypedData(input) {
2111
+ return {
2112
+ domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
2113
+ types: {
2114
+ TransferWithAuthorization: [
2115
+ { name: "from", type: "address" },
2116
+ { name: "to", type: "address" },
2117
+ { name: "value", type: "uint256" },
2118
+ { name: "validAfter", type: "uint256" },
2119
+ { name: "validBefore", type: "uint256" },
2120
+ { name: "nonce", type: "bytes32" }
2121
+ ]
2122
+ },
2123
+ primaryType: "TransferWithAuthorization",
2124
+ message: input.message
2125
+ };
2126
+ }
2127
+ async function readTokenMeta(publicClient, token) {
2128
+ const [tokenName, tokenVersion] = await Promise.all([
2129
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
2130
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
2131
+ ]);
2132
+ return { tokenName, tokenVersion };
2133
+ }
2134
+ function randomAuthNonce() {
2135
+ const bytes = new Uint8Array(32);
2136
+ globalThis.crypto.getRandomValues(bytes);
2137
+ return (0, import_viem3.bytesToHex)(bytes);
2138
+ }
2139
+
2140
+ // src/lib/sponsor-client.ts
2141
+ var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2142
+ async function postSponsorTransferAuth(input) {
2143
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2144
+ let res;
2145
+ try {
2146
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2147
+ method: "POST",
2148
+ headers: {
2149
+ "content-type": "application/json",
2150
+ "x-owney-api-key": input.apiKey
2151
+ },
2152
+ body: JSON.stringify(input.body)
2153
+ });
2154
+ } catch (networkError) {
2155
+ throw new OwneyError(
2156
+ "SPONSOR_REQUEST_FAILED",
2157
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2158
+ { cause: String(networkError) }
2159
+ );
2160
+ }
2161
+ const text = await res.text();
2162
+ let parsed = null;
2163
+ try {
2164
+ parsed = JSON.parse(text);
2165
+ } catch {
2166
+ }
2167
+ if (!res.ok || !parsed?.success || !parsed.data) {
2168
+ throw new OwneyError(
2169
+ "SPONSOR_REQUEST_FAILED",
2170
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2171
+ {
2172
+ statusCode: res.status,
2173
+ responseBody: text.slice(0, 500),
2174
+ // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2175
+ // before broadcast, so it is safe to fall back to a user-paid deposit.
2176
+ safeToFallback: res.status === 503
2177
+ }
2178
+ );
2179
+ }
2180
+ return parsed.data;
2181
+ }
2182
+ async function postSponsorPermit2Transfer(input) {
2183
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2184
+ let res;
2185
+ try {
2186
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2187
+ method: "POST",
2188
+ headers: {
2189
+ "content-type": "application/json",
2190
+ "x-owney-api-key": input.apiKey
2191
+ },
2192
+ body: JSON.stringify(input.body)
2193
+ });
2194
+ } catch (networkError) {
2195
+ throw new OwneyError(
2196
+ "SPONSOR_REQUEST_FAILED",
2197
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2198
+ { cause: String(networkError), safeToFallback: false }
2199
+ );
2200
+ }
2201
+ const text = await res.text();
2202
+ let parsed = null;
2203
+ try {
2204
+ parsed = JSON.parse(text);
2205
+ } catch {
2206
+ }
2207
+ if (!res.ok || !parsed?.success || !parsed.data) {
2208
+ throw new OwneyError(
2209
+ "SPONSOR_REQUEST_FAILED",
2210
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2211
+ {
2212
+ statusCode: res.status,
2213
+ responseBody: text.slice(0, 500),
2214
+ safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
2215
+ }
2216
+ );
2217
+ }
2218
+ return parsed.data;
2219
+ }
2220
+ async function getSponsorRelayerAddress(input) {
2221
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2222
+ let res;
2223
+ try {
2224
+ res = await fetch(
2225
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2226
+ {
2227
+ headers: { "x-owney-api-key": input.apiKey }
2228
+ }
2229
+ );
2230
+ } catch (networkError) {
2231
+ throw new OwneyError(
2232
+ "SPONSOR_REQUEST_FAILED",
2233
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2234
+ { cause: String(networkError), safeToFallback: true }
2235
+ );
2236
+ }
2237
+ const text = await res.text();
2238
+ let parsed = null;
2239
+ try {
2043
2240
  parsed = JSON.parse(text);
2044
2241
  } catch {
2045
2242
  }
@@ -2058,7 +2255,7 @@ async function getSponsorRelayerAddress(input) {
2058
2255
  }
2059
2256
 
2060
2257
  // src/lib/permit2.ts
2061
- var import_viem3 = require("viem");
2258
+ var import_viem4 = require("viem");
2062
2259
  var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2063
2260
  var MAX_UINT256 = 2n ** 256n - 1n;
2064
2261
  var ERC20_ALLOWANCE_ABI = [
@@ -2109,1398 +2306,230 @@ function buildPermitTransferFromTypedData(input) {
2109
2306
  { name: "amount", type: "uint256" }
2110
2307
  ]
2111
2308
  },
2112
- primaryType: "PermitTransferFrom",
2113
- message: input.message
2114
- };
2115
- }
2116
- function randomPermit2Nonce() {
2117
- const bytes = new Uint8Array(32);
2118
- globalThis.crypto.getRandomValues(bytes);
2119
- return BigInt((0, import_viem3.bytesToHex)(bytes));
2120
- }
2121
- async function readPermit2Allowance(publicClient, token2, owner) {
2122
- return publicClient.readContract({
2123
- address: token2,
2124
- abi: ERC20_ALLOWANCE_ABI,
2125
- functionName: "allowance",
2126
- args: [owner, PERMIT2_ADDRESS]
2127
- });
2128
- }
2129
- async function readErc20Balance(publicClient, token2, owner) {
2130
- return publicClient.readContract({
2131
- address: token2,
2132
- abi: ERC20_ALLOWANCE_ABI,
2133
- functionName: "balanceOf",
2134
- args: [owner]
2135
- });
2136
- }
2137
-
2138
- // src/lib/sponsored-deposit.ts
2139
- var AUTH_WINDOW_SECONDS = 15 * 60;
2140
- var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
2141
- function provideDepositVerificationContext(callback, context) {
2142
- callback[verificationSetter]?.(context);
2143
- }
2144
- function makeVerificationAwareDepositCallback(implementation) {
2145
- let nextVerification;
2146
- const callback = async (smartWallet, chainId, amount) => {
2147
- const verification = nextVerification;
2148
- nextVerification = void 0;
2149
- return implementation(smartWallet, chainId, amount, verification);
2150
- };
2151
- Object.defineProperty(callback, verificationSetter, {
2152
- value: (context) => {
2153
- nextVerification = context;
2154
- }
2155
- });
2156
- return callback;
2157
- }
2158
- function makeSponsoredDepositCallback(deps) {
2159
- const post = deps.httpPost ?? postSponsorTransferAuth;
2160
- return makeVerificationAwareDepositCallback(
2161
- async (smartWallet, chainId, amount, verification) => {
2162
- const cid = chainId;
2163
- const token2 = deps.tokenAddressByChain[cid];
2164
- if (!token2) {
2165
- throw new OwneyError(
2166
- "CHAIN_UNSUPPORTED",
2167
- `No sponsored token configured for chain ${chainId}`
2168
- );
2169
- }
2170
- const pub = deps.getPublicClient(cid);
2171
- const wallet = deps.getWalletClient(cid);
2172
- await ensureWalletOnChain(pub, wallet, cid);
2173
- try {
2174
- const balance = await readErc20Balance(pub, token2, deps.ownerAddress);
2175
- if (balance < BigInt(amount)) {
2176
- throw new OwneyError(
2177
- "DEPOSIT_INSUFFICIENT_BALANCE",
2178
- "Insufficient balance for this deposit.",
2179
- { token: token2, chainId: cid, balance: balance.toString(), amount }
2180
- );
2181
- }
2182
- } catch (err) {
2183
- if (err instanceof OwneyError) throw err;
2184
- console.warn(
2185
- "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2186
- err instanceof Error ? err.message : String(err)
2187
- );
2188
- }
2189
- const { tokenName, tokenVersion } = await readTokenMeta(pub, token2);
2190
- const validAfter = 0n;
2191
- const validBefore = BigInt(
2192
- Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2193
- );
2194
- const nonce = randomAuthNonce();
2195
- const typedData = buildTransferWithAuthorizationTypedData({
2196
- token: token2,
2197
- chainId: cid,
2198
- tokenName,
2199
- tokenVersion,
2200
- message: {
2201
- from: deps.ownerAddress,
2202
- to: smartWallet,
2203
- value: BigInt(amount),
2204
- validAfter,
2205
- validBefore,
2206
- nonce
2207
- }
2208
- });
2209
- const authSignature = await wallet.signTypedData({
2210
- account: deps.ownerAddress,
2211
- ...typedData
2212
- });
2213
- deps.onApproved?.();
2214
- const result = await post({
2215
- baseUrl: deps.baseUrl,
2216
- apiKey: deps.apiKey,
2217
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
2218
- body: {
2219
- chainId: cid,
2220
- token: token2,
2221
- from: deps.ownerAddress,
2222
- to: smartWallet,
2223
- value: amount,
2224
- validAfter: validAfter.toString(),
2225
- validBefore: validBefore.toString(),
2226
- nonce,
2227
- authSignature,
2228
- tokenName,
2229
- tokenVersion
2230
- }
2231
- });
2232
- return result.txHash;
2233
- }
2234
- );
2235
- }
2236
-
2237
- // src/agents/yieldseeker/yieldseeker.auth.ts
2238
- var import_siwe = require("siwe");
2239
- var import_viem4 = require("viem");
2240
- var import_chains2 = require("viem/chains");
2241
-
2242
- // src/agents/yieldseeker/yieldseeker.auth-cache.ts
2243
- var KEY_PREFIX2 = "owney.yieldseeker.session";
2244
- var storage2 = () => {
2245
- if (typeof window === "undefined") return null;
2246
- try {
2247
- return window.localStorage;
2248
- } catch {
2249
- return null;
2250
- }
2251
- };
2252
- var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2253
- var memorySessions2 = /* @__PURE__ */ new Map();
2254
- var isValidSession = (session) => {
2255
- if (!session?.token) return false;
2256
- try {
2257
- const parsed = JSON.parse(atob(session.token));
2258
- return typeof parsed.message === "string" && typeof parsed.signature === "string" && parsed.signature.startsWith("0x");
2259
- } catch {
2260
- return false;
2261
- }
2262
- };
2263
- var readYieldseekerSession = (address, chainId) => {
2264
- if (typeof window === "undefined") return null;
2265
- const key2 = buildKey2(address, chainId);
2266
- const store = storage2();
2267
- let raw = null;
2268
- try {
2269
- raw = store?.getItem(key2) ?? null;
2270
- } catch {
2271
- raw = null;
2272
- }
2273
- if (raw) {
2274
- try {
2275
- const parsed = JSON.parse(raw);
2276
- if (isValidSession(parsed)) return parsed.token;
2277
- } catch {
2278
- }
2279
- memorySessions2.delete(key2);
2280
- try {
2281
- store?.removeItem(key2);
2282
- } catch {
2283
- }
2284
- return null;
2285
- }
2286
- const cached = memorySessions2.get(key2);
2287
- if (isValidSession(cached)) return cached.token;
2288
- if (cached) memorySessions2.delete(key2);
2289
- return null;
2290
- };
2291
- var writeYieldseekerSession = (address, chainId, token2) => {
2292
- if (typeof window === "undefined") return;
2293
- const session = { token: token2 };
2294
- if (!isValidSession(session)) return;
2295
- const key2 = buildKey2(address, chainId);
2296
- memorySessions2.set(key2, session);
2297
- const store = storage2();
2298
- try {
2299
- store?.setItem(key2, JSON.stringify(session));
2300
- } catch {
2301
- }
2302
- };
2303
- var clearYieldseekerSession = (address, chainId) => {
2304
- const key2 = buildKey2(address, chainId);
2305
- memorySessions2.delete(key2);
2306
- const store = storage2();
2307
- try {
2308
- store?.removeItem(key2);
2309
- } catch {
2310
- }
2311
- };
2312
-
2313
- // src/agents/yieldseeker/yieldseeker.auth.ts
2314
- function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
2315
- return new import_siwe.SiweMessage({
2316
- domain: "yieldseeker.xyz",
2317
- address: (0, import_viem4.getAddress)(address),
2318
- uri: "https://yieldseeker.xyz",
2319
- version: "1",
2320
- chainId,
2321
- nonce: (dependencies.nonce ?? import_siwe.generateNonce)(),
2322
- issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
2323
- }).prepareMessage();
2324
- }
2325
- function encodeYieldseekerAuthToken(token2) {
2326
- const bytes = new TextEncoder().encode(JSON.stringify(token2));
2327
- let binary = "";
2328
- for (const byte of bytes) binary += String.fromCharCode(byte);
2329
- return btoa(binary);
2330
- }
2331
- var YieldseekerAuth = class {
2332
- constructor(dependencies = {}) {
2333
- this.dependencies = dependencies;
2334
- }
2335
- dependencies;
2336
- tokens = /* @__PURE__ */ new Map();
2337
- pending = /* @__PURE__ */ new Map();
2338
- scopes = /* @__PURE__ */ new Map();
2339
- key(state, chainId) {
2340
- return `${state.walletAddress.toLowerCase()}:${chainId}`;
2341
- }
2342
- async getToken(state, chainId) {
2343
- const key2 = this.key(state, chainId);
2344
- const scope = { address: state.walletAddress, chainId };
2345
- this.scopes.set(key2, scope);
2346
- const cached = this.tokens.get(key2);
2347
- if (cached) return cached;
2348
- const persisted = readYieldseekerSession(scope.address, scope.chainId);
2349
- if (persisted) {
2350
- this.tokens.set(key2, persisted);
2351
- return persisted;
2352
- }
2353
- const inFlight = this.pending.get(key2);
2354
- if (inFlight) return inFlight;
2355
- const request = this.sign(state, chainId).then((token2) => {
2356
- this.tokens.set(key2, token2);
2357
- writeYieldseekerSession(scope.address, scope.chainId, token2);
2358
- return token2;
2359
- });
2360
- this.pending.set(key2, request);
2361
- try {
2362
- return await request;
2363
- } finally {
2364
- this.pending.delete(key2);
2365
- }
2366
- }
2367
- clear(state, chainId) {
2368
- if (!state || chainId === void 0) {
2369
- for (const scope of this.scopes.values()) {
2370
- clearYieldseekerSession(scope.address, scope.chainId);
2371
- }
2372
- this.tokens.clear();
2373
- this.pending.clear();
2374
- this.scopes.clear();
2375
- return;
2376
- }
2377
- const key2 = this.key(state, chainId);
2378
- this.tokens.delete(key2);
2379
- this.pending.delete(key2);
2380
- this.scopes.delete(key2);
2381
- clearYieldseekerSession(state.walletAddress, chainId);
2382
- }
2383
- async sign(state, chainId) {
2384
- const account = (0, import_viem4.getAddress)(state.walletAddress);
2385
- const publicClient = (0, import_viem4.createPublicClient)({
2386
- chain: import_chains2.base,
2387
- transport: (0, import_viem4.custom)(state.provider)
2388
- });
2389
- const walletClient = (0, import_viem4.createWalletClient)({
2390
- account,
2391
- chain: import_chains2.base,
2392
- transport: (0, import_viem4.custom)(state.provider)
2393
- });
2394
- await ensureWalletOnChain(
2395
- publicClient,
2396
- walletClient,
2397
- 8453
2398
- );
2399
- const message = createYieldseekerSiweMessage(
2400
- account,
2401
- chainId,
2402
- this.dependencies
2403
- );
2404
- const signature = await walletClient.signMessage({ account, message });
2405
- return encodeYieldseekerAuthToken({ message, signature });
2406
- }
2407
- };
2408
-
2409
- // src/agents/yieldseeker/yieldseeker.client.ts
2410
- var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2411
- function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
2412
- return `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/agent/yieldseeker`;
2413
- }
2414
- var YIELDSEEKER_API_BASE_URL = getYieldseekerProxyBaseUrl();
2415
- var YieldseekerApiError = class extends Error {
2416
- constructor(status, providerCode, responseFields) {
2417
- super(`Yieldseeker request failed (${status}): ${providerCode}`);
2418
- this.status = status;
2419
- this.providerCode = providerCode;
2420
- this.responseFields = responseFields;
2421
- this.name = "YieldseekerApiError";
2422
- }
2423
- status;
2424
- providerCode;
2425
- responseFields;
2426
- get isAuthenticationError() {
2427
- return this.status === 401 || this.status === 403;
2428
- }
2429
- };
2430
- function providerError(body, fallback) {
2431
- if (!body || typeof body !== "object") return { code: fallback };
2432
- const record = body;
2433
- return {
2434
- code: typeof record.message === "string" ? record.message : fallback,
2435
- fields: record.fields && typeof record.fields === "object" ? record.fields : void 0
2436
- };
2437
- }
2438
- var YieldseekerApiClient = class {
2439
- constructor(owneyApiKey, baseUrl = YIELDSEEKER_API_BASE_URL, fetchFn = fetch) {
2440
- this.owneyApiKey = owneyApiKey;
2441
- this.baseUrl = baseUrl;
2442
- this.fetchFn = fetchFn;
2443
- }
2444
- owneyApiKey;
2445
- baseUrl;
2446
- fetchFn;
2447
- async request(path, options = {}) {
2448
- const controller = new AbortController();
2449
- const timer = setTimeout(
2450
- () => controller.abort(),
2451
- options.timeoutMs ?? 15e3
2452
- );
2453
- try {
2454
- const response = await this.fetchFn(`${this.baseUrl}${path}`, {
2455
- method: options.method ?? "GET",
2456
- headers: {
2457
- "Content-Type": "application/json",
2458
- "x-owney-api-key": this.owneyApiKey,
2459
- ...options.signature ? { "X-Signature": options.signature } : {}
2460
- },
2461
- body: options.body ? JSON.stringify(options.body) : void 0,
2462
- signal: controller.signal
2463
- });
2464
- const payload = await response.json().catch(() => null);
2465
- if (!response.ok) {
2466
- const error = providerError(payload, `HTTP_${response.status}`);
2467
- throw new YieldseekerApiError(
2468
- response.status,
2469
- error.code,
2470
- error.fields
2471
- );
2472
- }
2473
- if (payload && typeof payload === "object" && payload.success === true && "data" in payload) {
2474
- return payload.data;
2475
- }
2476
- return payload;
2477
- } catch (error) {
2478
- if (error instanceof YieldseekerApiError) throw error;
2479
- if (error instanceof DOMException && error.name === "AbortError") {
2480
- throw new YieldseekerApiError(408, "REQUEST_TIMEOUT");
2481
- }
2482
- throw new YieldseekerApiError(0, "NETWORK_ERROR", {
2483
- cause: error instanceof Error ? error.message : String(error)
2484
- });
2485
- } finally {
2486
- clearTimeout(timer);
2487
- }
2488
- }
2489
- };
2490
-
2491
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2492
- var import_viem5 = require("viem");
2493
- var REBALANCE_AMOUNT_DECIMALS = {
2494
- USDC: 6,
2495
- WETH: 18
2496
- };
2497
- function rebalanceAmount(value, tokenSymbol) {
2498
- const decimals = REBALANCE_AMOUNT_DECIMALS[tokenSymbol.toUpperCase()];
2499
- if (decimals === void 0) {
2500
- return invalid(
2501
- "history",
2502
- `unsupported rebalance token ${tokenSymbol || "<empty>"}`
2503
- );
2504
- }
2505
- try {
2506
- return (0, import_viem5.formatUnits)(BigInt(value), decimals);
2507
- } catch {
2508
- return invalid("history", `invalid rebalance amount ${value}`);
2509
- }
2510
- }
2511
- function invalid(endpoint, detail) {
2512
- throw new OwneyError(
2513
- "AGENT_INVALID_RESPONSE",
2514
- `Yieldseeker returned an invalid ${endpoint} response: ${detail}.`,
2515
- { endpoint, detail },
2516
- "yieldseeker"
2517
- );
2518
- }
2519
- function requireObject(value, endpoint) {
2520
- if (!value || typeof value !== "object" || Array.isArray(value)) {
2521
- return invalid(endpoint, "expected an object");
2522
- }
2523
- return value;
2524
- }
2525
- function requireEnvelope(value, key2, endpoint) {
2526
- const root = requireObject(value, endpoint);
2527
- return requireObject(root[key2], endpoint);
2528
- }
2529
- function token(value) {
2530
- return {
2531
- chain: value.chain,
2532
- chainId: value.chainId,
2533
- asset: value.asset,
2534
- amount: String(value.amount)
2535
- };
2536
- }
2537
- function position(value) {
2538
- return {
2539
- chain: String(value.chain),
2540
- protocol: String(value.protocol),
2541
- ...value.protocolId ? { protocolId: value.protocolId } : {},
2542
- ...value.pool ? { pool: value.pool } : {},
2543
- asset: String(value.asset),
2544
- amount: String(value.amount),
2545
- ...value.amountRaw !== void 0 ? { amountRaw: value.amountRaw } : {},
2546
- ...typeof value.apy === "number" ? { apy: value.apy } : {},
2547
- ...typeof value.tvl === "number" ? { tvl: value.tvl } : {},
2548
- ...typeof value.liquidity === "number" ? { liquidity: value.liquidity } : {}
2549
- };
2550
- }
2551
- function mapApyMatrix(matrix) {
2552
- const mapped = {};
2553
- for (const [chain, assets] of Object.entries(matrix ?? {})) {
2554
- const chainId = Number(chain);
2555
- if (chainId !== 8453 || !assets || typeof assets !== "object") continue;
2556
- mapped[8453] = {};
2557
- for (const [asset, apy] of Object.entries(assets)) {
2558
- if ((asset === "USDC" || asset === "WETH") && typeof apy === "number") {
2559
- mapped[8453][asset] = apy;
2560
- }
2561
- }
2562
- }
2563
- return mapped;
2564
- }
2565
- function mapYieldseekerProfile(value) {
2566
- const profile = requireEnvelope(
2567
- value,
2568
- "profile",
2569
- "profile"
2570
- );
2571
- if (typeof profile.address !== "string" || typeof profile.smartWallet !== "string" || !Array.isArray(profile.chains) || typeof profile.hasActiveSessionKey !== "boolean" || !Array.isArray(profile.protocols)) {
2572
- return invalid("profile", "missing required fields");
2573
- }
2574
- return {
2575
- address: profile.address,
2576
- smartWallet: profile.smartWallet,
2577
- chains: profile.chains.map(Number),
2578
- hasActiveSessionKey: profile.hasActiveSessionKey,
2579
- protocols: profile.protocols.map(String)
2580
- };
2581
- }
2582
- function mapYieldseekerBalances(value) {
2583
- const balances = requireEnvelope(
2584
- value,
2585
- "balances",
2586
- "balances"
2587
- );
2588
- if (typeof balances.smartWallet !== "string" || typeof balances.totalBalance !== "string" || typeof balances.totalBalanceAsset !== "string" || !Array.isArray(balances.tokens) || !Array.isArray(balances.positions)) {
2589
- return invalid("balances", "missing required fields");
2590
- }
2591
- return {
2592
- smartWallet: balances.smartWallet,
2593
- totalBalance: balances.totalBalance,
2594
- totalBalanceAsset: balances.totalBalanceAsset.toLowerCase(),
2595
- tokens: balances.tokens.map(token),
2596
- positions: balances.positions.map(position)
2597
- };
2598
- }
2599
- function mapYieldseekerEarnings(value) {
2600
- const earnings = requireEnvelope(
2601
- value,
2602
- "earnings",
2603
- "earnings"
2604
- );
2605
- if (typeof earnings.smartWallet !== "string" || typeof earnings.lifetimeEarnings !== "number" || !Array.isArray(earnings.tokens)) {
2606
- return invalid("earnings", "missing required fields");
2607
- }
2608
- return {
2609
- smartWallet: earnings.smartWallet,
2610
- lifetimeEarnings: earnings.lifetimeEarnings,
2611
- tokens: earnings.tokens.map(token)
2612
- };
2613
- }
2614
- function mapYieldseekerApy(value) {
2615
- const apy = requireEnvelope(
2616
- value,
2617
- "apy",
2618
- "apy"
2619
- );
2620
- if (typeof apy.walletAddress !== "string" || typeof apy.weightedApyAfterFee !== "number" || !apy.apyByChainAndAsset || typeof apy.apyByChainAndAsset !== "object" || !Array.isArray(apy.history)) {
2621
- return invalid("apy", "missing required fields");
2622
- }
2623
- return {
2624
- walletAddress: apy.walletAddress,
2625
- weightedApyAfterFee: apy.weightedApyAfterFee,
2626
- apyByChainAndAsset: mapApyMatrix(apy.apyByChainAndAsset),
2627
- history: apy.history.map((point) => ({
2628
- date: String(point.date),
2629
- apy: Number(point.apy)
2630
- }))
2631
- };
2632
- }
2633
- function historyAction(value) {
2634
- const normalized = value.trim().toLowerCase();
2635
- if (normalized === "rebalance") return "Rebalance";
2636
- if (normalized === "deposit") return "Deposit";
2637
- if (normalized === "top up" || normalized === "topup") return "Top up";
2638
- if (normalized === "withdraw" || normalized === "withdrawal")
2639
- return "Withdraw";
2640
- if (normalized === "earned" || normalized === "earnings") return "Earned";
2641
- return invalid("history", `unsupported action ${value}`);
2642
- }
2643
- function historyItem(value) {
2644
- return {
2645
- agent: "yieldseeker",
2646
- action: historyAction(value.action),
2647
- date: String(value.date),
2648
- oldApy: value.oldApy === null ? null : String(value.oldApy),
2649
- newApy: value.newApy === null ? null : String(value.newApy),
2650
- transactions: (value.transactions ?? []).map((transaction) => ({
2651
- txHashes: transaction.txHashes.map(String),
2652
- ...typeof transaction.chainId === "number" ? { chainId: transaction.chainId } : {},
2653
- ...typeof transaction.tokenSymbol === "string" ? { tokenSymbol: transaction.tokenSymbol } : {},
2654
- ...typeof transaction.amount === "string" ? { amount: transaction.amount } : {}
2655
- })),
2656
- rebalanceLog: (value.rebalanceLog ?? []).map((entry) => ({
2657
- fromProtocol: String(entry.fromProtocol),
2658
- toProtocol: String(entry.toProtocol),
2659
- ...entry.fromPool ? { fromPool: entry.fromPool } : {},
2660
- ...entry.toPool ? { toPool: entry.toPool } : {},
2661
- tokenSymbol: String(entry.tokenSymbol),
2662
- // Unlike Yieldseeker's other read-response amounts, live history
2663
- // rebalance amounts are returned in the token's smallest unit. Normalize
2664
- // them at the adapter boundary so every Owney consumer receives the
2665
- // shared human-readable decimal shape.
2666
- amount: rebalanceAmount(String(entry.amount), String(entry.tokenSymbol)),
2667
- status: entry.status
2668
- }))
2669
- };
2670
- }
2671
- function mapYieldseekerHistory(value) {
2672
- const history = requireEnvelope(
2673
- value,
2674
- "history",
2675
- "history"
2676
- );
2677
- if (!Array.isArray(history.data) || typeof history.hasMore !== "boolean") {
2678
- return invalid("history", "missing required fields");
2679
- }
2680
- return {
2681
- data: history.data.map(historyItem),
2682
- hasMore: history.hasMore,
2683
- ...history.hasMore && typeof history.nextCursor === "string" ? { nextCursor: history.nextCursor } : {}
2684
- };
2685
- }
2686
- function mapYieldseekerAgentApy(value) {
2687
- const agentApy = requireEnvelope(
2688
- value,
2689
- "agentApy",
2690
- "agent APY"
2691
- );
2692
- if (typeof agentApy.averageApy !== "number") {
2693
- return invalid("agent APY", "missing averageApy");
2694
- }
2695
- return {
2696
- averageApy: agentApy.averageApy,
2697
- ...agentApy.detailedApys ? {
2698
- detailedApys: {
2699
- apyPerAsset: mapApyMatrix(agentApy.detailedApys.apyPerAsset)
2700
- }
2701
- } : {}
2702
- };
2703
- }
2704
-
2705
- // src/agents/yieldseeker/yieldseeker.agent.ts
2706
- function query(params) {
2707
- const search = new URLSearchParams();
2708
- for (const [key2, value] of Object.entries(params)) {
2709
- if (value !== void 0) search.set(key2, String(value));
2710
- }
2711
- const encoded = search.toString();
2712
- return encoded ? `?${encoded}` : "";
2713
- }
2714
- var YieldseekerAgent = class {
2715
- id = "yieldseeker";
2716
- balanceComposition = "tokens-plus-positions";
2717
- supportedChainIds = [8453];
2718
- supportedAssets = [
2719
- {
2720
- chainId: 8453,
2721
- chain: "BASE",
2722
- assets: [
2723
- { symbol: "USDC", minDepositAmount: "1" },
2724
- { symbol: "WETH", minDepositAmount: "1" }
2725
- ]
2726
- }
2727
- ];
2728
- api;
2729
- auth;
2730
- transactionExecutor;
2731
- unwindReceiptWaiter;
2732
- activated = /* @__PURE__ */ new Set();
2733
- constructor(owneyApiKey, options = {}) {
2734
- this.api = new YieldseekerApiClient(
2735
- owneyApiKey,
2736
- options.baseUrl ?? getYieldseekerProxyBaseUrl(),
2737
- options.fetchFn
2738
- );
2739
- this.auth = new YieldseekerAuth(options.auth);
2740
- this.transactionExecutor = options.transactionExecutor;
2741
- this.unwindReceiptWaiter = options.unwindReceiptWaiter;
2742
- }
2743
- async disconnect() {
2744
- this.auth.clear();
2745
- this.activated.clear();
2746
- }
2747
- async activateAgent(state, chainId, asset) {
2748
- this.assertChain(chainId);
2749
- await this.auth.getToken(state, chainId);
2750
- if (asset === "USDC" || asset === "WETH") {
2751
- await this.ensureActivated(state, chainId, asset);
2752
- }
2753
- }
2754
- async deposit(state, chainId, amount, asset, depositCallback) {
2755
- this.assertChain(chainId);
2756
- this.assertAsset(asset);
2757
- if (BigInt(amount) <= 0n) {
2758
- throw new OwneyError(
2759
- "DEPOSIT_AMOUNT_BELOW_MINIMUM",
2760
- "Yieldseeker deposits must be greater than zero.",
2761
- { amount, minDepositAmount: "1" },
2762
- this.id
2763
- );
2764
- }
2765
- await this.ensureActivated(state, chainId, asset);
2766
- const response = await this.walletRequest(
2767
- state,
2768
- chainId,
2769
- "/deposits",
2770
- { method: "POST", body: { chainId, asset, amount } }
2771
- );
2772
- const deposit = response?.deposit;
2773
- if (!deposit?.transaction || typeof deposit.amount !== "string" || deposit.amount !== amount || typeof deposit.smartWallet !== "string" || !(0, import_viem6.isAddress)(deposit.smartWallet)) {
2774
- throw this.invalidResponse("deposit");
2775
- }
2776
- if (depositCallback) {
2777
- provideDepositVerificationContext(depositCallback, {
2778
- agentId: "yieldseeker",
2779
- // Re-read after /deposits so an authentication retry cannot forward
2780
- // the stale token that Yieldseeker just rejected.
2781
- signature: await this.auth.getToken(state, chainId)
2782
- });
2783
- }
2784
- const txHash = depositCallback ? await depositCallback(deposit.smartWallet, chainId, amount) : await this.submitTransaction(state, chainId, deposit.transaction);
2785
- const confirmation = await this.walletRequest(
2786
- state,
2787
- chainId,
2788
- "/deposits/confirm",
2789
- { method: "POST", body: { chainId, asset } }
2790
- );
2791
- if (typeof confirmation?.confirmation?.autoseekQueued !== "boolean") {
2792
- throw this.invalidResponse("deposit confirmation", {
2793
- transactionHash: txHash,
2794
- transactionConfirmed: true
2795
- });
2796
- }
2797
- return {
2798
- txHash,
2799
- smartWallet: deposit.smartWallet,
2800
- amount: deposit.amount
2801
- };
2802
- }
2803
- async withdraw(state, chainId, asset, amount) {
2804
- this.assertChain(chainId);
2805
- this.assertAsset(asset);
2806
- if (amount !== void 0 && BigInt(amount) <= 0n) {
2807
- throw new OwneyError(
2808
- "WITHDRAW_FAILED",
2809
- "Yieldseeker withdrawals must be greater than zero.",
2810
- { amount },
2811
- this.id
2812
- );
2813
- }
2814
- const balances = await this.getBalances(state, chainId);
2815
- const decimals = asset === "USDC" ? 6 : 18;
2816
- const targetAsset = asset.toUpperCase();
2817
- const idle = balances.tokens.filter(
2818
- (token2) => token2.chainId === chainId && token2.asset.toUpperCase() === targetAsset
2819
- ).reduce((total, token2) => total + (0, import_viem6.parseUnits)(token2.amount, decimals), 0n);
2820
- const positions = (balances.positions ?? []).filter(
2821
- (position2) => this.positionMatchesChain(position2.chain, chainId) && position2.asset.toUpperCase() === targetAsset
2822
- ).map((position2) => ({
2823
- position: position2,
2824
- amount: position2.amountRaw !== void 0 ? BigInt(position2.amountRaw) : (0, import_viem6.parseUnits)(position2.amount, decimals)
2825
- }));
2826
- const deployed = positions.reduce(
2827
- (total, position2) => total + position2.amount,
2828
- 0n
2829
- );
2830
- const totalAvailable = idle + deployed;
2831
- const requested = amount === void 0 ? totalAvailable : BigInt(amount);
2832
- if (requested > totalAvailable) {
2833
- throw new OwneyError(
2834
- "WITHDRAW_INSUFFICIENT_BALANCE",
2835
- `Requested withdrawal "${requested.toString()}" exceeds available Yieldseeker balance "${totalAvailable.toString()}" for asset "${asset}".`,
2836
- {
2837
- asset,
2838
- requested: requested.toString(),
2839
- available: totalAvailable.toString()
2840
- },
2841
- this.id
2842
- );
2843
- }
2844
- const requiredFromPositions = requested > idle ? requested - idle : 0n;
2845
- const unwindPlans = [];
2846
- let remainingToUnwind = requiredFromPositions;
2847
- for (const { position: position2, amount: positionAmount } of positions) {
2848
- if (remainingToUnwind === 0n) break;
2849
- if (positionAmount <= 0n) continue;
2850
- if (!position2.protocolId || !(0, import_viem6.isAddress)(position2.protocolId)) {
2851
- throw this.invalidResponse("position", {
2852
- reason: "A deployed position is missing its vault address.",
2853
- protocol: position2.protocol,
2854
- pool: position2.pool
2855
- });
2856
- }
2857
- const unwindAmount = positionAmount < remainingToUnwind ? positionAmount : remainingToUnwind;
2858
- unwindPlans.push({
2859
- vaultAddress: (0, import_viem6.getAddress)(position2.protocolId),
2860
- amount: unwindAmount
2861
- });
2862
- remainingToUnwind -= unwindAmount;
2863
- }
2864
- if (remainingToUnwind > 0n) {
2865
- throw this.invalidResponse("balances", {
2866
- reason: "Deployed position balances could not cover the unwind.",
2867
- required: requiredFromPositions.toString(),
2868
- planned: (requiredFromPositions - remainingToUnwind).toString()
2869
- });
2870
- }
2871
- for (const plan of unwindPlans) {
2872
- const response2 = await this.walletRequest(
2873
- state,
2874
- chainId,
2875
- "/positions/unwind",
2876
- {
2877
- method: "POST",
2878
- body: {
2879
- chainId,
2880
- asset,
2881
- vaultAddress: plan.vaultAddress,
2882
- amount: plan.amount.toString()
2883
- }
2884
- }
2885
- );
2886
- const transactionHash = response2?.unwind?.transactionHash;
2887
- if (!this.isTransactionHash(transactionHash)) {
2888
- throw this.invalidResponse("position unwind");
2889
- }
2890
- await this.waitForUnwindReceipt(state, chainId, transactionHash);
2891
- }
2892
- const response = await this.walletRequest(
2893
- state,
2894
- chainId,
2895
- "/withdrawals",
2896
- {
2897
- method: "POST",
2898
- body: { chainId, asset, ...amount !== void 0 ? { amount } : {} }
2899
- }
2900
- );
2901
- const withdrawal = response?.withdrawal;
2902
- if (!withdrawal?.transaction || typeof withdrawal.amount !== "string") {
2903
- throw this.invalidResponse("withdrawal");
2904
- }
2905
- const txHash = await this.submitTransaction(
2906
- state,
2907
- chainId,
2908
- withdrawal.transaction
2909
- );
2910
- return {
2911
- txHash,
2912
- type: amount === void 0 ? "full" : "partial",
2913
- amount: withdrawal.amount
2914
- };
2915
- }
2916
- async getBalances(state, chainId) {
2917
- return mapYieldseekerBalances(
2918
- await this.walletRequest(
2919
- state,
2920
- chainId,
2921
- `/balances${query({ chainId })}`
2922
- )
2923
- );
2924
- }
2925
- async getEarnings(state, chainId) {
2926
- return mapYieldseekerEarnings(
2927
- await this.walletRequest(
2928
- state,
2929
- chainId,
2930
- `/earnings${query({ chainId })}`
2931
- )
2932
- );
2933
- }
2934
- async getAccountApy(state, chainId, days, tokenSymbol) {
2935
- return mapYieldseekerApy(
2936
- await this.walletRequest(
2937
- state,
2938
- chainId,
2939
- `/apy${query({ chainId, days, tokenSymbol })}`
2940
- )
2941
- );
2942
- }
2943
- async getHistory(state, chainId, options) {
2944
- return mapYieldseekerHistory(
2945
- await this.walletRequest(
2946
- state,
2947
- chainId,
2948
- `/history${query({
2949
- chainId,
2950
- limit: options?.limit ?? 10,
2951
- cursor: options?.cursor,
2952
- fromDate: options?.fromDate,
2953
- toDate: options?.toDate
2954
- })}`
2955
- )
2956
- );
2957
- }
2958
- async getUserProfile(state, chainId) {
2959
- return mapYieldseekerProfile(
2960
- await this.walletRequest(state, chainId, `/profile${query({ chainId })}`)
2961
- );
2962
- }
2963
- async getAgentApy(days, options) {
2964
- this.assertOptionalChain(options?.chainId);
2965
- return mapYieldseekerAgentApy(
2966
- await this.api.request(
2967
- `/agent/apy${query({
2968
- days,
2969
- tokenSymbol: options?.tokenSymbol,
2970
- chainId: options?.chainId
2971
- })}`
2972
- )
2973
- );
2974
- }
2975
- async ensureActivated(state, chainId, asset) {
2976
- const key2 = `${state.walletAddress.toLowerCase()}:${chainId}:${asset}`;
2977
- if (this.activated.has(key2)) return;
2978
- const response = await this.walletRequest(
2979
- state,
2980
- chainId,
2981
- "/activation",
2982
- { method: "POST", body: { chainId, asset } }
2983
- );
2984
- if (typeof response?.activation?.smartWallet !== "string" || typeof response.activation.deployed !== "boolean" || typeof response.activation.hasActiveSessionKey !== "boolean") {
2985
- throw this.invalidResponse("activation");
2986
- }
2987
- this.activated.add(key2);
2988
- }
2989
- async walletRequest(state, chainId, path, options = {}) {
2990
- this.assertChain(chainId);
2991
- let signature = await this.auth.getToken(state, chainId);
2992
- try {
2993
- return await this.api.request(path, { ...options, signature });
2994
- } catch (error) {
2995
- if (!(error instanceof YieldseekerApiError)) throw error;
2996
- if (error.isAuthenticationError) {
2997
- this.auth.clear(state, chainId);
2998
- signature = await this.auth.getToken(state, chainId);
2999
- try {
3000
- return await this.api.request(path, { ...options, signature });
3001
- } catch (retryError) {
3002
- throw this.mapApiError(retryError);
3003
- }
3004
- }
3005
- throw this.mapApiError(error);
3006
- }
3007
- }
3008
- mapApiError(error) {
3009
- if (!(error instanceof YieldseekerApiError)) {
3010
- return new OwneyError(
3011
- "AGENT_API_ERROR",
3012
- "Yieldseeker request failed.",
3013
- { cause: error instanceof Error ? error.message : String(error) },
3014
- this.id
3015
- );
3016
- }
3017
- const code = error.isAuthenticationError ? "AGENT_AUTH_FAILED" : error.providerCode === "REQUEST_TIMEOUT" ? "AGENT_TIMEOUT" : "AGENT_API_ERROR";
3018
- return new OwneyError(
3019
- code,
3020
- `Yieldseeker request failed: ${error.providerCode}.`,
3021
- {
3022
- statusCode: error.status,
3023
- providerCode: error.providerCode,
3024
- ...error.responseFields ? { fields: error.responseFields } : {}
3025
- },
3026
- this.id
3027
- );
3028
- }
3029
- async submitTransaction(state, chainId, transaction) {
3030
- if (this.transactionExecutor) {
3031
- return this.transactionExecutor(state, chainId, transaction);
3032
- }
3033
- if (typeof transaction.from !== "string" || typeof transaction.to !== "string" || typeof transaction.data !== "string" || typeof transaction.value !== "string" || transaction.chainId !== chainId) {
3034
- throw this.invalidResponse("transaction");
3035
- }
3036
- const account = (0, import_viem6.getAddress)(state.walletAddress);
3037
- if ((0, import_viem6.getAddress)(transaction.from) !== account) {
3038
- throw this.invalidResponse("transaction", {
3039
- reason: "transaction.from does not match the connected wallet"
3040
- });
3041
- }
3042
- const walletClient = (0, import_viem6.createWalletClient)({
3043
- account,
3044
- chain: import_chains3.base,
3045
- transport: (0, import_viem6.custom)(state.provider)
3046
- });
3047
- const publicClient = (0, import_viem6.createPublicClient)({
3048
- chain: import_chains3.base,
3049
- transport: (0, import_viem6.custom)(state.provider)
3050
- });
3051
- await ensureWalletOnChain(
3052
- publicClient,
3053
- walletClient,
3054
- 8453
3055
- );
3056
- const hash = await walletClient.sendTransaction({
3057
- account,
3058
- chain: import_chains3.base,
3059
- to: (0, import_viem6.getAddress)(transaction.to),
3060
- data: transaction.data,
3061
- value: BigInt(transaction.value)
3062
- });
3063
- const receipt = await publicClient.waitForTransactionReceipt({
3064
- hash,
3065
- confirmations: 1
3066
- });
3067
- if (receipt.status !== "success") {
3068
- throw new OwneyError(
3069
- "AGENT_TRANSACTION_REVERTED",
3070
- `Yieldseeker transaction reverted (${hash}).`,
3071
- { transactionHash: hash },
3072
- this.id
3073
- );
3074
- }
3075
- return hash;
3076
- }
3077
- async waitForUnwindReceipt(state, chainId, transactionHash) {
3078
- if (this.unwindReceiptWaiter) {
3079
- await this.unwindReceiptWaiter(state, chainId, transactionHash);
3080
- return;
3081
- }
3082
- const publicClient = (0, import_viem6.createPublicClient)({
3083
- chain: import_chains3.base,
3084
- transport: (0, import_viem6.custom)(state.provider)
3085
- });
3086
- const receipt = await publicClient.waitForTransactionReceipt({
3087
- hash: transactionHash,
3088
- confirmations: 1
3089
- });
3090
- if (receipt.status !== "success") {
3091
- throw new OwneyError(
3092
- "AGENT_TRANSACTION_REVERTED",
3093
- `Yieldseeker position unwind reverted (${transactionHash}).`,
3094
- { transactionHash },
3095
- this.id
3096
- );
3097
- }
3098
- }
3099
- positionMatchesChain(chain, chainId) {
3100
- const normalized = chain.trim().toUpperCase();
3101
- return normalized === String(chainId) || normalized === "BASE";
3102
- }
3103
- isTransactionHash(value) {
3104
- return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
3105
- }
3106
- assertChain(chainId) {
3107
- if (chainId !== 8453) {
3108
- throw new OwneyError(
3109
- "CHAIN_UNSUPPORTED",
3110
- `Yieldseeker does not support chain ${chainId}.`,
3111
- { chainId, supportedChainIds: [8453] },
3112
- this.id
3113
- );
3114
- }
3115
- }
3116
- assertOptionalChain(chainId) {
3117
- if (chainId !== void 0) this.assertChain(chainId);
3118
- }
3119
- assertAsset(asset) {
3120
- if (asset !== "USDC" && asset !== "WETH") {
3121
- throw new OwneyError(
3122
- "ASSET_UNSUPPORTED",
3123
- `Yieldseeker does not support asset ${asset}.`,
3124
- { asset, supportedAssets: ["USDC", "WETH"] },
3125
- this.id
3126
- );
3127
- }
3128
- }
3129
- invalidResponse(operation, details = {}) {
3130
- return new OwneyError(
3131
- "AGENT_INVALID_RESPONSE",
3132
- `Yieldseeker returned an invalid ${operation} response.`,
3133
- details,
3134
- this.id
3135
- );
3136
- }
3137
- };
3138
-
3139
- // src/lib/routing-api.ts
3140
- var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
3141
- async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
3142
- const url = `${baseUrl}/api/v1/agent/org-config`;
3143
- try {
3144
- const res = await fetch(url, {
3145
- method: "GET",
3146
- headers: {
3147
- "Content-Type": "application/json",
3148
- "x-owney-api-key": `${apiKey}`
3149
- }
3150
- });
3151
- if (!res.ok) {
3152
- if (res.status !== 404) {
3153
- console.warn(
3154
- `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
3155
- );
3156
- }
3157
- return null;
3158
- }
3159
- const json = await res.json();
3160
- const policy = json.success ? json.data ?? null : null;
3161
- debugLog(
3162
- "owney-sdk",
3163
- policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
3164
- policy ?? void 0
3165
- );
3166
- return policy;
3167
- } catch (error) {
3168
- console.warn(
3169
- "[owney-sdk] Could not read org agent config (non-fatal):",
3170
- error instanceof Error ? error.message : String(error)
3171
- );
3172
- return null;
3173
- }
3174
- }
3175
- async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
3176
- const url = `${baseUrl}/api/v1/agent/keys`;
3177
- const res = await fetch(url, {
3178
- method: "GET",
3179
- headers: {
3180
- "Content-Type": "application/json",
3181
- "x-owney-api-key": `${apiKey}`
3182
- }
3183
- });
3184
- if (!res.ok) {
3185
- const text = await res.text().catch(() => "");
3186
- throw new OwneyError(
3187
- "API_ROUTING_ERROR",
3188
- `Routing API error ${res.status}: ${text}`,
3189
- { statusCode: res.status, responseBody: text }
3190
- );
3191
- }
3192
- const json = await res.json();
3193
- if (!json.success) {
3194
- throw new OwneyError(
3195
- "API_ROUTING_FAILED",
3196
- `Routing API request failed: ${json.message}`,
3197
- { message: json.message }
3198
- );
3199
- }
3200
- return json.data;
3201
- }
3202
-
3203
- // src/lib/health-report.ts
3204
- var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
3205
- async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL3) {
3206
- try {
3207
- await fetch(`${baseUrl}/api/v1/agent/health-report`, {
3208
- method: "POST",
3209
- headers: {
3210
- "Content-Type": "application/json",
3211
- "x-owney-api-key": apiKey
3212
- },
3213
- body: JSON.stringify({
3214
- agent_type: agentType,
3215
- error_code: errorCode,
3216
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
3217
- })
3218
- });
3219
- } catch (err) {
3220
- console.warn(
3221
- `[owney-sdk] health-report failed for agent "${agentType}":`,
3222
- err instanceof Error ? err.message : err
3223
- );
3224
- }
3225
- }
3226
- async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
3227
- try {
3228
- return await fn();
3229
- } catch (err) {
3230
- const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
3231
- void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
3232
- throw err;
3233
- }
3234
- }
3235
-
3236
- // src/lib/helpers/withdraw-helper.ts
3237
- var import_viem7 = require("viem");
3238
- function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
3239
- const target = asset.toUpperCase();
3240
- return agents.map((agent) => {
3241
- const agentBalance = aggregated[agent.id];
3242
- const tokenBalance = agentBalance?.tokens.find(
3243
- (t) => t.chainId === chainId && t.asset.toUpperCase() === target
3244
- );
3245
- let balance = tokenBalance ? (0, import_viem7.parseUnits)(tokenBalance.amount, decimals) : 0n;
3246
- if (agent.balanceComposition === "tokens-plus-positions") {
3247
- const chainNameById = {
3248
- 1: "ETHEREUM",
3249
- 8453: "BASE",
3250
- 42161: "ARBITRUM"
3251
- };
3252
- const targetChain = chainNameById[chainId];
3253
- for (const position2 of agentBalance?.positions ?? []) {
3254
- const positionChain = position2.chain.trim().toUpperCase();
3255
- const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
3256
- if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
3257
- if (position2.amountRaw !== void 0) {
3258
- try {
3259
- balance += BigInt(position2.amountRaw);
3260
- continue;
3261
- } catch {
3262
- }
3263
- }
3264
- balance += (0, import_viem7.parseUnits)(position2.amount, decimals);
3265
- }
3266
- }
3267
- return { agent, balance };
2309
+ primaryType: "PermitTransferFrom",
2310
+ message: input.message
2311
+ };
2312
+ }
2313
+ function randomPermit2Nonce() {
2314
+ const bytes = new Uint8Array(32);
2315
+ globalThis.crypto.getRandomValues(bytes);
2316
+ return BigInt((0, import_viem4.bytesToHex)(bytes));
2317
+ }
2318
+ async function readPermit2Allowance(publicClient, token, owner) {
2319
+ return publicClient.readContract({
2320
+ address: token,
2321
+ abi: ERC20_ALLOWANCE_ABI,
2322
+ functionName: "allowance",
2323
+ args: [owner, PERMIT2_ADDRESS]
3268
2324
  });
3269
2325
  }
3270
- function planProportionalShares(balances, requested, totalAvailable) {
3271
- const plans = balances.map(({ agent, balance }) => ({
3272
- agent,
3273
- balance,
3274
- planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
3275
- }));
3276
- const assigned = plans.reduce((s, p) => s + p.planned, 0n);
3277
- let remainder = requested - assigned;
3278
- const byHeadroom = [...plans].sort((a, b) => {
3279
- const diff = b.balance - b.planned - (a.balance - a.planned);
3280
- return diff > 0n ? 1 : diff < 0n ? -1 : 0;
2326
+ async function readErc20Balance(publicClient, token, owner) {
2327
+ return publicClient.readContract({
2328
+ address: token,
2329
+ abi: ERC20_ALLOWANCE_ABI,
2330
+ functionName: "balanceOf",
2331
+ args: [owner]
3281
2332
  });
3282
- for (const p of byHeadroom) {
3283
- if (remainder === 0n) break;
3284
- const headroom = p.balance - p.planned;
3285
- if (headroom <= 0n) continue;
3286
- const take = headroom < remainder ? headroom : remainder;
3287
- p.planned += take;
3288
- remainder -= take;
3289
- }
3290
- return plans;
3291
2333
  }
3292
- function planDisabledDrain(disabled, requested) {
3293
- const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
3294
- (a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
3295
- );
3296
- const plans = [];
3297
- let remaining = requested;
3298
- for (const { agent, balance } of sorted) {
3299
- if (remaining === 0n) {
3300
- plans.push({ agent, balance, planned: 0n });
3301
- continue;
3302
- }
3303
- const take = balance < remaining ? balance : remaining;
3304
- plans.push({ agent, balance, planned: take });
3305
- remaining -= take;
3306
- }
3307
- return { plans, remaining };
2334
+
2335
+ // src/lib/chain-guard.ts
2336
+ var CHAIN_NAMES = {
2337
+ 1: "Ethereum",
2338
+ 8453: "Base",
2339
+ 42161: "Arbitrum"
2340
+ };
2341
+ function chainName(chainId) {
2342
+ return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
3308
2343
  }
3309
- function redistributeShare(plans, fromIndex, amount, candidatePool) {
3310
- const pool = candidatePool ?? plans.slice(fromIndex + 1);
3311
- const candidates = pool.filter((c) => c.balance - c.planned > 0n);
3312
- const totalHeadroom = candidates.reduce(
3313
- (s, c) => s + (c.balance - c.planned),
3314
- 0n
3315
- );
3316
- if (totalHeadroom === 0n) return;
3317
- let distributed = 0n;
3318
- for (const c of candidates) {
3319
- const headroom = c.balance - c.planned;
3320
- const proportional = headroom * amount / totalHeadroom;
3321
- const give = proportional > headroom ? headroom : proportional;
3322
- c.planned += give;
3323
- distributed += give;
2344
+ async function ensureWalletOnChain(pub, wallet, expected) {
2345
+ const actual = await pub.getChainId();
2346
+ if (actual === expected) return;
2347
+ try {
2348
+ await wallet.switchChain({ id: expected });
2349
+ } catch (error) {
2350
+ throw new OwneyError(
2351
+ "CHAIN_MISMATCH",
2352
+ `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2353
+ {
2354
+ expectedChainId: expected,
2355
+ actualChainId: actual,
2356
+ cause: error instanceof Error ? error.message : String(error)
2357
+ }
2358
+ );
3324
2359
  }
3325
- let leftover = amount - distributed;
3326
- for (const c of candidates) {
3327
- if (leftover === 0n) break;
3328
- const headroom = c.balance - c.planned;
3329
- if (headroom <= 0n) continue;
3330
- const take = headroom < leftover ? headroom : leftover;
3331
- c.planned += take;
3332
- leftover -= take;
2360
+ const after = await pub.getChainId();
2361
+ if (after !== expected) {
2362
+ throw new OwneyError(
2363
+ "CHAIN_MISMATCH",
2364
+ `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2365
+ { expectedChainId: expected, actualChainId: after }
2366
+ );
3333
2367
  }
3334
2368
  }
3335
- function sumWithdrawnAmount(results) {
3336
- return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
3337
- }
3338
2369
 
3339
- // src/lib/helpers/account-apy-helper.ts
3340
- function balanceForApyScope(balance, chainId, tokenSymbol) {
3341
- if (!tokenSymbol) {
3342
- const total = Number(balance.totalBalance);
3343
- return Number.isFinite(total) && total > 0 ? total : 0;
3344
- }
3345
- const normalizedToken = tokenSymbol.toUpperCase();
3346
- return balance.tokens.reduce((total, token2) => {
3347
- if (Number(token2.chainId) !== chainId || String(token2.asset).toUpperCase() !== normalizedToken) {
3348
- return total;
3349
- }
3350
- const amount = Number(token2.amount);
3351
- return Number.isFinite(amount) && amount > 0 ? total + amount : total;
3352
- }, 0);
3353
- }
3354
- function aggregateApyHistory(agentApys, agentBalances) {
3355
- const byDate = /* @__PURE__ */ new Map();
3356
- for (const [id, accountApy] of Object.entries(agentApys)) {
3357
- const balance = agentBalances[id] ?? 0;
3358
- if (!Number.isFinite(balance) || balance <= 0) continue;
3359
- for (const point of accountApy.history ?? []) {
3360
- const apy = Number(point.apy);
3361
- if (!point.date || !Number.isFinite(apy)) continue;
3362
- const current = byDate.get(point.date) ?? { weightedSum: 0, weight: 0 };
3363
- current.weightedSum += apy * balance;
3364
- current.weight += balance;
3365
- byDate.set(point.date, current);
2370
+ // src/lib/sponsored-deposit.ts
2371
+ var AUTH_WINDOW_SECONDS = 15 * 60;
2372
+ function makeSponsoredDepositCallback(deps) {
2373
+ const post = deps.httpPost ?? postSponsorTransferAuth;
2374
+ return async (smartWallet, chainId, amount) => {
2375
+ const cid = chainId;
2376
+ const token = deps.tokenAddressByChain[cid];
2377
+ if (!token) {
2378
+ throw new OwneyError(
2379
+ "CHAIN_UNSUPPORTED",
2380
+ `No sponsored token configured for chain ${chainId}`
2381
+ );
3366
2382
  }
3367
- }
3368
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
3369
- date,
3370
- apy: value.weightedSum / value.weight
3371
- }));
3372
- }
3373
- function aggregateApyByChainAndAsset(agentApys, agentBalances) {
3374
- const sums = {};
3375
- const weights = {};
3376
- for (const id of Object.keys(agentApys)) {
3377
- const cells = agentApys[id].apyByChainAndAsset;
3378
- const balance = agentBalances[id] ?? 0;
3379
- if (!cells || balance <= 0) continue;
3380
- for (const [chainKey, perAsset] of Object.entries(cells)) {
3381
- if (!perAsset) continue;
3382
- const chainId = Number(chainKey);
3383
- for (const [asset, apyValue] of Object.entries(perAsset)) {
3384
- const apy = Number(apyValue ?? 0);
3385
- if (apy === 0) continue;
3386
- sums[chainId] ??= {};
3387
- weights[chainId] ??= {};
3388
- sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
3389
- weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2383
+ const pub = deps.getPublicClient(cid);
2384
+ const wallet = deps.getWalletClient(cid);
2385
+ await ensureWalletOnChain(pub, wallet, cid);
2386
+ try {
2387
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2388
+ if (balance < BigInt(amount)) {
2389
+ throw new OwneyError(
2390
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2391
+ "Insufficient balance for this deposit.",
2392
+ { token, chainId: cid, balance: balance.toString(), amount }
2393
+ );
3390
2394
  }
2395
+ } catch (err) {
2396
+ if (err instanceof OwneyError) throw err;
2397
+ console.warn(
2398
+ "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2399
+ err instanceof Error ? err.message : String(err)
2400
+ );
3391
2401
  }
3392
- }
3393
- const out = {};
3394
- for (const chainKey of Object.keys(sums)) {
3395
- const chainId = Number(chainKey);
3396
- const perAssetOut = {};
3397
- for (const asset of Object.keys(sums[chainId])) {
3398
- const w = weights[chainId][asset];
3399
- if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
3400
- }
3401
- if (Object.keys(perAssetOut).length > 0) {
3402
- out[chainId] = perAssetOut;
3403
- }
3404
- }
3405
- return out;
2402
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2403
+ const validAfter = 0n;
2404
+ const validBefore = BigInt(
2405
+ Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2406
+ );
2407
+ const nonce = randomAuthNonce();
2408
+ const typedData = buildTransferWithAuthorizationTypedData({
2409
+ token,
2410
+ chainId: cid,
2411
+ tokenName,
2412
+ tokenVersion,
2413
+ message: {
2414
+ from: deps.ownerAddress,
2415
+ to: smartWallet,
2416
+ value: BigInt(amount),
2417
+ validAfter,
2418
+ validBefore,
2419
+ nonce
2420
+ }
2421
+ });
2422
+ const authSignature = await wallet.signTypedData({
2423
+ account: deps.ownerAddress,
2424
+ ...typedData
2425
+ });
2426
+ deps.onApproved?.();
2427
+ const result = await post({
2428
+ baseUrl: deps.baseUrl,
2429
+ apiKey: deps.apiKey,
2430
+ body: {
2431
+ chainId: cid,
2432
+ token,
2433
+ from: deps.ownerAddress,
2434
+ to: smartWallet,
2435
+ value: amount,
2436
+ validAfter: validAfter.toString(),
2437
+ validBefore: validBefore.toString(),
2438
+ nonce,
2439
+ authSignature,
2440
+ tokenName,
2441
+ tokenVersion
2442
+ }
2443
+ });
2444
+ return result.txHash;
2445
+ };
3406
2446
  }
3407
2447
 
3408
- // src/client.ts
3409
- var import_viem9 = require("viem");
3410
- var import_chains4 = require("viem/chains");
3411
-
3412
2448
  // src/lib/sponsored-weth-deposit.ts
3413
2449
  var PERMIT_WINDOW_SECONDS = 15 * 60;
3414
2450
  function makeSponsoredWethCallback(deps) {
3415
2451
  const get = deps.httpGet ?? getSponsorRelayerAddress;
3416
2452
  const post = deps.httpPost ?? postSponsorPermit2Transfer;
3417
- return makeVerificationAwareDepositCallback(
3418
- async (smartWallet, chainId, amount, verification) => {
3419
- const cid = chainId;
3420
- const token2 = deps.tokenAddressByChain[cid];
3421
- if (!token2) {
3422
- throw new OwneyError(
3423
- "CHAIN_UNSUPPORTED",
3424
- `No sponsored WETH configured for chain ${chainId}`
3425
- );
3426
- }
3427
- const amountWei = BigInt(amount);
3428
- const pub = deps.getPublicClient(cid);
3429
- const wallet = deps.getWalletClient(cid);
3430
- await ensureWalletOnChain(pub, wallet, cid);
3431
- try {
3432
- const balance = await readErc20Balance(pub, token2, deps.ownerAddress);
3433
- if (balance < amountWei) {
3434
- throw new OwneyError(
3435
- "DEPOSIT_INSUFFICIENT_BALANCE",
3436
- "Insufficient WETH balance for this deposit.",
3437
- { token: token2, chainId: cid, balance: balance.toString(), amount }
3438
- );
3439
- }
3440
- } catch (err) {
3441
- if (err instanceof OwneyError) throw err;
3442
- console.warn(
3443
- "[owney-sdk] WETH balance pre-check failed (non-fatal):",
3444
- err instanceof Error ? err.message : String(err)
3445
- );
3446
- }
3447
- const allowance = await readPermit2Allowance(
3448
- pub,
3449
- token2,
3450
- deps.ownerAddress
2453
+ return async (smartWallet, chainId, amount) => {
2454
+ const cid = chainId;
2455
+ const token = deps.tokenAddressByChain[cid];
2456
+ if (!token) {
2457
+ throw new OwneyError(
2458
+ "CHAIN_UNSUPPORTED",
2459
+ `No sponsored WETH configured for chain ${chainId}`
3451
2460
  );
3452
- if (allowance < amountWei) {
2461
+ }
2462
+ const amountWei = BigInt(amount);
2463
+ const pub = deps.getPublicClient(cid);
2464
+ const wallet = deps.getWalletClient(cid);
2465
+ await ensureWalletOnChain(pub, wallet, cid);
2466
+ try {
2467
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2468
+ if (balance < amountWei) {
3453
2469
  throw new OwneyError(
3454
- "PERMIT2_APPROVAL_REQUIRED",
3455
- "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
3456
- { token: token2, chainId: cid, allowance: allowance.toString(), amount }
2470
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2471
+ "Insufficient WETH balance for this deposit.",
2472
+ { token, chainId: cid, balance: balance.toString(), amount }
3457
2473
  );
3458
2474
  }
3459
- const relayer = await get({
3460
- baseUrl: deps.baseUrl,
3461
- apiKey: deps.apiKey,
3462
- chainId: cid
3463
- });
3464
- const nonce = randomPermit2Nonce();
3465
- const deadline = BigInt(
3466
- Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2475
+ } catch (err) {
2476
+ if (err instanceof OwneyError) throw err;
2477
+ console.warn(
2478
+ "[owney-sdk] WETH balance pre-check failed (non-fatal):",
2479
+ err instanceof Error ? err.message : String(err)
3467
2480
  );
3468
- const typedData = buildPermitTransferFromTypedData({
3469
- chainId: cid,
3470
- message: {
3471
- permitted: { token: token2, amount: amountWei },
3472
- spender: relayer,
3473
- nonce,
3474
- deadline
3475
- }
3476
- });
3477
- const signature = await wallet.signTypedData({
3478
- account: deps.ownerAddress,
3479
- ...typedData
3480
- });
3481
- deps.onApproved?.();
3482
- const result = await post({
3483
- baseUrl: deps.baseUrl,
3484
- apiKey: deps.apiKey,
3485
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
3486
- body: {
3487
- chainId: cid,
3488
- token: token2,
3489
- from: deps.ownerAddress,
3490
- to: smartWallet,
3491
- amount,
3492
- nonce: nonce.toString(),
3493
- deadline: deadline.toString(),
3494
- signature
3495
- }
3496
- });
3497
- return result.txHash;
3498
2481
  }
3499
- );
2482
+ const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
2483
+ if (allowance < amountWei) {
2484
+ throw new OwneyError(
2485
+ "PERMIT2_APPROVAL_REQUIRED",
2486
+ "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
2487
+ { token, chainId: cid, allowance: allowance.toString(), amount }
2488
+ );
2489
+ }
2490
+ const relayer = await get({
2491
+ baseUrl: deps.baseUrl,
2492
+ apiKey: deps.apiKey,
2493
+ chainId: cid
2494
+ });
2495
+ const nonce = randomPermit2Nonce();
2496
+ const deadline = BigInt(
2497
+ Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2498
+ );
2499
+ const typedData = buildPermitTransferFromTypedData({
2500
+ chainId: cid,
2501
+ message: {
2502
+ permitted: { token, amount: amountWei },
2503
+ spender: relayer,
2504
+ nonce,
2505
+ deadline
2506
+ }
2507
+ });
2508
+ const signature = await wallet.signTypedData({
2509
+ account: deps.ownerAddress,
2510
+ ...typedData
2511
+ });
2512
+ deps.onApproved?.();
2513
+ const result = await post({
2514
+ baseUrl: deps.baseUrl,
2515
+ apiKey: deps.apiKey,
2516
+ body: {
2517
+ chainId: cid,
2518
+ token,
2519
+ from: deps.ownerAddress,
2520
+ to: smartWallet,
2521
+ amount,
2522
+ nonce: nonce.toString(),
2523
+ deadline: deadline.toString(),
2524
+ signature
2525
+ }
2526
+ });
2527
+ return result.txHash;
2528
+ };
3500
2529
  }
3501
2530
 
3502
2531
  // src/lib/sponsored-calls-deposit.ts
3503
- var import_viem8 = require("viem");
2532
+ var import_viem5 = require("viem");
3504
2533
  var DEFAULT_POLL_INTERVAL_MS = 1500;
3505
2534
  var DEFAULT_MAX_POLLS = 30;
3506
2535
  async function paymasterSupported(provider, owner, chainId) {
@@ -3508,7 +2537,7 @@ async function paymasterSupported(provider, owner, chainId) {
3508
2537
  method: "wallet_getCapabilities",
3509
2538
  params: [owner]
3510
2539
  });
3511
- const forChain = caps?.[(0, import_viem8.toHex)(chainId)] ?? caps?.[String(chainId)];
2540
+ const forChain = caps?.[(0, import_viem5.toHex)(chainId)] ?? caps?.[String(chainId)];
3512
2541
  return Boolean(forChain?.paymasterService?.supported);
3513
2542
  }
3514
2543
  function makeSponsoredCallsCallback(deps) {
@@ -3528,8 +2557,8 @@ function makeSponsoredCallsCallback(deps) {
3528
2557
  };
3529
2558
  return async (smartWallet, chainId, amount) => {
3530
2559
  const cid = chainId;
3531
- const token2 = deps.tokenAddressByChain[cid];
3532
- if (!token2) {
2560
+ const token = deps.tokenAddressByChain[cid];
2561
+ if (!token) {
3533
2562
  throw new OwneyError(
3534
2563
  "CHAIN_UNSUPPORTED",
3535
2564
  `No sponsored token configured for chain ${chainId}`
@@ -3542,8 +2571,8 @@ function makeSponsoredCallsCallback(deps) {
3542
2571
  { chainId }
3543
2572
  );
3544
2573
  }
3545
- const data = (0, import_viem8.encodeFunctionData)({
3546
- abi: import_viem8.erc20Abi,
2574
+ const data = (0, import_viem5.encodeFunctionData)({
2575
+ abi: import_viem5.erc20Abi,
3547
2576
  functionName: "transfer",
3548
2577
  args: [smartWallet, BigInt(amount)]
3549
2578
  });
@@ -3553,9 +2582,9 @@ function makeSponsoredCallsCallback(deps) {
3553
2582
  {
3554
2583
  version: "2.0.0",
3555
2584
  from: deps.ownerAddress,
3556
- chainId: (0, import_viem8.toHex)(chainId),
2585
+ chainId: (0, import_viem5.toHex)(chainId),
3557
2586
  atomicRequired: false,
3558
- calls: [{ to: token2, value: "0x0", data }],
2587
+ calls: [{ to: token, value: "0x0", data }],
3559
2588
  capabilities: {
3560
2589
  paymasterService: { url: absolutePaymasterUrl() }
3561
2590
  }
@@ -3594,10 +2623,10 @@ function makeSponsoredCallsCallback(deps) {
3594
2623
  function encodeMultiAgentCursor(map) {
3595
2624
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
3596
2625
  }
3597
- function decodeMultiAgentCursor(token2) {
2626
+ function decodeMultiAgentCursor(token) {
3598
2627
  let parsed;
3599
2628
  try {
3600
- const json = Buffer.from(token2, "base64").toString("utf8");
2629
+ const json = Buffer.from(token, "base64").toString("utf8");
3601
2630
  parsed = JSON.parse(json);
3602
2631
  } catch {
3603
2632
  throw new InvalidHistoryCursorError(
@@ -3617,9 +2646,9 @@ var SPONSORED_USDC_BY_CHAIN = {
3617
2646
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
3618
2647
  };
3619
2648
  var VIEM_CHAIN2 = {
3620
- 8453: import_chains4.base,
3621
- 42161: import_chains4.arbitrum,
3622
- 1: import_chains4.mainnet
2649
+ 8453: import_chains2.base,
2650
+ 42161: import_chains2.arbitrum,
2651
+ 1: import_chains2.mainnet
3623
2652
  };
3624
2653
  var SPONSORED_WETH_BY_CHAIN = {
3625
2654
  8453: "0x4200000000000000000000000000000000000006",
@@ -3647,7 +2676,6 @@ var OwneySDK = class {
3647
2676
  orgAgentConfig;
3648
2677
  orgAgentConfigPromise = null;
3649
2678
  zyfaiRpcUrls;
3650
- yieldseekerApiBaseUrl;
3651
2679
  routingApiBaseUrl;
3652
2680
  referralSource;
3653
2681
  cachedSponsoredCallback = null;
@@ -3659,7 +2687,6 @@ var OwneySDK = class {
3659
2687
  this.apiKey = config.apiKey;
3660
2688
  if (config.debug) setOwneyDebug(true);
3661
2689
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
3662
- this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
3663
2690
  this.routingApiBaseUrl = config.routingApiBaseUrl;
3664
2691
  this.paymasterServiceUrl = config.paymasterServiceUrl;
3665
2692
  this.referralSource = config.referralSource;
@@ -3762,14 +2789,14 @@ var OwneySDK = class {
3762
2789
  // Casts work around viem's chain-narrowed Client vs the generic
3763
2790
  // PublicClient/WalletClient param types — structurally identical at
3764
2791
  // runtime, but the two share a name TS treats as unrelated.
3765
- getPublicClient: (cid) => (0, import_viem9.createPublicClient)({
2792
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
3766
2793
  chain: VIEM_CHAIN2[cid],
3767
- transport: (0, import_viem9.custom)(provider)
2794
+ transport: (0, import_viem6.custom)(provider)
3768
2795
  }),
3769
- getWalletClient: (cid) => (0, import_viem9.createWalletClient)({
2796
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
3770
2797
  account: owner,
3771
2798
  chain: VIEM_CHAIN2[cid],
3772
- transport: (0, import_viem9.custom)(provider)
2799
+ transport: (0, import_viem6.custom)(provider)
3773
2800
  })
3774
2801
  });
3775
2802
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -3815,14 +2842,14 @@ var OwneySDK = class {
3815
2842
  // Casts work around viem's chain-narrowed Client vs the generic
3816
2843
  // PublicClient/WalletClient param types — structurally identical at
3817
2844
  // runtime, but the two share a name TS treats as unrelated.
3818
- getPublicClient: (cid) => (0, import_viem9.createPublicClient)({
2845
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
3819
2846
  chain: VIEM_CHAIN2[cid],
3820
- transport: (0, import_viem9.custom)(provider)
2847
+ transport: (0, import_viem6.custom)(provider)
3821
2848
  }),
3822
- getWalletClient: (cid) => (0, import_viem9.createWalletClient)({
2849
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
3823
2850
  account: owner,
3824
2851
  chain: VIEM_CHAIN2[cid],
3825
- transport: (0, import_viem9.custom)(provider)
2852
+ transport: (0, import_viem6.custom)(provider)
3826
2853
  })
3827
2854
  });
3828
2855
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -3853,10 +2880,12 @@ var OwneySDK = class {
3853
2880
  this.orgAgentConfigPromise = fetchOrgAgentConfig(
3854
2881
  this.apiKey,
3855
2882
  this.routingApiBaseUrl
3856
- ).then((config) => {
3857
- this.orgAgentConfig = config;
3858
- return config;
3859
- });
2883
+ ).then(
2884
+ (config) => {
2885
+ this.orgAgentConfig = config;
2886
+ return config;
2887
+ }
2888
+ );
3860
2889
  }
3861
2890
  return this.orgAgentConfigPromise;
3862
2891
  }
@@ -3896,14 +2925,7 @@ var OwneySDK = class {
3896
2925
  this.routingApiBaseUrl
3897
2926
  );
3898
2927
  this.disabledAgents.clear();
3899
- for (const {
3900
- key: key2,
3901
- agent_type,
3902
- is_enabled,
3903
- is_configured
3904
- } of agentKeys) {
3905
- const configured = is_configured ?? Boolean(key2);
3906
- if (!configured) continue;
2928
+ for (const { key: key2, agent_type, is_enabled } of agentKeys) {
3907
2929
  const agent = this.createAgent(agent_type, key2);
3908
2930
  if (!agent) continue;
3909
2931
  this.agents.set(agent_type, agent);
@@ -3927,47 +2949,10 @@ var OwneySDK = class {
3927
2949
  }
3928
2950
  createAgent(agentId, key2) {
3929
2951
  if (agentId === "zyfai") {
3930
- if (!key2) return null;
3931
2952
  return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
3932
2953
  }
3933
- if (agentId === "yieldseeker") {
3934
- return new YieldseekerAgent(this.apiKey, {
3935
- baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl)
3936
- });
3937
- }
3938
2954
  return null;
3939
2955
  }
3940
- /**
3941
- * Discover the agents actually returned by routing for this organization.
3942
- * Consumers should use this instead of hardcoding a global agent roster.
3943
- */
3944
- async getAvailableAgents(options = {}) {
3945
- await this.ensureAgentsInitialized();
3946
- const { chainId, asset, includeDisabled = false } = options;
3947
- const available = [];
3948
- for (const [id, agent] of this.agents) {
3949
- const isEnabled = !this.isAgentDisabled(id);
3950
- if (!includeDisabled && !isEnabled) continue;
3951
- if (chainId !== void 0 && !agent.supportedChainIds.includes(chainId)) {
3952
- continue;
3953
- }
3954
- if (asset !== void 0) {
3955
- const supportsAsset = agent.supportedAssets.some(
3956
- (entry) => (chainId === void 0 || entry.chainId === chainId) && entry.assets.some((candidate) => candidate.symbol === asset)
3957
- );
3958
- if (!supportsAsset) {
3959
- continue;
3960
- }
3961
- }
3962
- available.push({
3963
- id,
3964
- isEnabled,
3965
- supportedChainIds: agent.supportedChainIds,
3966
- supportedAssets: agent.supportedAssets
3967
- });
3968
- }
3969
- return available;
3970
- }
3971
2956
  // --- Account lifecycle ---
3972
2957
  /**
3973
2958
  * Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted.
@@ -3979,7 +2964,7 @@ var OwneySDK = class {
3979
2964
  * If provided, ALL specified agents must support the chainId or the call
3980
2965
  * throws before activating any agent.
3981
2966
  */
3982
- async activateAgent(chainId, agentId, asset) {
2967
+ async activateAgent(chainId, agentId) {
3983
2968
  const state = this.requireState();
3984
2969
  await this.ensureAgentsInitialized();
3985
2970
  if (agentId !== void 0) {
@@ -4015,7 +3000,9 @@ var OwneySDK = class {
4015
3000
  this.activeAgents.add(id);
4016
3001
  }
4017
3002
  state.chainId = chainId;
4018
- await this.activateAgentsInTurn(agents, state, chainId, asset);
3003
+ this.activateAgentsInTurn(agents, state, chainId).catch((error) => {
3004
+ console.error("activateAgent background init failed:", error);
3005
+ });
4019
3006
  return;
4020
3007
  }
4021
3008
  const compatible = [...this.agents.values()].filter(
@@ -4036,7 +3023,11 @@ var OwneySDK = class {
4036
3023
  const enabledCompatible = compatible.filter(
4037
3024
  (agent) => !this.isAgentDisabled(agent.id)
4038
3025
  );
4039
- await this.activateAgentsInTurn(enabledCompatible, state, chainId, asset);
3026
+ this.activateAgentsInTurn(enabledCompatible, state, chainId).catch(
3027
+ (error) => {
3028
+ console.error("activateAgent background init failed:", error);
3029
+ }
3030
+ );
4040
3031
  }
4041
3032
  /**
4042
3033
  * Activate agents ONE AT A TIME, each followed by its org policy.
@@ -4056,11 +3047,11 @@ var OwneySDK = class {
4056
3047
  * rethrown (matching the previous `Promise.all` rejection) once all agents
4057
3048
  * have had a chance to activate.
4058
3049
  */
4059
- async activateAgentsInTurn(agents, state, chainId, asset) {
3050
+ async activateAgentsInTurn(agents, state, chainId) {
4060
3051
  let firstError = null;
4061
3052
  for (const agent of agents) {
4062
3053
  try {
4063
- await agent.activateAgent(state, chainId, asset);
3054
+ await agent.activateAgent(state, chainId);
4064
3055
  await this.applyOrgPolicyTo(agent, state, chainId);
4065
3056
  } catch (error) {
4066
3057
  if (firstError === null) {
@@ -4269,10 +3260,10 @@ var OwneySDK = class {
4269
3260
  try {
4270
3261
  const balance = await agent.getBalances(state, chainId);
4271
3262
  const target = asset.toLowerCase();
4272
- const token2 = balance.tokens.find(
3263
+ const token = balance.tokens.find(
4273
3264
  (t) => t.chainId === chainId && t.asset.toLowerCase() === target
4274
3265
  );
4275
- return !!token2 && Number(token2.amount) > 0;
3266
+ return !!token && Number(token.amount) > 0;
4276
3267
  } catch {
4277
3268
  return false;
4278
3269
  }
@@ -4323,9 +3314,9 @@ var OwneySDK = class {
4323
3314
  const { asset, amount, agentId } = options;
4324
3315
  const state = this.requireState();
4325
3316
  const chainId = this.requireChainId();
4326
- const token2 = asset;
3317
+ const token = asset;
4327
3318
  const assetInfo = SupportedAssets.find(
4328
- (a) => a.chainId === chainId && a.symbol === token2
3319
+ (a) => a.chainId === chainId && a.symbol === token
4329
3320
  );
4330
3321
  if (!assetInfo) {
4331
3322
  throw new OwneyError(
@@ -4339,7 +3330,7 @@ var OwneySDK = class {
4339
3330
  return withFailureReporting(
4340
3331
  this.apiKey,
4341
3332
  agent.id,
4342
- () => agent.withdraw(state, chainId, token2, amount),
3333
+ () => agent.withdraw(state, chainId, token, amount),
4343
3334
  this.routingApiBaseUrl
4344
3335
  );
4345
3336
  }
@@ -4349,7 +3340,7 @@ var OwneySDK = class {
4349
3340
  const agentErrors2 = {};
4350
3341
  for (const agent of eligibleAgents) {
4351
3342
  try {
4352
- results2[agent.id] = await agent.withdraw(state, chainId, token2);
3343
+ results2[agent.id] = await agent.withdraw(state, chainId, token);
4353
3344
  } catch (err) {
4354
3345
  console.error(`withdraw failed for agent "${agent.id}":`, err);
4355
3346
  agentErrors2[agent.id] = err instanceof Error ? err.message : String(err);
@@ -4376,10 +3367,6 @@ var OwneySDK = class {
4376
3367
  }
4377
3368
  const requested = BigInt(amount);
4378
3369
  const aggregated = await this.getBalances();
4379
- const unavailableAgents = eligibleAgents.filter(
4380
- (agent) => !(agent.id in aggregated.agentBalances)
4381
- );
4382
- const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
4383
3370
  const balances = projectAgentBalancesForAsset(
4384
3371
  eligibleAgents,
4385
3372
  aggregated.agentBalances,
@@ -4388,18 +3375,7 @@ var OwneySDK = class {
4388
3375
  assetInfo.decimals
4389
3376
  );
4390
3377
  const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
4391
- if (totalAvailable === 0n && unavailableAgents.length > 0) {
4392
- throw new OwneyError(
4393
- "WITHDRAW_BALANCE_UNAVAILABLE",
4394
- `Cannot safely plan the withdrawal because balance data is unavailable for: ${unavailableAgentIds.join(", ")}.`,
4395
- {
4396
- asset,
4397
- unavailableAgents: unavailableAgentIds,
4398
- agentErrors: aggregated.agentErrors
4399
- }
4400
- );
4401
- }
4402
- if (totalAvailable < requested && unavailableAgents.length === 0) {
3378
+ if (totalAvailable < requested) {
4403
3379
  throw new OwneyError(
4404
3380
  "WITHDRAW_INSUFFICIENT_BALANCE",
4405
3381
  `Requested withdrawal "${amount}" exceeds available balance "${totalAvailable.toString()}" for asset "${asset}".`,
@@ -4410,7 +3386,6 @@ var OwneySDK = class {
4410
3386
  }
4411
3387
  );
4412
3388
  }
4413
- const plannedTarget = totalAvailable < requested ? totalAvailable : requested;
4414
3389
  const disabledBalances = balances.filter(
4415
3390
  (b) => this.isAgentDisabled(b.agent.id)
4416
3391
  );
@@ -4419,7 +3394,7 @@ var OwneySDK = class {
4419
3394
  );
4420
3395
  const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
4421
3396
  disabledBalances,
4422
- plannedTarget
3397
+ requested
4423
3398
  );
4424
3399
  const enabledTotal = enabledBalances.reduce((s, b) => s + b.balance, 0n);
4425
3400
  const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
@@ -4429,9 +3404,7 @@ var OwneySDK = class {
4429
3404
  }));
4430
3405
  const plans = [...disabledPlans, ...enabledPlans];
4431
3406
  const results = {};
4432
- const agentErrors = {
4433
- ...aggregated.agentErrors ?? {}
4434
- };
3407
+ const agentErrors = {};
4435
3408
  for (let i = 0; i < plans.length; i++) {
4436
3409
  const p = plans[i];
4437
3410
  if (p.planned === 0n) continue;
@@ -4439,7 +3412,7 @@ var OwneySDK = class {
4439
3412
  results[p.agent.id] = await p.agent.withdraw(
4440
3413
  state,
4441
3414
  chainId,
4442
- token2,
3415
+ token,
4443
3416
  p.planned.toString()
4444
3417
  );
4445
3418
  } catch (err) {
@@ -4478,8 +3451,7 @@ var OwneySDK = class {
4478
3451
  requested: amount,
4479
3452
  withdrawn: withdrawn.toString(),
4480
3453
  partialResults: results,
4481
- agentErrors,
4482
- ...unavailableAgentIds.length > 0 ? { unavailableAgents: unavailableAgentIds } : {}
3454
+ agentErrors
4483
3455
  }
4484
3456
  );
4485
3457
  }
@@ -4520,12 +3492,7 @@ var OwneySDK = class {
4520
3492
  continue;
4521
3493
  }
4522
3494
  const reason = settledResult.reason;
4523
- const message = reason instanceof Error ? reason.message : String(reason);
4524
- agentErrors[agentId2] = message;
4525
- console.error(
4526
- `[owney-sdk] Balance fetch failed for agent "${agentId2}":`,
4527
- reason
4528
- );
3495
+ agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
4529
3496
  }
4530
3497
  if (successCount === 0) {
4531
3498
  throw new OwneyError(
@@ -4537,8 +3504,7 @@ var OwneySDK = class {
4537
3504
  return {
4538
3505
  totalBalance: String(totalBalance),
4539
3506
  totalBalanceAsset: "usdc",
4540
- agentBalances: results,
4541
- ...Object.keys(agentErrors).length > 0 ? { agentErrors } : {}
3507
+ agentBalances: results
4542
3508
  };
4543
3509
  }
4544
3510
  /**
@@ -4632,10 +3598,7 @@ var OwneySDK = class {
4632
3598
  Promise.all(
4633
3599
  entries.map(async ([id, agent]) => {
4634
3600
  const b = await agent.getBalances(state, chainId);
4635
- return [
4636
- id,
4637
- balanceForApyScope(b, chainId, tokenSymbol)
4638
- ];
3601
+ return [id, Number(b.totalBalance)];
4639
3602
  })
4640
3603
  )
4641
3604
  ]);
@@ -4663,12 +3626,10 @@ var OwneySDK = class {
4663
3626
  }
4664
3627
  }
4665
3628
  const apyByChainAndAsset = aggregateApyByChainAndAsset(results, balances);
4666
- const history = aggregateApyHistory(results, balances);
4667
3629
  return {
4668
3630
  totalApy: String(totalApy),
4669
3631
  agentApy: results,
4670
- apyByChainAndAsset,
4671
- history
3632
+ apyByChainAndAsset
4672
3633
  };
4673
3634
  }
4674
3635
  /**
@@ -4790,30 +3751,30 @@ var OwneySDK = class {
4790
3751
  const state = this.requireState();
4791
3752
  const chainId = this.requireChainId();
4792
3753
  this.validateAssetSupport(this.getAgent("zyfai"), chainId, "WETH");
4793
- const token2 = SPONSORED_WETH_BY_CHAIN[chainId];
4794
- if (!token2) {
3754
+ const token = SPONSORED_WETH_BY_CHAIN[chainId];
3755
+ if (!token) {
4795
3756
  throw new OwneyError(
4796
3757
  "CHAIN_UNSUPPORTED",
4797
3758
  `No sponsored WETH on chain ${chainId}`
4798
3759
  );
4799
3760
  }
4800
3761
  const provider = this.requireConnectedProvider();
4801
- const wallet = (0, import_viem9.createWalletClient)({
3762
+ const wallet = (0, import_viem6.createWalletClient)({
4802
3763
  account: state.walletAddress,
4803
3764
  chain: VIEM_CHAIN2[chainId],
4804
- transport: (0, import_viem9.custom)(provider)
3765
+ transport: (0, import_viem6.custom)(provider)
4805
3766
  });
4806
3767
  const hash = await wallet.writeContract({
4807
- address: token2,
3768
+ address: token,
4808
3769
  abi: ERC20_ALLOWANCE_ABI,
4809
3770
  functionName: "approve",
4810
3771
  args: [PERMIT2_ADDRESS, MAX_UINT256],
4811
3772
  account: state.walletAddress,
4812
3773
  chain: VIEM_CHAIN2[chainId]
4813
3774
  });
4814
- const publicClient = (0, import_viem9.createPublicClient)({
3775
+ const publicClient = (0, import_viem6.createPublicClient)({
4815
3776
  chain: VIEM_CHAIN2[chainId],
4816
- transport: (0, import_viem9.custom)(provider)
3777
+ transport: (0, import_viem6.custom)(provider)
4817
3778
  });
4818
3779
  const receipt = await publicClient.waitForTransactionReceipt({
4819
3780
  hash,
@@ -4849,9 +3810,7 @@ var OwneySDK = class {
4849
3810
  return this.getAgent(agentId).getAgentApy(days, agentOptions);
4850
3811
  }
4851
3812
  const results = {};
4852
- const agentEntries = [...this.agents.entries()].filter(
4853
- ([id]) => !this.isAgentDisabled(id)
4854
- );
3813
+ const agentEntries = [...this.agents.entries()];
4855
3814
  const apyResults = await Promise.all(
4856
3815
  agentEntries.map(async ([id, agent]) => {
4857
3816
  const apy = await agent.getAgentApy(days, agentOptions);
@@ -4924,13 +3883,13 @@ var OwneySDK = class {
4924
3883
  };
4925
3884
 
4926
3885
  // src/agents/zyfai/zyfai.siwx.ts
4927
- var import_viem10 = require("viem");
4928
- var import_siwe2 = require("siwe");
3886
+ var import_viem7 = require("viem");
3887
+ var import_siwe = require("siwe");
4929
3888
  var import_sdk2 = require("@zyfai/sdk");
4930
3889
 
4931
3890
  // src/agents/zyfai/zyfai.siwx-cache.ts
4932
- var KEY_PREFIX3 = "owney.siwx.session";
4933
- var storage3 = () => {
3891
+ var KEY_PREFIX2 = "owney.siwx.session";
3892
+ var storage2 = () => {
4934
3893
  if (typeof window === "undefined") return null;
4935
3894
  try {
4936
3895
  return window.localStorage;
@@ -4938,8 +3897,8 @@ var storage3 = () => {
4938
3897
  return null;
4939
3898
  }
4940
3899
  };
4941
- var buildKey3 = (address) => `${KEY_PREFIX3}:${address.toLowerCase()}`;
4942
- var legacyKeyPrefix2 = (address) => `${KEY_PREFIX3}:${address.toLowerCase()}:`;
3900
+ var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
3901
+ var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
4943
3902
  var memorySiwxSessions = /* @__PURE__ */ new Map();
4944
3903
  var readLegacySiwxSession = (store, address) => {
4945
3904
  if (!store) return null;
@@ -4970,8 +3929,8 @@ var readLegacySiwxSession = (store, address) => {
4970
3929
  };
4971
3930
  var readSiwxSession = (address, chainId) => {
4972
3931
  if (typeof window === "undefined") return null;
4973
- const key2 = buildKey3(address);
4974
- const store = storage3();
3932
+ const key2 = buildKey2(address);
3933
+ const store = storage2();
4975
3934
  let raw = null;
4976
3935
  try {
4977
3936
  raw = store?.getItem(key2) ?? null;
@@ -4999,18 +3958,18 @@ var readSiwxSession = (address, chainId) => {
4999
3958
  };
5000
3959
  var writeSiwxSession = (address, _chainId, session) => {
5001
3960
  if (typeof window === "undefined") return;
5002
- const key2 = buildKey3(address);
3961
+ const key2 = buildKey2(address);
5003
3962
  memorySiwxSessions.set(key2, session);
5004
- const store = storage3();
3963
+ const store = storage2();
5005
3964
  try {
5006
3965
  store?.setItem(key2, JSON.stringify(session));
5007
3966
  } catch {
5008
3967
  }
5009
3968
  };
5010
3969
  var clearSiwxSession = (address, _chainId) => {
5011
- const key2 = buildKey3(address);
3970
+ const key2 = buildKey2(address);
5012
3971
  memorySiwxSessions.delete(key2);
5013
- const store = storage3();
3972
+ const store = storage2();
5014
3973
  try {
5015
3974
  store?.removeItem(key2);
5016
3975
  } catch {
@@ -5050,8 +4009,8 @@ function buildSIWXConfig(deps) {
5050
4009
  statement: STATEMENT,
5051
4010
  issuedAt,
5052
4011
  toString() {
5053
- return new import_siwe2.SiweMessage({
5054
- address: (0, import_viem10.getAddress)(accountAddress),
4012
+ return new import_siwe.SiweMessage({
4013
+ address: (0, import_viem7.getAddress)(accountAddress),
5055
4014
  chainId: numericChainId(chainId),
5056
4015
  domain,
5057
4016
  uri,
@@ -5093,7 +4052,7 @@ function buildSIWXConfig(deps) {
5093
4052
  const persistSession = async (session) => {
5094
4053
  const address = session.data.accountAddress;
5095
4054
  const id = numericChainId(session.data.chainId);
5096
- const message = new import_siwe2.SiweMessage(session.message);
4055
+ const message = new import_siwe.SiweMessage(session.message);
5097
4056
  const login = await post("/auth/login", {
5098
4057
  message,
5099
4058
  signature: session.signature,
@@ -5142,7 +4101,6 @@ function createOwneySIWX(config) {
5142
4101
  NotConnectedError,
5143
4102
  OwneyError,
5144
4103
  OwneySDK,
5145
- YieldseekerAgent,
5146
4104
  createOwneySIWX,
5147
4105
  setOwneyDebug
5148
4106
  });