@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.js CHANGED
@@ -50,6 +50,23 @@ var SupportedAssets = [
50
50
  }
51
51
  ];
52
52
 
53
+ // src/lib/debug.ts
54
+ var configuredDebug = false;
55
+ function setOwneyDebug(enabled) {
56
+ configuredDebug = enabled;
57
+ }
58
+ function isOwneyDebug() {
59
+ return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
60
+ }
61
+ function debugLog(scope, message, data) {
62
+ if (!isOwneyDebug()) return;
63
+ if (data === void 0) {
64
+ console.log(`[${scope}] ${message}`);
65
+ } else {
66
+ console.log(`[${scope}] ${message}`, data);
67
+ }
68
+ }
69
+
53
70
  // src/errors.ts
54
71
  var OwneyError = class extends Error {
55
72
  code;
@@ -249,7 +266,7 @@ function mapBalances(raw, _chainId, smartWallet) {
249
266
  )
250
267
  )
251
268
  ),
252
- apy: p.pool_apy,
269
+ apy: netApy(p.pool_apy_withFee, p.pool_apy, "pool_apy_withFee"),
253
270
  tvl: p.pool_tvl,
254
271
  // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
255
272
  // structural read keeps it undefined today and auto-populates later.
@@ -306,14 +323,27 @@ function mapWeightedApyByChain(raw) {
306
323
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
307
324
  const perAsset = {};
308
325
  for (const [symbol, apy] of Object.entries(tokenApy)) {
309
- const token2 = symbol;
310
- if (!SUPPORTED_TOKENS.includes(token2)) continue;
311
- perAsset[token2] = apy;
326
+ const token = symbol;
327
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
328
+ perAsset[token] = apy;
312
329
  }
313
330
  if (Object.keys(perAsset).length > 0) out[chainId] = perAsset;
314
331
  }
315
332
  return Object.keys(out).length > 0 ? out : void 0;
316
333
  }
334
+ var warnedGrossApyFallbacks = /* @__PURE__ */ new Set();
335
+ function netApy(net, gross, field) {
336
+ if (net !== void 0 && net !== null) return net;
337
+ if (gross === void 0 || gross === null) return void 0;
338
+ if (!warnedGrossApyFallbacks.has(field)) {
339
+ warnedGrossApyFallbacks.add(field);
340
+ console.warn(
341
+ `[owney] @zyfai/sdk omitted "${field}"; falling back to the gross APY, which does not deduct Zyfai's performance fee and so reads high.`
342
+ );
343
+ }
344
+ debugLog("zyfai:apy", `gross fallback for ${field}`, { gross });
345
+ return gross;
346
+ }
317
347
  function rawPoolApyForChain(entry, chainId, tokenSymbol) {
318
348
  let weightedSum = 0;
319
349
  let totalBalance = 0;
@@ -321,8 +351,9 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
321
351
  if (p.chainId !== chainId) continue;
322
352
  if (tokenSymbol && p.tokenSymbol !== tokenSymbol) continue;
323
353
  const balance = p.balance ?? 0;
324
- if (balance <= 0 || typeof p.apy !== "number") continue;
325
- weightedSum += p.apy * balance;
354
+ const apy = netApy(p.apy_withFee, p.apy, "apy_withFee");
355
+ if (balance <= 0 || typeof apy !== "number") continue;
356
+ weightedSum += apy * balance;
326
357
  totalBalance += balance;
327
358
  }
328
359
  return totalBalance > 0 ? weightedSum / totalBalance : null;
@@ -370,8 +401,12 @@ function mapEntries(rawEntries, chainId) {
370
401
  const matched = positions.find(
371
402
  (p) => p.protocol_name ? rawLog.newOpportunity.includes(`${p.protocol_name} (${p.pool})`) : false
372
403
  );
373
- oldApy = Number(rawLog.oldApy);
374
- newApy = Number(rawLog.newApy);
404
+ oldApy = Number(
405
+ netApy(rawLog.oldApy_withFee, rawLog.oldApy, "oldApy_withFee")
406
+ );
407
+ newApy = Number(
408
+ netApy(rawLog.newApy_withFee, rawLog.newApy, "newApy_withFee")
409
+ );
375
410
  const from = splitOpportunity(rawLog.oldOpportunity);
376
411
  const to = splitOpportunity(rawLog.newOpportunity);
377
412
  rebalanceLog = [
@@ -451,7 +486,11 @@ function mapApyByStrategy(raw) {
451
486
  const chainKey = supported.chainId;
452
487
  const symbolKey = supported.symbol;
453
488
  const bucket = apyPerAsset[chainKey] ?? {};
454
- const apy = entry.average_apy_with_fee ?? entry.average_apy;
489
+ const apy = netApy(
490
+ entry.average_apy_withFee,
491
+ entry.average_apy,
492
+ "average_apy_withFee"
493
+ ) ?? entry.average_apy;
455
494
  bucket[symbolKey] = apy;
456
495
  apyPerAsset[chainKey] = bucket;
457
496
  apySum += apy;
@@ -477,23 +516,23 @@ function computeAllocationApy(positions) {
477
516
  weightedSum += apy * value;
478
517
  totalValue += value;
479
518
  const chainId = resolveChainId(p.chain);
480
- const token2 = p.asset;
519
+ const token = p.asset;
481
520
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
482
- if (!SUPPORTED_TOKENS.includes(token2)) continue;
521
+ if (!SUPPORTED_TOKENS.includes(token)) continue;
483
522
  const perAsset = buckets[chainId] ?? {};
484
- const cell = perAsset[token2] ?? { weightedSum: 0, value: 0 };
523
+ const cell = perAsset[token] ?? { weightedSum: 0, value: 0 };
485
524
  cell.weightedSum += apy * value;
486
525
  cell.value += value;
487
- perAsset[token2] = cell;
526
+ perAsset[token] = cell;
488
527
  buckets[chainId] = perAsset;
489
528
  }
490
529
  const apyByChainAndAsset = {};
491
530
  for (const [chainKey, perAsset] of Object.entries(buckets)) {
492
531
  const chainId = Number(chainKey);
493
532
  const out = {};
494
- for (const [token2, cell] of Object.entries(perAsset ?? {})) {
533
+ for (const [token, cell] of Object.entries(perAsset ?? {})) {
495
534
  if (cell && cell.value > 0) {
496
- out[token2] = cell.weightedSum / cell.value;
535
+ out[token] = cell.weightedSum / cell.value;
497
536
  }
498
537
  }
499
538
  if (Object.keys(out).length > 0) apyByChainAndAsset[chainId] = out;
@@ -507,9 +546,9 @@ var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4d
507
546
  function topicToAddress(topic) {
508
547
  return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
509
548
  }
510
- function extractWithdrawnAmount(logs, recipient, token2, decimals) {
549
+ function extractWithdrawnAmount(logs, recipient, token, decimals) {
511
550
  const wantRecipient = recipient.toLowerCase();
512
- const wantToken = token2.toLowerCase();
551
+ const wantToken = token.toLowerCase();
513
552
  let total = 0n;
514
553
  let matched = false;
515
554
  for (const log of logs) {
@@ -535,11 +574,11 @@ var InvalidHistoryCursorError = class extends Error {
535
574
  function encodeHistoryCursor(payload) {
536
575
  return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
537
576
  }
538
- function decodeHistoryCursor(token2) {
539
- if (!token2) throw new InvalidHistoryCursorError("Cursor is empty.");
577
+ function decodeHistoryCursor(token) {
578
+ if (!token) throw new InvalidHistoryCursorError("Cursor is empty.");
540
579
  let parsed;
541
580
  try {
542
- const json = Buffer.from(token2, "base64").toString("utf8");
581
+ const json = Buffer.from(token, "base64").toString("utf8");
543
582
  parsed = JSON.parse(json);
544
583
  } catch {
545
584
  throw new InvalidHistoryCursorError("Cursor is not valid base64 JSON.");
@@ -562,8 +601,8 @@ var storage = () => {
562
601
  };
563
602
  var buildKey = (address) => `${KEY_PREFIX}:${address.toLowerCase()}`;
564
603
  var legacyKeyPrefix = (address) => `${KEY_PREFIX}:${address.toLowerCase()}:`;
565
- var isJwtExpired = (token2) => {
566
- const parts = token2.split(".");
604
+ var isJwtExpired = (token) => {
605
+ const parts = token.split(".");
567
606
  if (parts.length !== 3) return false;
568
607
  try {
569
608
  const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
@@ -811,23 +850,6 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
811
850
  return !protocolListsEqual(current.protocols, desiredProtocols);
812
851
  }
813
852
 
814
- // src/lib/debug.ts
815
- var configuredDebug = false;
816
- function setOwneyDebug(enabled) {
817
- configuredDebug = enabled;
818
- }
819
- function isOwneyDebug() {
820
- return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
821
- }
822
- function debugLog(scope, message, data) {
823
- if (!isOwneyDebug()) return;
824
- if (data === void 0) {
825
- console.log(`[${scope}] ${message}`);
826
- } else {
827
- console.log(`[${scope}] ${message}`, data);
828
- }
829
- }
830
-
831
853
  // src/agents/zyfai/zyfai.agent.ts
832
854
  var ERC7579_IS_MODULE_INSTALLED_ABI = parseAbi([
833
855
  "function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
@@ -1665,20 +1687,20 @@ var ZyfaiAgent = class _ZyfaiAgent {
1665
1687
  }
1666
1688
  }
1667
1689
  // --- IAgent: Fund operations ---
1668
- async withdraw(state, chainId, token2, amount) {
1690
+ async withdraw(state, chainId, token, amount) {
1669
1691
  const validChainId = isValidChainId(chainId);
1670
1692
  await this.ensureConnected(state, validChainId);
1671
1693
  const raw = await this.sdk.withdrawFunds(
1672
1694
  this.getAddress(),
1673
1695
  validChainId,
1674
1696
  amount,
1675
- token2
1697
+ token
1676
1698
  );
1677
1699
  if (!raw.success) {
1678
1700
  throw new OwneyError(
1679
1701
  "WITHDRAW_FAILED",
1680
1702
  raw.message || "Zyfai withdraw failed.",
1681
- { chainId: validChainId, token: token2, amount, response: raw },
1703
+ { chainId: validChainId, token, amount, response: raw },
1682
1704
  this.id
1683
1705
  );
1684
1706
  }
@@ -1829,189 +1851,362 @@ var ZyfaiAgent = class _ZyfaiAgent {
1829
1851
  }
1830
1852
  };
1831
1853
 
1832
- // src/agents/yieldseeker/yieldseeker.agent.ts
1833
- import {
1834
- createPublicClient as createPublicClient3,
1835
- createWalletClient as createWalletClient2,
1836
- custom as custom2,
1837
- getAddress as getAddress2,
1838
- isAddress,
1839
- parseUnits
1840
- } from "viem";
1841
- import { base as base3 } from "viem/chains";
1842
-
1843
- // src/lib/chain-guard.ts
1844
- var CHAIN_NAMES = {
1845
- 1: "Ethereum",
1846
- 8453: "Base",
1847
- 42161: "Arbitrum"
1848
- };
1849
- function chainName(chainId) {
1850
- return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
1851
- }
1852
- async function ensureWalletOnChain(pub, wallet, expected) {
1853
- const actual = await pub.getChainId();
1854
- if (actual === expected) return;
1854
+ // src/lib/routing-api.ts
1855
+ var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
1856
+ async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
1857
+ const url = `${baseUrl}/api/v1/agent/org-config`;
1855
1858
  try {
1856
- await wallet.switchChain({ id: expected });
1857
- } catch (error) {
1858
- throw new OwneyError(
1859
- "CHAIN_MISMATCH",
1860
- `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
1861
- {
1862
- expectedChainId: expected,
1863
- actualChainId: actual,
1864
- cause: error instanceof Error ? error.message : String(error)
1859
+ const res = await fetch(url, {
1860
+ method: "GET",
1861
+ headers: {
1862
+ "Content-Type": "application/json",
1863
+ "x-owney-api-key": `${apiKey}`
1865
1864
  }
1865
+ });
1866
+ if (!res.ok) {
1867
+ if (res.status !== 404) {
1868
+ console.warn(
1869
+ `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
1870
+ );
1871
+ }
1872
+ return null;
1873
+ }
1874
+ const json = await res.json();
1875
+ const policy = json.success ? json.data ?? null : null;
1876
+ debugLog(
1877
+ "owney-sdk",
1878
+ policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
1879
+ policy ?? void 0
1866
1880
  );
1867
- }
1868
- const after = await pub.getChainId();
1869
- if (after !== expected) {
1870
- throw new OwneyError(
1871
- "CHAIN_MISMATCH",
1872
- `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
1873
- { expectedChainId: expected, actualChainId: after }
1881
+ return policy;
1882
+ } catch (error) {
1883
+ console.warn(
1884
+ "[owney-sdk] Could not read org agent config (non-fatal):",
1885
+ error instanceof Error ? error.message : String(error)
1874
1886
  );
1887
+ return null;
1875
1888
  }
1876
1889
  }
1877
-
1878
- // src/lib/transfer-auth.ts
1879
- import { bytesToHex } from "viem";
1880
- var ERC20_META_ABI = [
1881
- { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
1882
- { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
1883
- ];
1884
- function buildTransferWithAuthorizationTypedData(input) {
1885
- return {
1886
- domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
1887
- types: {
1888
- TransferWithAuthorization: [
1889
- { name: "from", type: "address" },
1890
- { name: "to", type: "address" },
1891
- { name: "value", type: "uint256" },
1892
- { name: "validAfter", type: "uint256" },
1893
- { name: "validBefore", type: "uint256" },
1894
- { name: "nonce", type: "bytes32" }
1895
- ]
1896
- },
1897
- primaryType: "TransferWithAuthorization",
1898
- message: input.message
1899
- };
1900
- }
1901
- async function readTokenMeta(publicClient, token2) {
1902
- const [tokenName, tokenVersion] = await Promise.all([
1903
- publicClient.readContract({ address: token2, abi: ERC20_META_ABI, functionName: "name" }),
1904
- publicClient.readContract({ address: token2, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
1905
- ]);
1906
- return { tokenName, tokenVersion };
1907
- }
1908
- function randomAuthNonce() {
1909
- const bytes = new Uint8Array(32);
1910
- globalThis.crypto.getRandomValues(bytes);
1911
- return bytesToHex(bytes);
1912
- }
1913
-
1914
- // src/lib/sponsor-client.ts
1915
- var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
1916
- async function postSponsorTransferAuth(input) {
1917
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
1918
- let res;
1919
- try {
1920
- res = await fetch(`${base5}/api/v1/sponsor/erc20-transfer-auth`, {
1921
- method: "POST",
1922
- headers: {
1923
- "content-type": "application/json",
1924
- "x-owney-api-key": input.apiKey,
1925
- ...input.yieldseekerSignature ? { "x-signature": input.yieldseekerSignature } : {}
1926
- },
1927
- body: JSON.stringify(input.body)
1928
- });
1929
- } catch (networkError) {
1890
+ async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
1891
+ const url = `${baseUrl}/api/v1/agent/keys`;
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
+ const text = await res.text().catch(() => "");
1930
1901
  throw new OwneyError(
1931
- "SPONSOR_REQUEST_FAILED",
1932
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
1933
- { cause: String(networkError) }
1902
+ "API_ROUTING_ERROR",
1903
+ `Routing API error ${res.status}: ${text}`,
1904
+ { statusCode: res.status, responseBody: text }
1934
1905
  );
1935
1906
  }
1936
- const text = await res.text();
1937
- let parsed = null;
1938
- try {
1939
- parsed = JSON.parse(text);
1940
- } catch {
1941
- }
1942
- if (!res.ok || !parsed?.success || !parsed.data) {
1907
+ const json = await res.json();
1908
+ if (!json.success) {
1943
1909
  throw new OwneyError(
1944
- "SPONSOR_REQUEST_FAILED",
1945
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1946
- {
1947
- statusCode: res.status,
1948
- responseBody: text.slice(0, 500),
1949
- // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
1950
- // before broadcast, so it is safe to fall back to a user-paid deposit.
1951
- safeToFallback: res.status === 503
1952
- }
1910
+ "API_ROUTING_FAILED",
1911
+ `Routing API request failed: ${json.message}`,
1912
+ { message: json.message }
1953
1913
  );
1954
1914
  }
1955
- return parsed.data;
1915
+ return json.data;
1956
1916
  }
1957
- async function postSponsorPermit2Transfer(input) {
1958
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
1959
- let res;
1917
+
1918
+ // src/lib/health-report.ts
1919
+ var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
1920
+ async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
1960
1921
  try {
1961
- res = await fetch(`${base5}/api/v1/sponsor/permit2-transfer`, {
1922
+ await fetch(`${baseUrl}/api/v1/agent/health-report`, {
1962
1923
  method: "POST",
1963
1924
  headers: {
1964
- "content-type": "application/json",
1965
- "x-owney-api-key": input.apiKey,
1966
- ...input.yieldseekerSignature ? { "x-signature": input.yieldseekerSignature } : {}
1925
+ "Content-Type": "application/json",
1926
+ "x-owney-api-key": apiKey
1967
1927
  },
1968
- body: JSON.stringify(input.body)
1928
+ body: JSON.stringify({
1929
+ agent_type: agentType,
1930
+ error_code: errorCode,
1931
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1932
+ })
1969
1933
  });
1970
- } catch (networkError) {
1971
- throw new OwneyError(
1972
- "SPONSOR_REQUEST_FAILED",
1973
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
1974
- { cause: String(networkError), safeToFallback: false }
1934
+ } catch (err) {
1935
+ console.warn(
1936
+ `[owney-sdk] health-report failed for agent "${agentType}":`,
1937
+ err instanceof Error ? err.message : err
1975
1938
  );
1976
1939
  }
1977
- const text = await res.text();
1978
- let parsed = null;
1940
+ }
1941
+ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
1979
1942
  try {
1980
- parsed = JSON.parse(text);
1981
- } catch {
1982
- }
1983
- if (!res.ok || !parsed?.success || !parsed.data) {
1984
- throw new OwneyError(
1985
- "SPONSOR_REQUEST_FAILED",
1986
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1987
- {
1988
- statusCode: res.status,
1989
- responseBody: text.slice(0, 500),
1990
- safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
1991
- }
1992
- );
1943
+ return await fn();
1944
+ } catch (err) {
1945
+ const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
1946
+ void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
1947
+ throw err;
1993
1948
  }
1994
- return parsed.data;
1995
1949
  }
1996
- async function getSponsorRelayerAddress(input) {
1997
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
1998
- let res;
1999
- try {
2000
- res = await fetch(
2001
- `${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2002
- {
2003
- headers: { "x-owney-api-key": input.apiKey }
2004
- }
2005
- );
2006
- } catch (networkError) {
2007
- throw new OwneyError(
2008
- "SPONSOR_REQUEST_FAILED",
2009
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2010
- { cause: String(networkError), safeToFallback: true }
1950
+
1951
+ // src/lib/helpers/withdraw-helper.ts
1952
+ import { parseUnits } from "viem";
1953
+ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
1954
+ const target = asset.toUpperCase();
1955
+ return agents.map((agent) => {
1956
+ const agentBalance = aggregated[agent.id];
1957
+ const tokenBalance = agentBalance?.tokens.find(
1958
+ (t) => t.chainId === chainId && t.asset.toUpperCase() === target
2011
1959
  );
2012
- }
2013
- const text = await res.text();
2014
- let parsed = null;
1960
+ if (!tokenBalance) return { agent, balance: 0n };
1961
+ return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
1962
+ });
1963
+ }
1964
+ function planProportionalShares(balances, requested, totalAvailable) {
1965
+ const plans = balances.map(({ agent, balance }) => ({
1966
+ agent,
1967
+ balance,
1968
+ planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
1969
+ }));
1970
+ const assigned = plans.reduce((s, p) => s + p.planned, 0n);
1971
+ let remainder = requested - assigned;
1972
+ const byHeadroom = [...plans].sort((a, b) => {
1973
+ const diff = b.balance - b.planned - (a.balance - a.planned);
1974
+ return diff > 0n ? 1 : diff < 0n ? -1 : 0;
1975
+ });
1976
+ for (const p of byHeadroom) {
1977
+ if (remainder === 0n) break;
1978
+ const headroom = p.balance - p.planned;
1979
+ if (headroom <= 0n) continue;
1980
+ const take = headroom < remainder ? headroom : remainder;
1981
+ p.planned += take;
1982
+ remainder -= take;
1983
+ }
1984
+ return plans;
1985
+ }
1986
+ function planDisabledDrain(disabled, requested) {
1987
+ const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
1988
+ const plans = [];
1989
+ let remaining = requested;
1990
+ for (const { agent, balance } of sorted) {
1991
+ if (remaining === 0n) {
1992
+ plans.push({ agent, balance, planned: 0n });
1993
+ continue;
1994
+ }
1995
+ const take = balance < remaining ? balance : remaining;
1996
+ plans.push({ agent, balance, planned: take });
1997
+ remaining -= take;
1998
+ }
1999
+ return { plans, remaining };
2000
+ }
2001
+ function redistributeShare(plans, fromIndex, amount, candidatePool) {
2002
+ const pool = candidatePool ?? plans.slice(fromIndex + 1);
2003
+ const candidates = pool.filter((c) => c.balance - c.planned > 0n);
2004
+ const totalHeadroom = candidates.reduce(
2005
+ (s, c) => s + (c.balance - c.planned),
2006
+ 0n
2007
+ );
2008
+ if (totalHeadroom === 0n) return;
2009
+ let distributed = 0n;
2010
+ for (const c of candidates) {
2011
+ const headroom = c.balance - c.planned;
2012
+ const proportional = headroom * amount / totalHeadroom;
2013
+ const give = proportional > headroom ? headroom : proportional;
2014
+ c.planned += give;
2015
+ distributed += give;
2016
+ }
2017
+ let leftover = amount - distributed;
2018
+ for (const c of candidates) {
2019
+ if (leftover === 0n) break;
2020
+ const headroom = c.balance - c.planned;
2021
+ if (headroom <= 0n) continue;
2022
+ const take = headroom < leftover ? headroom : leftover;
2023
+ c.planned += take;
2024
+ leftover -= take;
2025
+ }
2026
+ }
2027
+ function sumWithdrawnAmount(results) {
2028
+ return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
2029
+ }
2030
+
2031
+ // src/lib/helpers/account-apy-helper.ts
2032
+ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
2033
+ const sums = {};
2034
+ const weights = {};
2035
+ for (const id of Object.keys(agentApys)) {
2036
+ const cells = agentApys[id].apyByChainAndAsset;
2037
+ const balance = agentBalances[id] ?? 0;
2038
+ if (!cells || balance <= 0) continue;
2039
+ for (const [chainKey, perAsset] of Object.entries(cells)) {
2040
+ if (!perAsset) continue;
2041
+ const chainId = Number(chainKey);
2042
+ for (const [asset, apyValue] of Object.entries(perAsset)) {
2043
+ const apy = Number(apyValue ?? 0);
2044
+ if (apy === 0) continue;
2045
+ sums[chainId] ??= {};
2046
+ weights[chainId] ??= {};
2047
+ sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
2048
+ weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2049
+ }
2050
+ }
2051
+ }
2052
+ const out = {};
2053
+ for (const chainKey of Object.keys(sums)) {
2054
+ const chainId = Number(chainKey);
2055
+ const perAssetOut = {};
2056
+ for (const asset of Object.keys(sums[chainId])) {
2057
+ const w = weights[chainId][asset];
2058
+ if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
2059
+ }
2060
+ if (Object.keys(perAssetOut).length > 0) {
2061
+ out[chainId] = perAssetOut;
2062
+ }
2063
+ }
2064
+ return out;
2065
+ }
2066
+
2067
+ // src/client.ts
2068
+ import {
2069
+ createPublicClient as createPublicClient2,
2070
+ createWalletClient,
2071
+ custom
2072
+ } from "viem";
2073
+ import { base as base2, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
2074
+
2075
+ // src/lib/transfer-auth.ts
2076
+ import { bytesToHex } from "viem";
2077
+ var ERC20_META_ABI = [
2078
+ { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
2079
+ { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
2080
+ ];
2081
+ function buildTransferWithAuthorizationTypedData(input) {
2082
+ return {
2083
+ domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
2084
+ types: {
2085
+ TransferWithAuthorization: [
2086
+ { name: "from", type: "address" },
2087
+ { name: "to", type: "address" },
2088
+ { name: "value", type: "uint256" },
2089
+ { name: "validAfter", type: "uint256" },
2090
+ { name: "validBefore", type: "uint256" },
2091
+ { name: "nonce", type: "bytes32" }
2092
+ ]
2093
+ },
2094
+ primaryType: "TransferWithAuthorization",
2095
+ message: input.message
2096
+ };
2097
+ }
2098
+ async function readTokenMeta(publicClient, token) {
2099
+ const [tokenName, tokenVersion] = await Promise.all([
2100
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
2101
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
2102
+ ]);
2103
+ return { tokenName, tokenVersion };
2104
+ }
2105
+ function randomAuthNonce() {
2106
+ const bytes = new Uint8Array(32);
2107
+ globalThis.crypto.getRandomValues(bytes);
2108
+ return bytesToHex(bytes);
2109
+ }
2110
+
2111
+ // src/lib/sponsor-client.ts
2112
+ var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2113
+ async function postSponsorTransferAuth(input) {
2114
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2115
+ let res;
2116
+ try {
2117
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2118
+ method: "POST",
2119
+ headers: {
2120
+ "content-type": "application/json",
2121
+ "x-owney-api-key": input.apiKey
2122
+ },
2123
+ body: JSON.stringify(input.body)
2124
+ });
2125
+ } catch (networkError) {
2126
+ throw new OwneyError(
2127
+ "SPONSOR_REQUEST_FAILED",
2128
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2129
+ { cause: String(networkError) }
2130
+ );
2131
+ }
2132
+ const text = await res.text();
2133
+ let parsed = null;
2134
+ try {
2135
+ parsed = JSON.parse(text);
2136
+ } catch {
2137
+ }
2138
+ if (!res.ok || !parsed?.success || !parsed.data) {
2139
+ throw new OwneyError(
2140
+ "SPONSOR_REQUEST_FAILED",
2141
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2142
+ {
2143
+ statusCode: res.status,
2144
+ responseBody: text.slice(0, 500),
2145
+ // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2146
+ // before broadcast, so it is safe to fall back to a user-paid deposit.
2147
+ safeToFallback: res.status === 503
2148
+ }
2149
+ );
2150
+ }
2151
+ return parsed.data;
2152
+ }
2153
+ async function postSponsorPermit2Transfer(input) {
2154
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2155
+ let res;
2156
+ try {
2157
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2158
+ method: "POST",
2159
+ headers: {
2160
+ "content-type": "application/json",
2161
+ "x-owney-api-key": input.apiKey
2162
+ },
2163
+ body: JSON.stringify(input.body)
2164
+ });
2165
+ } catch (networkError) {
2166
+ throw new OwneyError(
2167
+ "SPONSOR_REQUEST_FAILED",
2168
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2169
+ { cause: String(networkError), safeToFallback: false }
2170
+ );
2171
+ }
2172
+ const text = await res.text();
2173
+ let parsed = null;
2174
+ try {
2175
+ parsed = JSON.parse(text);
2176
+ } catch {
2177
+ }
2178
+ if (!res.ok || !parsed?.success || !parsed.data) {
2179
+ throw new OwneyError(
2180
+ "SPONSOR_REQUEST_FAILED",
2181
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2182
+ {
2183
+ statusCode: res.status,
2184
+ responseBody: text.slice(0, 500),
2185
+ safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
2186
+ }
2187
+ );
2188
+ }
2189
+ return parsed.data;
2190
+ }
2191
+ async function getSponsorRelayerAddress(input) {
2192
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2193
+ let res;
2194
+ try {
2195
+ res = await fetch(
2196
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2197
+ {
2198
+ headers: { "x-owney-api-key": input.apiKey }
2199
+ }
2200
+ );
2201
+ } catch (networkError) {
2202
+ throw new OwneyError(
2203
+ "SPONSOR_REQUEST_FAILED",
2204
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2205
+ { cause: String(networkError), safeToFallback: true }
2206
+ );
2207
+ }
2208
+ const text = await res.text();
2209
+ let parsed = null;
2015
2210
  try {
2016
2211
  parsed = JSON.parse(text);
2017
2212
  } catch {
@@ -2059,1426 +2254,249 @@ var ERC20_ALLOWANCE_ABI = [
2059
2254
  type: "function",
2060
2255
  name: "balanceOf",
2061
2256
  stateMutability: "view",
2062
- inputs: [{ name: "account", type: "address" }],
2063
- outputs: [{ name: "", type: "uint256" }]
2064
- }
2065
- ];
2066
- function buildPermitTransferFromTypedData(input) {
2067
- return {
2068
- domain: {
2069
- name: "Permit2",
2070
- chainId: input.chainId,
2071
- verifyingContract: PERMIT2_ADDRESS
2072
- },
2073
- types: {
2074
- PermitTransferFrom: [
2075
- { name: "permitted", type: "TokenPermissions" },
2076
- { name: "spender", type: "address" },
2077
- { name: "nonce", type: "uint256" },
2078
- { name: "deadline", type: "uint256" }
2079
- ],
2080
- TokenPermissions: [
2081
- { name: "token", type: "address" },
2082
- { name: "amount", type: "uint256" }
2083
- ]
2084
- },
2085
- primaryType: "PermitTransferFrom",
2086
- message: input.message
2087
- };
2088
- }
2089
- function randomPermit2Nonce() {
2090
- const bytes = new Uint8Array(32);
2091
- globalThis.crypto.getRandomValues(bytes);
2092
- return BigInt(bytesToHex2(bytes));
2093
- }
2094
- async function readPermit2Allowance(publicClient, token2, owner) {
2095
- return publicClient.readContract({
2096
- address: token2,
2097
- abi: ERC20_ALLOWANCE_ABI,
2098
- functionName: "allowance",
2099
- args: [owner, PERMIT2_ADDRESS]
2100
- });
2101
- }
2102
- async function readErc20Balance(publicClient, token2, owner) {
2103
- return publicClient.readContract({
2104
- address: token2,
2105
- abi: ERC20_ALLOWANCE_ABI,
2106
- functionName: "balanceOf",
2107
- args: [owner]
2108
- });
2109
- }
2110
-
2111
- // src/lib/sponsored-deposit.ts
2112
- var AUTH_WINDOW_SECONDS = 15 * 60;
2113
- var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
2114
- function provideDepositVerificationContext(callback, context) {
2115
- callback[verificationSetter]?.(context);
2116
- }
2117
- function makeVerificationAwareDepositCallback(implementation) {
2118
- let nextVerification;
2119
- const callback = async (smartWallet, chainId, amount) => {
2120
- const verification = nextVerification;
2121
- nextVerification = void 0;
2122
- return implementation(smartWallet, chainId, amount, verification);
2123
- };
2124
- Object.defineProperty(callback, verificationSetter, {
2125
- value: (context) => {
2126
- nextVerification = context;
2127
- }
2128
- });
2129
- return callback;
2130
- }
2131
- function makeSponsoredDepositCallback(deps) {
2132
- const post = deps.httpPost ?? postSponsorTransferAuth;
2133
- return makeVerificationAwareDepositCallback(
2134
- async (smartWallet, chainId, amount, verification) => {
2135
- const cid = chainId;
2136
- const token2 = deps.tokenAddressByChain[cid];
2137
- if (!token2) {
2138
- throw new OwneyError(
2139
- "CHAIN_UNSUPPORTED",
2140
- `No sponsored token configured for chain ${chainId}`
2141
- );
2142
- }
2143
- const pub = deps.getPublicClient(cid);
2144
- const wallet = deps.getWalletClient(cid);
2145
- await ensureWalletOnChain(pub, wallet, cid);
2146
- try {
2147
- const balance = await readErc20Balance(pub, token2, deps.ownerAddress);
2148
- if (balance < BigInt(amount)) {
2149
- throw new OwneyError(
2150
- "DEPOSIT_INSUFFICIENT_BALANCE",
2151
- "Insufficient balance for this deposit.",
2152
- { token: token2, chainId: cid, balance: balance.toString(), amount }
2153
- );
2154
- }
2155
- } catch (err) {
2156
- if (err instanceof OwneyError) throw err;
2157
- console.warn(
2158
- "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2159
- err instanceof Error ? err.message : String(err)
2160
- );
2161
- }
2162
- const { tokenName, tokenVersion } = await readTokenMeta(pub, token2);
2163
- const validAfter = 0n;
2164
- const validBefore = BigInt(
2165
- Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2166
- );
2167
- const nonce = randomAuthNonce();
2168
- const typedData = buildTransferWithAuthorizationTypedData({
2169
- token: token2,
2170
- chainId: cid,
2171
- tokenName,
2172
- tokenVersion,
2173
- message: {
2174
- from: deps.ownerAddress,
2175
- to: smartWallet,
2176
- value: BigInt(amount),
2177
- validAfter,
2178
- validBefore,
2179
- nonce
2180
- }
2181
- });
2182
- const authSignature = await wallet.signTypedData({
2183
- account: deps.ownerAddress,
2184
- ...typedData
2185
- });
2186
- deps.onApproved?.();
2187
- const result = await post({
2188
- baseUrl: deps.baseUrl,
2189
- apiKey: deps.apiKey,
2190
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
2191
- body: {
2192
- chainId: cid,
2193
- token: token2,
2194
- from: deps.ownerAddress,
2195
- to: smartWallet,
2196
- value: amount,
2197
- validAfter: validAfter.toString(),
2198
- validBefore: validBefore.toString(),
2199
- nonce,
2200
- authSignature,
2201
- tokenName,
2202
- tokenVersion
2203
- }
2204
- });
2205
- return result.txHash;
2206
- }
2207
- );
2208
- }
2209
-
2210
- // src/agents/yieldseeker/yieldseeker.auth.ts
2211
- import { SiweMessage, generateNonce } from "siwe";
2212
- import {
2213
- createPublicClient as createPublicClient2,
2214
- createWalletClient,
2215
- custom,
2216
- getAddress
2217
- } from "viem";
2218
- import { base as base2 } from "viem/chains";
2219
-
2220
- // src/agents/yieldseeker/yieldseeker.auth-cache.ts
2221
- var KEY_PREFIX2 = "owney.yieldseeker.session";
2222
- var storage2 = () => {
2223
- if (typeof window === "undefined") return null;
2224
- try {
2225
- return window.localStorage;
2226
- } catch {
2227
- return null;
2228
- }
2229
- };
2230
- var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2231
- var memorySessions2 = /* @__PURE__ */ new Map();
2232
- var isValidSession = (session) => {
2233
- if (!session?.token) return false;
2234
- try {
2235
- const parsed = JSON.parse(atob(session.token));
2236
- return typeof parsed.message === "string" && typeof parsed.signature === "string" && parsed.signature.startsWith("0x");
2237
- } catch {
2238
- return false;
2239
- }
2240
- };
2241
- var readYieldseekerSession = (address, chainId) => {
2242
- if (typeof window === "undefined") return null;
2243
- const key2 = buildKey2(address, chainId);
2244
- const store = storage2();
2245
- let raw = null;
2246
- try {
2247
- raw = store?.getItem(key2) ?? null;
2248
- } catch {
2249
- raw = null;
2250
- }
2251
- if (raw) {
2252
- try {
2253
- const parsed = JSON.parse(raw);
2254
- if (isValidSession(parsed)) return parsed.token;
2255
- } catch {
2256
- }
2257
- memorySessions2.delete(key2);
2258
- try {
2259
- store?.removeItem(key2);
2260
- } catch {
2261
- }
2262
- return null;
2263
- }
2264
- const cached = memorySessions2.get(key2);
2265
- if (isValidSession(cached)) return cached.token;
2266
- if (cached) memorySessions2.delete(key2);
2267
- return null;
2268
- };
2269
- var writeYieldseekerSession = (address, chainId, token2) => {
2270
- if (typeof window === "undefined") return;
2271
- const session = { token: token2 };
2272
- if (!isValidSession(session)) return;
2273
- const key2 = buildKey2(address, chainId);
2274
- memorySessions2.set(key2, session);
2275
- const store = storage2();
2276
- try {
2277
- store?.setItem(key2, JSON.stringify(session));
2278
- } catch {
2279
- }
2280
- };
2281
- var clearYieldseekerSession = (address, chainId) => {
2282
- const key2 = buildKey2(address, chainId);
2283
- memorySessions2.delete(key2);
2284
- const store = storage2();
2285
- try {
2286
- store?.removeItem(key2);
2287
- } catch {
2288
- }
2289
- };
2290
-
2291
- // src/agents/yieldseeker/yieldseeker.auth.ts
2292
- function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
2293
- return new SiweMessage({
2294
- domain: "yieldseeker.xyz",
2295
- address: getAddress(address),
2296
- uri: "https://yieldseeker.xyz",
2297
- version: "1",
2298
- chainId,
2299
- nonce: (dependencies.nonce ?? generateNonce)(),
2300
- issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
2301
- }).prepareMessage();
2302
- }
2303
- function encodeYieldseekerAuthToken(token2) {
2304
- const bytes = new TextEncoder().encode(JSON.stringify(token2));
2305
- let binary = "";
2306
- for (const byte of bytes) binary += String.fromCharCode(byte);
2307
- return btoa(binary);
2308
- }
2309
- var YieldseekerAuth = class {
2310
- constructor(dependencies = {}) {
2311
- this.dependencies = dependencies;
2312
- }
2313
- dependencies;
2314
- tokens = /* @__PURE__ */ new Map();
2315
- pending = /* @__PURE__ */ new Map();
2316
- scopes = /* @__PURE__ */ new Map();
2317
- key(state, chainId) {
2318
- return `${state.walletAddress.toLowerCase()}:${chainId}`;
2319
- }
2320
- async getToken(state, chainId) {
2321
- const key2 = this.key(state, chainId);
2322
- const scope = { address: state.walletAddress, chainId };
2323
- this.scopes.set(key2, scope);
2324
- const cached = this.tokens.get(key2);
2325
- if (cached) return cached;
2326
- const persisted = readYieldseekerSession(scope.address, scope.chainId);
2327
- if (persisted) {
2328
- this.tokens.set(key2, persisted);
2329
- return persisted;
2330
- }
2331
- const inFlight = this.pending.get(key2);
2332
- if (inFlight) return inFlight;
2333
- const request = this.sign(state, chainId).then((token2) => {
2334
- this.tokens.set(key2, token2);
2335
- writeYieldseekerSession(scope.address, scope.chainId, token2);
2336
- return token2;
2337
- });
2338
- this.pending.set(key2, request);
2339
- try {
2340
- return await request;
2341
- } finally {
2342
- this.pending.delete(key2);
2343
- }
2344
- }
2345
- clear(state, chainId) {
2346
- if (!state || chainId === void 0) {
2347
- for (const scope of this.scopes.values()) {
2348
- clearYieldseekerSession(scope.address, scope.chainId);
2349
- }
2350
- this.tokens.clear();
2351
- this.pending.clear();
2352
- this.scopes.clear();
2353
- return;
2354
- }
2355
- const key2 = this.key(state, chainId);
2356
- this.tokens.delete(key2);
2357
- this.pending.delete(key2);
2358
- this.scopes.delete(key2);
2359
- clearYieldseekerSession(state.walletAddress, chainId);
2360
- }
2361
- async sign(state, chainId) {
2362
- const account = getAddress(state.walletAddress);
2363
- const publicClient = createPublicClient2({
2364
- chain: base2,
2365
- transport: custom(state.provider)
2366
- });
2367
- const walletClient = createWalletClient({
2368
- account,
2369
- chain: base2,
2370
- transport: custom(state.provider)
2371
- });
2372
- await ensureWalletOnChain(
2373
- publicClient,
2374
- walletClient,
2375
- 8453
2376
- );
2377
- const message = createYieldseekerSiweMessage(
2378
- account,
2379
- chainId,
2380
- this.dependencies
2381
- );
2382
- const signature = await walletClient.signMessage({ account, message });
2383
- return encodeYieldseekerAuthToken({ message, signature });
2384
- }
2385
- };
2386
-
2387
- // src/agents/yieldseeker/yieldseeker.client.ts
2388
- var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2389
- function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
2390
- return `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/agent/yieldseeker`;
2391
- }
2392
- var YIELDSEEKER_API_BASE_URL = getYieldseekerProxyBaseUrl();
2393
- var YieldseekerApiError = class extends Error {
2394
- constructor(status, providerCode, responseFields) {
2395
- super(`Yieldseeker request failed (${status}): ${providerCode}`);
2396
- this.status = status;
2397
- this.providerCode = providerCode;
2398
- this.responseFields = responseFields;
2399
- this.name = "YieldseekerApiError";
2400
- }
2401
- status;
2402
- providerCode;
2403
- responseFields;
2404
- get isAuthenticationError() {
2405
- return this.status === 401 || this.status === 403;
2406
- }
2407
- };
2408
- function providerError(body, fallback) {
2409
- if (!body || typeof body !== "object") return { code: fallback };
2410
- const record = body;
2411
- return {
2412
- code: typeof record.message === "string" ? record.message : fallback,
2413
- fields: record.fields && typeof record.fields === "object" ? record.fields : void 0
2414
- };
2415
- }
2416
- var YieldseekerApiClient = class {
2417
- constructor(owneyApiKey, baseUrl = YIELDSEEKER_API_BASE_URL, fetchFn = fetch) {
2418
- this.owneyApiKey = owneyApiKey;
2419
- this.baseUrl = baseUrl;
2420
- this.fetchFn = fetchFn;
2421
- }
2422
- owneyApiKey;
2423
- baseUrl;
2424
- fetchFn;
2425
- async request(path, options = {}) {
2426
- const controller = new AbortController();
2427
- const timer = setTimeout(
2428
- () => controller.abort(),
2429
- options.timeoutMs ?? 15e3
2430
- );
2431
- try {
2432
- const response = await this.fetchFn(`${this.baseUrl}${path}`, {
2433
- method: options.method ?? "GET",
2434
- headers: {
2435
- "Content-Type": "application/json",
2436
- "x-owney-api-key": this.owneyApiKey,
2437
- ...options.signature ? { "X-Signature": options.signature } : {}
2438
- },
2439
- body: options.body ? JSON.stringify(options.body) : void 0,
2440
- signal: controller.signal
2441
- });
2442
- const payload = await response.json().catch(() => null);
2443
- if (!response.ok) {
2444
- const error = providerError(payload, `HTTP_${response.status}`);
2445
- throw new YieldseekerApiError(
2446
- response.status,
2447
- error.code,
2448
- error.fields
2449
- );
2450
- }
2451
- if (payload && typeof payload === "object" && payload.success === true && "data" in payload) {
2452
- return payload.data;
2453
- }
2454
- return payload;
2455
- } catch (error) {
2456
- if (error instanceof YieldseekerApiError) throw error;
2457
- if (error instanceof DOMException && error.name === "AbortError") {
2458
- throw new YieldseekerApiError(408, "REQUEST_TIMEOUT");
2459
- }
2460
- throw new YieldseekerApiError(0, "NETWORK_ERROR", {
2461
- cause: error instanceof Error ? error.message : String(error)
2462
- });
2463
- } finally {
2464
- clearTimeout(timer);
2465
- }
2466
- }
2467
- };
2468
-
2469
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2470
- import { formatUnits } from "viem";
2471
- var REBALANCE_AMOUNT_DECIMALS = {
2472
- USDC: 6,
2473
- WETH: 18
2474
- };
2475
- function rebalanceAmount(value, tokenSymbol) {
2476
- const decimals = REBALANCE_AMOUNT_DECIMALS[tokenSymbol.toUpperCase()];
2477
- if (decimals === void 0) {
2478
- return invalid(
2479
- "history",
2480
- `unsupported rebalance token ${tokenSymbol || "<empty>"}`
2481
- );
2482
- }
2483
- try {
2484
- return formatUnits(BigInt(value), decimals);
2485
- } catch {
2486
- return invalid("history", `invalid rebalance amount ${value}`);
2487
- }
2488
- }
2489
- function invalid(endpoint, detail) {
2490
- throw new OwneyError(
2491
- "AGENT_INVALID_RESPONSE",
2492
- `Yieldseeker returned an invalid ${endpoint} response: ${detail}.`,
2493
- { endpoint, detail },
2494
- "yieldseeker"
2495
- );
2496
- }
2497
- function requireObject(value, endpoint) {
2498
- if (!value || typeof value !== "object" || Array.isArray(value)) {
2499
- return invalid(endpoint, "expected an object");
2500
- }
2501
- return value;
2502
- }
2503
- function requireEnvelope(value, key2, endpoint) {
2504
- const root = requireObject(value, endpoint);
2505
- return requireObject(root[key2], endpoint);
2506
- }
2507
- function token(value) {
2508
- return {
2509
- chain: value.chain,
2510
- chainId: value.chainId,
2511
- asset: value.asset,
2512
- amount: String(value.amount)
2513
- };
2514
- }
2515
- function position(value) {
2516
- return {
2517
- chain: String(value.chain),
2518
- protocol: String(value.protocol),
2519
- ...value.protocolId ? { protocolId: value.protocolId } : {},
2520
- ...value.pool ? { pool: value.pool } : {},
2521
- asset: String(value.asset),
2522
- amount: String(value.amount),
2523
- ...value.amountRaw !== void 0 ? { amountRaw: value.amountRaw } : {},
2524
- ...typeof value.apy === "number" ? { apy: value.apy } : {},
2525
- ...typeof value.tvl === "number" ? { tvl: value.tvl } : {},
2526
- ...typeof value.liquidity === "number" ? { liquidity: value.liquidity } : {}
2527
- };
2528
- }
2529
- function mapApyMatrix(matrix) {
2530
- const mapped = {};
2531
- for (const [chain, assets] of Object.entries(matrix ?? {})) {
2532
- const chainId = Number(chain);
2533
- if (chainId !== 8453 || !assets || typeof assets !== "object") continue;
2534
- mapped[8453] = {};
2535
- for (const [asset, apy] of Object.entries(assets)) {
2536
- if ((asset === "USDC" || asset === "WETH") && typeof apy === "number") {
2537
- mapped[8453][asset] = apy;
2538
- }
2539
- }
2540
- }
2541
- return mapped;
2542
- }
2543
- function mapYieldseekerProfile(value) {
2544
- const profile = requireEnvelope(
2545
- value,
2546
- "profile",
2547
- "profile"
2548
- );
2549
- if (typeof profile.address !== "string" || typeof profile.smartWallet !== "string" || !Array.isArray(profile.chains) || typeof profile.hasActiveSessionKey !== "boolean" || !Array.isArray(profile.protocols)) {
2550
- return invalid("profile", "missing required fields");
2551
- }
2552
- return {
2553
- address: profile.address,
2554
- smartWallet: profile.smartWallet,
2555
- chains: profile.chains.map(Number),
2556
- hasActiveSessionKey: profile.hasActiveSessionKey,
2557
- protocols: profile.protocols.map(String)
2558
- };
2559
- }
2560
- function mapYieldseekerBalances(value) {
2561
- const balances = requireEnvelope(
2562
- value,
2563
- "balances",
2564
- "balances"
2565
- );
2566
- if (typeof balances.smartWallet !== "string" || typeof balances.totalBalance !== "string" || typeof balances.totalBalanceAsset !== "string" || !Array.isArray(balances.tokens) || !Array.isArray(balances.positions)) {
2567
- return invalid("balances", "missing required fields");
2568
- }
2569
- return {
2570
- smartWallet: balances.smartWallet,
2571
- totalBalance: balances.totalBalance,
2572
- totalBalanceAsset: balances.totalBalanceAsset.toLowerCase(),
2573
- tokens: balances.tokens.map(token),
2574
- positions: balances.positions.map(position)
2575
- };
2576
- }
2577
- function mapYieldseekerEarnings(value) {
2578
- const earnings = requireEnvelope(
2579
- value,
2580
- "earnings",
2581
- "earnings"
2582
- );
2583
- if (typeof earnings.smartWallet !== "string" || typeof earnings.lifetimeEarnings !== "number" || !Array.isArray(earnings.tokens)) {
2584
- return invalid("earnings", "missing required fields");
2585
- }
2586
- return {
2587
- smartWallet: earnings.smartWallet,
2588
- lifetimeEarnings: earnings.lifetimeEarnings,
2589
- tokens: earnings.tokens.map(token)
2590
- };
2591
- }
2592
- function mapYieldseekerApy(value) {
2593
- const apy = requireEnvelope(
2594
- value,
2595
- "apy",
2596
- "apy"
2597
- );
2598
- if (typeof apy.walletAddress !== "string" || typeof apy.weightedApyAfterFee !== "number" || !apy.apyByChainAndAsset || typeof apy.apyByChainAndAsset !== "object" || !Array.isArray(apy.history)) {
2599
- return invalid("apy", "missing required fields");
2600
- }
2601
- return {
2602
- walletAddress: apy.walletAddress,
2603
- weightedApyAfterFee: apy.weightedApyAfterFee,
2604
- apyByChainAndAsset: mapApyMatrix(apy.apyByChainAndAsset),
2605
- history: apy.history.map((point) => ({
2606
- date: String(point.date),
2607
- apy: Number(point.apy)
2608
- }))
2609
- };
2610
- }
2611
- function historyAction(value) {
2612
- const normalized = value.trim().toLowerCase();
2613
- if (normalized === "rebalance") return "Rebalance";
2614
- if (normalized === "deposit") return "Deposit";
2615
- if (normalized === "top up" || normalized === "topup") return "Top up";
2616
- if (normalized === "withdraw" || normalized === "withdrawal")
2617
- return "Withdraw";
2618
- if (normalized === "earned" || normalized === "earnings") return "Earned";
2619
- return invalid("history", `unsupported action ${value}`);
2620
- }
2621
- function historyItem(value) {
2622
- return {
2623
- agent: "yieldseeker",
2624
- action: historyAction(value.action),
2625
- date: String(value.date),
2626
- oldApy: value.oldApy === null ? null : String(value.oldApy),
2627
- newApy: value.newApy === null ? null : String(value.newApy),
2628
- transactions: (value.transactions ?? []).map((transaction) => ({
2629
- txHashes: transaction.txHashes.map(String),
2630
- ...typeof transaction.chainId === "number" ? { chainId: transaction.chainId } : {},
2631
- ...typeof transaction.tokenSymbol === "string" ? { tokenSymbol: transaction.tokenSymbol } : {},
2632
- ...typeof transaction.amount === "string" ? { amount: transaction.amount } : {}
2633
- })),
2634
- rebalanceLog: (value.rebalanceLog ?? []).map((entry) => ({
2635
- fromProtocol: String(entry.fromProtocol),
2636
- toProtocol: String(entry.toProtocol),
2637
- ...entry.fromPool ? { fromPool: entry.fromPool } : {},
2638
- ...entry.toPool ? { toPool: entry.toPool } : {},
2639
- tokenSymbol: String(entry.tokenSymbol),
2640
- // Unlike Yieldseeker's other read-response amounts, live history
2641
- // rebalance amounts are returned in the token's smallest unit. Normalize
2642
- // them at the adapter boundary so every Owney consumer receives the
2643
- // shared human-readable decimal shape.
2644
- amount: rebalanceAmount(String(entry.amount), String(entry.tokenSymbol)),
2645
- status: entry.status
2646
- }))
2647
- };
2648
- }
2649
- function mapYieldseekerHistory(value) {
2650
- const history = requireEnvelope(
2651
- value,
2652
- "history",
2653
- "history"
2654
- );
2655
- if (!Array.isArray(history.data) || typeof history.hasMore !== "boolean") {
2656
- return invalid("history", "missing required fields");
2657
- }
2658
- return {
2659
- data: history.data.map(historyItem),
2660
- hasMore: history.hasMore,
2661
- ...history.hasMore && typeof history.nextCursor === "string" ? { nextCursor: history.nextCursor } : {}
2662
- };
2663
- }
2664
- function mapYieldseekerAgentApy(value) {
2665
- const agentApy = requireEnvelope(
2666
- value,
2667
- "agentApy",
2668
- "agent APY"
2669
- );
2670
- if (typeof agentApy.averageApy !== "number") {
2671
- return invalid("agent APY", "missing averageApy");
2672
- }
2673
- return {
2674
- averageApy: agentApy.averageApy,
2675
- ...agentApy.detailedApys ? {
2676
- detailedApys: {
2677
- apyPerAsset: mapApyMatrix(agentApy.detailedApys.apyPerAsset)
2678
- }
2679
- } : {}
2680
- };
2681
- }
2682
-
2683
- // src/agents/yieldseeker/yieldseeker.agent.ts
2684
- function query(params) {
2685
- const search = new URLSearchParams();
2686
- for (const [key2, value] of Object.entries(params)) {
2687
- if (value !== void 0) search.set(key2, String(value));
2688
- }
2689
- const encoded = search.toString();
2690
- return encoded ? `?${encoded}` : "";
2691
- }
2692
- var YieldseekerAgent = class {
2693
- id = "yieldseeker";
2694
- balanceComposition = "tokens-plus-positions";
2695
- supportedChainIds = [8453];
2696
- supportedAssets = [
2697
- {
2698
- chainId: 8453,
2699
- chain: "BASE",
2700
- assets: [
2701
- { symbol: "USDC", minDepositAmount: "1" },
2702
- { symbol: "WETH", minDepositAmount: "1" }
2703
- ]
2704
- }
2705
- ];
2706
- api;
2707
- auth;
2708
- transactionExecutor;
2709
- unwindReceiptWaiter;
2710
- activated = /* @__PURE__ */ new Set();
2711
- constructor(owneyApiKey, options = {}) {
2712
- this.api = new YieldseekerApiClient(
2713
- owneyApiKey,
2714
- options.baseUrl ?? getYieldseekerProxyBaseUrl(),
2715
- options.fetchFn
2716
- );
2717
- this.auth = new YieldseekerAuth(options.auth);
2718
- this.transactionExecutor = options.transactionExecutor;
2719
- this.unwindReceiptWaiter = options.unwindReceiptWaiter;
2720
- }
2721
- async disconnect() {
2722
- this.auth.clear();
2723
- this.activated.clear();
2724
- }
2725
- async activateAgent(state, chainId, asset) {
2726
- this.assertChain(chainId);
2727
- await this.auth.getToken(state, chainId);
2728
- if (asset === "USDC" || asset === "WETH") {
2729
- await this.ensureActivated(state, chainId, asset);
2730
- }
2731
- }
2732
- async deposit(state, chainId, amount, asset, depositCallback) {
2733
- this.assertChain(chainId);
2734
- this.assertAsset(asset);
2735
- if (BigInt(amount) <= 0n) {
2736
- throw new OwneyError(
2737
- "DEPOSIT_AMOUNT_BELOW_MINIMUM",
2738
- "Yieldseeker deposits must be greater than zero.",
2739
- { amount, minDepositAmount: "1" },
2740
- this.id
2741
- );
2742
- }
2743
- await this.ensureActivated(state, chainId, asset);
2744
- const response = await this.walletRequest(
2745
- state,
2746
- chainId,
2747
- "/deposits",
2748
- { method: "POST", body: { chainId, asset, amount } }
2749
- );
2750
- const deposit = response?.deposit;
2751
- if (!deposit?.transaction || typeof deposit.amount !== "string" || deposit.amount !== amount || typeof deposit.smartWallet !== "string" || !isAddress(deposit.smartWallet)) {
2752
- throw this.invalidResponse("deposit");
2753
- }
2754
- if (depositCallback) {
2755
- provideDepositVerificationContext(depositCallback, {
2756
- agentId: "yieldseeker",
2757
- // Re-read after /deposits so an authentication retry cannot forward
2758
- // the stale token that Yieldseeker just rejected.
2759
- signature: await this.auth.getToken(state, chainId)
2760
- });
2761
- }
2762
- const txHash = depositCallback ? await depositCallback(deposit.smartWallet, chainId, amount) : await this.submitTransaction(state, chainId, deposit.transaction);
2763
- const confirmation = await this.walletRequest(
2764
- state,
2765
- chainId,
2766
- "/deposits/confirm",
2767
- { method: "POST", body: { chainId, asset } }
2768
- );
2769
- if (typeof confirmation?.confirmation?.autoseekQueued !== "boolean") {
2770
- throw this.invalidResponse("deposit confirmation", {
2771
- transactionHash: txHash,
2772
- transactionConfirmed: true
2773
- });
2774
- }
2775
- return {
2776
- txHash,
2777
- smartWallet: deposit.smartWallet,
2778
- amount: deposit.amount
2779
- };
2780
- }
2781
- async withdraw(state, chainId, asset, amount) {
2782
- this.assertChain(chainId);
2783
- this.assertAsset(asset);
2784
- if (amount !== void 0 && BigInt(amount) <= 0n) {
2785
- throw new OwneyError(
2786
- "WITHDRAW_FAILED",
2787
- "Yieldseeker withdrawals must be greater than zero.",
2788
- { amount },
2789
- this.id
2790
- );
2791
- }
2792
- const balances = await this.getBalances(state, chainId);
2793
- const decimals = asset === "USDC" ? 6 : 18;
2794
- const targetAsset = asset.toUpperCase();
2795
- const idle = balances.tokens.filter(
2796
- (token2) => token2.chainId === chainId && token2.asset.toUpperCase() === targetAsset
2797
- ).reduce((total, token2) => total + parseUnits(token2.amount, decimals), 0n);
2798
- const positions = (balances.positions ?? []).filter(
2799
- (position2) => this.positionMatchesChain(position2.chain, chainId) && position2.asset.toUpperCase() === targetAsset
2800
- ).map((position2) => ({
2801
- position: position2,
2802
- amount: position2.amountRaw !== void 0 ? BigInt(position2.amountRaw) : parseUnits(position2.amount, decimals)
2803
- }));
2804
- const deployed = positions.reduce(
2805
- (total, position2) => total + position2.amount,
2806
- 0n
2807
- );
2808
- const totalAvailable = idle + deployed;
2809
- const requested = amount === void 0 ? totalAvailable : BigInt(amount);
2810
- if (requested > totalAvailable) {
2811
- throw new OwneyError(
2812
- "WITHDRAW_INSUFFICIENT_BALANCE",
2813
- `Requested withdrawal "${requested.toString()}" exceeds available Yieldseeker balance "${totalAvailable.toString()}" for asset "${asset}".`,
2814
- {
2815
- asset,
2816
- requested: requested.toString(),
2817
- available: totalAvailable.toString()
2818
- },
2819
- this.id
2820
- );
2821
- }
2822
- const requiredFromPositions = requested > idle ? requested - idle : 0n;
2823
- const unwindPlans = [];
2824
- let remainingToUnwind = requiredFromPositions;
2825
- for (const { position: position2, amount: positionAmount } of positions) {
2826
- if (remainingToUnwind === 0n) break;
2827
- if (positionAmount <= 0n) continue;
2828
- if (!position2.protocolId || !isAddress(position2.protocolId)) {
2829
- throw this.invalidResponse("position", {
2830
- reason: "A deployed position is missing its vault address.",
2831
- protocol: position2.protocol,
2832
- pool: position2.pool
2833
- });
2834
- }
2835
- const unwindAmount = positionAmount < remainingToUnwind ? positionAmount : remainingToUnwind;
2836
- unwindPlans.push({
2837
- vaultAddress: getAddress2(position2.protocolId),
2838
- amount: unwindAmount
2839
- });
2840
- remainingToUnwind -= unwindAmount;
2841
- }
2842
- if (remainingToUnwind > 0n) {
2843
- throw this.invalidResponse("balances", {
2844
- reason: "Deployed position balances could not cover the unwind.",
2845
- required: requiredFromPositions.toString(),
2846
- planned: (requiredFromPositions - remainingToUnwind).toString()
2847
- });
2848
- }
2849
- for (const plan of unwindPlans) {
2850
- const response2 = await this.walletRequest(
2851
- state,
2852
- chainId,
2853
- "/positions/unwind",
2854
- {
2855
- method: "POST",
2856
- body: {
2857
- chainId,
2858
- asset,
2859
- vaultAddress: plan.vaultAddress,
2860
- amount: plan.amount.toString()
2861
- }
2862
- }
2863
- );
2864
- const transactionHash = response2?.unwind?.transactionHash;
2865
- if (!this.isTransactionHash(transactionHash)) {
2866
- throw this.invalidResponse("position unwind");
2867
- }
2868
- await this.waitForUnwindReceipt(state, chainId, transactionHash);
2869
- }
2870
- const response = await this.walletRequest(
2871
- state,
2872
- chainId,
2873
- "/withdrawals",
2874
- {
2875
- method: "POST",
2876
- body: { chainId, asset, ...amount !== void 0 ? { amount } : {} }
2877
- }
2878
- );
2879
- const withdrawal = response?.withdrawal;
2880
- if (!withdrawal?.transaction || typeof withdrawal.amount !== "string") {
2881
- throw this.invalidResponse("withdrawal");
2882
- }
2883
- const txHash = await this.submitTransaction(
2884
- state,
2885
- chainId,
2886
- withdrawal.transaction
2887
- );
2888
- return {
2889
- txHash,
2890
- type: amount === void 0 ? "full" : "partial",
2891
- amount: withdrawal.amount
2892
- };
2893
- }
2894
- async getBalances(state, chainId) {
2895
- return mapYieldseekerBalances(
2896
- await this.walletRequest(
2897
- state,
2898
- chainId,
2899
- `/balances${query({ chainId })}`
2900
- )
2901
- );
2902
- }
2903
- async getEarnings(state, chainId) {
2904
- return mapYieldseekerEarnings(
2905
- await this.walletRequest(
2906
- state,
2907
- chainId,
2908
- `/earnings${query({ chainId })}`
2909
- )
2910
- );
2911
- }
2912
- async getAccountApy(state, chainId, days, tokenSymbol) {
2913
- return mapYieldseekerApy(
2914
- await this.walletRequest(
2915
- state,
2916
- chainId,
2917
- `/apy${query({ chainId, days, tokenSymbol })}`
2918
- )
2919
- );
2920
- }
2921
- async getHistory(state, chainId, options) {
2922
- return mapYieldseekerHistory(
2923
- await this.walletRequest(
2924
- state,
2925
- chainId,
2926
- `/history${query({
2927
- chainId,
2928
- limit: options?.limit ?? 10,
2929
- cursor: options?.cursor,
2930
- fromDate: options?.fromDate,
2931
- toDate: options?.toDate
2932
- })}`
2933
- )
2934
- );
2935
- }
2936
- async getUserProfile(state, chainId) {
2937
- return mapYieldseekerProfile(
2938
- await this.walletRequest(state, chainId, `/profile${query({ chainId })}`)
2939
- );
2940
- }
2941
- async getAgentApy(days, options) {
2942
- this.assertOptionalChain(options?.chainId);
2943
- return mapYieldseekerAgentApy(
2944
- await this.api.request(
2945
- `/agent/apy${query({
2946
- days,
2947
- tokenSymbol: options?.tokenSymbol,
2948
- chainId: options?.chainId
2949
- })}`
2950
- )
2951
- );
2952
- }
2953
- async ensureActivated(state, chainId, asset) {
2954
- const key2 = `${state.walletAddress.toLowerCase()}:${chainId}:${asset}`;
2955
- if (this.activated.has(key2)) return;
2956
- const response = await this.walletRequest(
2957
- state,
2958
- chainId,
2959
- "/activation",
2960
- { method: "POST", body: { chainId, asset } }
2961
- );
2962
- if (typeof response?.activation?.smartWallet !== "string" || typeof response.activation.deployed !== "boolean" || typeof response.activation.hasActiveSessionKey !== "boolean") {
2963
- throw this.invalidResponse("activation");
2964
- }
2965
- this.activated.add(key2);
2966
- }
2967
- async walletRequest(state, chainId, path, options = {}) {
2968
- this.assertChain(chainId);
2969
- let signature = await this.auth.getToken(state, chainId);
2970
- try {
2971
- return await this.api.request(path, { ...options, signature });
2972
- } catch (error) {
2973
- if (!(error instanceof YieldseekerApiError)) throw error;
2974
- if (error.isAuthenticationError) {
2975
- this.auth.clear(state, chainId);
2976
- signature = await this.auth.getToken(state, chainId);
2977
- try {
2978
- return await this.api.request(path, { ...options, signature });
2979
- } catch (retryError) {
2980
- throw this.mapApiError(retryError);
2981
- }
2982
- }
2983
- throw this.mapApiError(error);
2984
- }
2985
- }
2986
- mapApiError(error) {
2987
- if (!(error instanceof YieldseekerApiError)) {
2988
- return new OwneyError(
2989
- "AGENT_API_ERROR",
2990
- "Yieldseeker request failed.",
2991
- { cause: error instanceof Error ? error.message : String(error) },
2992
- this.id
2993
- );
2994
- }
2995
- const code = error.isAuthenticationError ? "AGENT_AUTH_FAILED" : error.providerCode === "REQUEST_TIMEOUT" ? "AGENT_TIMEOUT" : "AGENT_API_ERROR";
2996
- return new OwneyError(
2997
- code,
2998
- `Yieldseeker request failed: ${error.providerCode}.`,
2999
- {
3000
- statusCode: error.status,
3001
- providerCode: error.providerCode,
3002
- ...error.responseFields ? { fields: error.responseFields } : {}
3003
- },
3004
- this.id
3005
- );
3006
- }
3007
- async submitTransaction(state, chainId, transaction) {
3008
- if (this.transactionExecutor) {
3009
- return this.transactionExecutor(state, chainId, transaction);
3010
- }
3011
- if (typeof transaction.from !== "string" || typeof transaction.to !== "string" || typeof transaction.data !== "string" || typeof transaction.value !== "string" || transaction.chainId !== chainId) {
3012
- throw this.invalidResponse("transaction");
3013
- }
3014
- const account = getAddress2(state.walletAddress);
3015
- if (getAddress2(transaction.from) !== account) {
3016
- throw this.invalidResponse("transaction", {
3017
- reason: "transaction.from does not match the connected wallet"
3018
- });
3019
- }
3020
- const walletClient = createWalletClient2({
3021
- account,
3022
- chain: base3,
3023
- transport: custom2(state.provider)
3024
- });
3025
- const publicClient = createPublicClient3({
3026
- chain: base3,
3027
- transport: custom2(state.provider)
3028
- });
3029
- await ensureWalletOnChain(
3030
- publicClient,
3031
- walletClient,
3032
- 8453
3033
- );
3034
- const hash = await walletClient.sendTransaction({
3035
- account,
3036
- chain: base3,
3037
- to: getAddress2(transaction.to),
3038
- data: transaction.data,
3039
- value: BigInt(transaction.value)
3040
- });
3041
- const receipt = await publicClient.waitForTransactionReceipt({
3042
- hash,
3043
- confirmations: 1
3044
- });
3045
- if (receipt.status !== "success") {
3046
- throw new OwneyError(
3047
- "AGENT_TRANSACTION_REVERTED",
3048
- `Yieldseeker transaction reverted (${hash}).`,
3049
- { transactionHash: hash },
3050
- this.id
3051
- );
3052
- }
3053
- return hash;
3054
- }
3055
- async waitForUnwindReceipt(state, chainId, transactionHash) {
3056
- if (this.unwindReceiptWaiter) {
3057
- await this.unwindReceiptWaiter(state, chainId, transactionHash);
3058
- return;
3059
- }
3060
- const publicClient = createPublicClient3({
3061
- chain: base3,
3062
- transport: custom2(state.provider)
3063
- });
3064
- const receipt = await publicClient.waitForTransactionReceipt({
3065
- hash: transactionHash,
3066
- confirmations: 1
3067
- });
3068
- if (receipt.status !== "success") {
3069
- throw new OwneyError(
3070
- "AGENT_TRANSACTION_REVERTED",
3071
- `Yieldseeker position unwind reverted (${transactionHash}).`,
3072
- { transactionHash },
3073
- this.id
3074
- );
3075
- }
3076
- }
3077
- positionMatchesChain(chain, chainId) {
3078
- const normalized = chain.trim().toUpperCase();
3079
- return normalized === String(chainId) || normalized === "BASE";
3080
- }
3081
- isTransactionHash(value) {
3082
- return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
3083
- }
3084
- assertChain(chainId) {
3085
- if (chainId !== 8453) {
3086
- throw new OwneyError(
3087
- "CHAIN_UNSUPPORTED",
3088
- `Yieldseeker does not support chain ${chainId}.`,
3089
- { chainId, supportedChainIds: [8453] },
3090
- this.id
3091
- );
3092
- }
3093
- }
3094
- assertOptionalChain(chainId) {
3095
- if (chainId !== void 0) this.assertChain(chainId);
3096
- }
3097
- assertAsset(asset) {
3098
- if (asset !== "USDC" && asset !== "WETH") {
3099
- throw new OwneyError(
3100
- "ASSET_UNSUPPORTED",
3101
- `Yieldseeker does not support asset ${asset}.`,
3102
- { asset, supportedAssets: ["USDC", "WETH"] },
3103
- this.id
3104
- );
3105
- }
3106
- }
3107
- invalidResponse(operation, details = {}) {
3108
- return new OwneyError(
3109
- "AGENT_INVALID_RESPONSE",
3110
- `Yieldseeker returned an invalid ${operation} response.`,
3111
- details,
3112
- this.id
3113
- );
3114
- }
3115
- };
3116
-
3117
- // src/lib/routing-api.ts
3118
- var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
3119
- async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
3120
- const url = `${baseUrl}/api/v1/agent/org-config`;
3121
- try {
3122
- const res = await fetch(url, {
3123
- method: "GET",
3124
- headers: {
3125
- "Content-Type": "application/json",
3126
- "x-owney-api-key": `${apiKey}`
3127
- }
3128
- });
3129
- if (!res.ok) {
3130
- if (res.status !== 404) {
3131
- console.warn(
3132
- `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
3133
- );
3134
- }
3135
- return null;
3136
- }
3137
- const json = await res.json();
3138
- const policy = json.success ? json.data ?? null : null;
3139
- debugLog(
3140
- "owney-sdk",
3141
- policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
3142
- policy ?? void 0
3143
- );
3144
- return policy;
3145
- } catch (error) {
3146
- console.warn(
3147
- "[owney-sdk] Could not read org agent config (non-fatal):",
3148
- error instanceof Error ? error.message : String(error)
3149
- );
3150
- return null;
3151
- }
3152
- }
3153
- async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
3154
- const url = `${baseUrl}/api/v1/agent/keys`;
3155
- const res = await fetch(url, {
3156
- method: "GET",
3157
- headers: {
3158
- "Content-Type": "application/json",
3159
- "x-owney-api-key": `${apiKey}`
3160
- }
3161
- });
3162
- if (!res.ok) {
3163
- const text = await res.text().catch(() => "");
3164
- throw new OwneyError(
3165
- "API_ROUTING_ERROR",
3166
- `Routing API error ${res.status}: ${text}`,
3167
- { statusCode: res.status, responseBody: text }
3168
- );
3169
- }
3170
- const json = await res.json();
3171
- if (!json.success) {
3172
- throw new OwneyError(
3173
- "API_ROUTING_FAILED",
3174
- `Routing API request failed: ${json.message}`,
3175
- { message: json.message }
3176
- );
3177
- }
3178
- return json.data;
3179
- }
3180
-
3181
- // src/lib/health-report.ts
3182
- var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
3183
- async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL3) {
3184
- try {
3185
- await fetch(`${baseUrl}/api/v1/agent/health-report`, {
3186
- method: "POST",
3187
- headers: {
3188
- "Content-Type": "application/json",
3189
- "x-owney-api-key": apiKey
3190
- },
3191
- body: JSON.stringify({
3192
- agent_type: agentType,
3193
- error_code: errorCode,
3194
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
3195
- })
3196
- });
3197
- } catch (err) {
3198
- console.warn(
3199
- `[owney-sdk] health-report failed for agent "${agentType}":`,
3200
- err instanceof Error ? err.message : err
3201
- );
3202
- }
3203
- }
3204
- async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
3205
- try {
3206
- return await fn();
3207
- } catch (err) {
3208
- const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
3209
- void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
3210
- throw err;
3211
- }
3212
- }
3213
-
3214
- // src/lib/helpers/withdraw-helper.ts
3215
- import { parseUnits as parseUnits2 } from "viem";
3216
- function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
3217
- const target = asset.toUpperCase();
3218
- return agents.map((agent) => {
3219
- const agentBalance = aggregated[agent.id];
3220
- const tokenBalance = agentBalance?.tokens.find(
3221
- (t) => t.chainId === chainId && t.asset.toUpperCase() === target
3222
- );
3223
- let balance = tokenBalance ? parseUnits2(tokenBalance.amount, decimals) : 0n;
3224
- if (agent.balanceComposition === "tokens-plus-positions") {
3225
- const chainNameById = {
3226
- 1: "ETHEREUM",
3227
- 8453: "BASE",
3228
- 42161: "ARBITRUM"
3229
- };
3230
- const targetChain = chainNameById[chainId];
3231
- for (const position2 of agentBalance?.positions ?? []) {
3232
- const positionChain = position2.chain.trim().toUpperCase();
3233
- const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
3234
- if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
3235
- if (position2.amountRaw !== void 0) {
3236
- try {
3237
- balance += BigInt(position2.amountRaw);
3238
- continue;
3239
- } catch {
3240
- }
3241
- }
3242
- balance += parseUnits2(position2.amount, decimals);
3243
- }
3244
- }
3245
- return { agent, balance };
3246
- });
3247
- }
3248
- function planProportionalShares(balances, requested, totalAvailable) {
3249
- const plans = balances.map(({ agent, balance }) => ({
3250
- agent,
3251
- balance,
3252
- planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
3253
- }));
3254
- const assigned = plans.reduce((s, p) => s + p.planned, 0n);
3255
- let remainder = requested - assigned;
3256
- const byHeadroom = [...plans].sort((a, b) => {
3257
- const diff = b.balance - b.planned - (a.balance - a.planned);
3258
- return diff > 0n ? 1 : diff < 0n ? -1 : 0;
3259
- });
3260
- for (const p of byHeadroom) {
3261
- if (remainder === 0n) break;
3262
- const headroom = p.balance - p.planned;
3263
- if (headroom <= 0n) continue;
3264
- const take = headroom < remainder ? headroom : remainder;
3265
- p.planned += take;
3266
- remainder -= take;
2257
+ inputs: [{ name: "account", type: "address" }],
2258
+ outputs: [{ name: "", type: "uint256" }]
3267
2259
  }
3268
- return plans;
2260
+ ];
2261
+ function buildPermitTransferFromTypedData(input) {
2262
+ return {
2263
+ domain: {
2264
+ name: "Permit2",
2265
+ chainId: input.chainId,
2266
+ verifyingContract: PERMIT2_ADDRESS
2267
+ },
2268
+ types: {
2269
+ PermitTransferFrom: [
2270
+ { name: "permitted", type: "TokenPermissions" },
2271
+ { name: "spender", type: "address" },
2272
+ { name: "nonce", type: "uint256" },
2273
+ { name: "deadline", type: "uint256" }
2274
+ ],
2275
+ TokenPermissions: [
2276
+ { name: "token", type: "address" },
2277
+ { name: "amount", type: "uint256" }
2278
+ ]
2279
+ },
2280
+ primaryType: "PermitTransferFrom",
2281
+ message: input.message
2282
+ };
3269
2283
  }
3270
- function planDisabledDrain(disabled, requested) {
3271
- const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
3272
- (a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
3273
- );
3274
- const plans = [];
3275
- let remaining = requested;
3276
- for (const { agent, balance } of sorted) {
3277
- if (remaining === 0n) {
3278
- plans.push({ agent, balance, planned: 0n });
3279
- continue;
3280
- }
3281
- const take = balance < remaining ? balance : remaining;
3282
- plans.push({ agent, balance, planned: take });
3283
- remaining -= take;
3284
- }
3285
- return { plans, remaining };
2284
+ function randomPermit2Nonce() {
2285
+ const bytes = new Uint8Array(32);
2286
+ globalThis.crypto.getRandomValues(bytes);
2287
+ return BigInt(bytesToHex2(bytes));
3286
2288
  }
3287
- function redistributeShare(plans, fromIndex, amount, candidatePool) {
3288
- const pool = candidatePool ?? plans.slice(fromIndex + 1);
3289
- const candidates = pool.filter((c) => c.balance - c.planned > 0n);
3290
- const totalHeadroom = candidates.reduce(
3291
- (s, c) => s + (c.balance - c.planned),
3292
- 0n
3293
- );
3294
- if (totalHeadroom === 0n) return;
3295
- let distributed = 0n;
3296
- for (const c of candidates) {
3297
- const headroom = c.balance - c.planned;
3298
- const proportional = headroom * amount / totalHeadroom;
3299
- const give = proportional > headroom ? headroom : proportional;
3300
- c.planned += give;
3301
- distributed += give;
3302
- }
3303
- let leftover = amount - distributed;
3304
- for (const c of candidates) {
3305
- if (leftover === 0n) break;
3306
- const headroom = c.balance - c.planned;
3307
- if (headroom <= 0n) continue;
3308
- const take = headroom < leftover ? headroom : leftover;
3309
- c.planned += take;
3310
- leftover -= take;
3311
- }
2289
+ async function readPermit2Allowance(publicClient, token, owner) {
2290
+ return publicClient.readContract({
2291
+ address: token,
2292
+ abi: ERC20_ALLOWANCE_ABI,
2293
+ functionName: "allowance",
2294
+ args: [owner, PERMIT2_ADDRESS]
2295
+ });
3312
2296
  }
3313
- function sumWithdrawnAmount(results) {
3314
- return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
2297
+ async function readErc20Balance(publicClient, token, owner) {
2298
+ return publicClient.readContract({
2299
+ address: token,
2300
+ abi: ERC20_ALLOWANCE_ABI,
2301
+ functionName: "balanceOf",
2302
+ args: [owner]
2303
+ });
3315
2304
  }
3316
2305
 
3317
- // src/lib/helpers/account-apy-helper.ts
3318
- function balanceForApyScope(balance, chainId, tokenSymbol) {
3319
- if (!tokenSymbol) {
3320
- const total = Number(balance.totalBalance);
3321
- return Number.isFinite(total) && total > 0 ? total : 0;
3322
- }
3323
- const normalizedToken = tokenSymbol.toUpperCase();
3324
- return balance.tokens.reduce((total, token2) => {
3325
- if (Number(token2.chainId) !== chainId || String(token2.asset).toUpperCase() !== normalizedToken) {
3326
- return total;
3327
- }
3328
- const amount = Number(token2.amount);
3329
- return Number.isFinite(amount) && amount > 0 ? total + amount : total;
3330
- }, 0);
3331
- }
3332
- function aggregateApyHistory(agentApys, agentBalances) {
3333
- const byDate = /* @__PURE__ */ new Map();
3334
- for (const [id, accountApy] of Object.entries(agentApys)) {
3335
- const balance = agentBalances[id] ?? 0;
3336
- if (!Number.isFinite(balance) || balance <= 0) continue;
3337
- for (const point of accountApy.history ?? []) {
3338
- const apy = Number(point.apy);
3339
- if (!point.date || !Number.isFinite(apy)) continue;
3340
- const current = byDate.get(point.date) ?? { weightedSum: 0, weight: 0 };
3341
- current.weightedSum += apy * balance;
3342
- current.weight += balance;
3343
- byDate.set(point.date, current);
3344
- }
3345
- }
3346
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
3347
- date,
3348
- apy: value.weightedSum / value.weight
3349
- }));
2306
+ // src/lib/chain-guard.ts
2307
+ var CHAIN_NAMES = {
2308
+ 1: "Ethereum",
2309
+ 8453: "Base",
2310
+ 42161: "Arbitrum"
2311
+ };
2312
+ function chainName(chainId) {
2313
+ return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
3350
2314
  }
3351
- function aggregateApyByChainAndAsset(agentApys, agentBalances) {
3352
- const sums = {};
3353
- const weights = {};
3354
- for (const id of Object.keys(agentApys)) {
3355
- const cells = agentApys[id].apyByChainAndAsset;
3356
- const balance = agentBalances[id] ?? 0;
3357
- if (!cells || balance <= 0) continue;
3358
- for (const [chainKey, perAsset] of Object.entries(cells)) {
3359
- if (!perAsset) continue;
3360
- const chainId = Number(chainKey);
3361
- for (const [asset, apyValue] of Object.entries(perAsset)) {
3362
- const apy = Number(apyValue ?? 0);
3363
- if (apy === 0) continue;
3364
- sums[chainId] ??= {};
3365
- weights[chainId] ??= {};
3366
- sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
3367
- weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2315
+ async function ensureWalletOnChain(pub, wallet, expected) {
2316
+ const actual = await pub.getChainId();
2317
+ if (actual === expected) return;
2318
+ try {
2319
+ await wallet.switchChain({ id: expected });
2320
+ } catch (error) {
2321
+ throw new OwneyError(
2322
+ "CHAIN_MISMATCH",
2323
+ `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2324
+ {
2325
+ expectedChainId: expected,
2326
+ actualChainId: actual,
2327
+ cause: error instanceof Error ? error.message : String(error)
3368
2328
  }
3369
- }
2329
+ );
3370
2330
  }
3371
- const out = {};
3372
- for (const chainKey of Object.keys(sums)) {
3373
- const chainId = Number(chainKey);
3374
- const perAssetOut = {};
3375
- for (const asset of Object.keys(sums[chainId])) {
3376
- const w = weights[chainId][asset];
3377
- if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
3378
- }
3379
- if (Object.keys(perAssetOut).length > 0) {
3380
- out[chainId] = perAssetOut;
3381
- }
2331
+ const after = await pub.getChainId();
2332
+ if (after !== expected) {
2333
+ throw new OwneyError(
2334
+ "CHAIN_MISMATCH",
2335
+ `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2336
+ { expectedChainId: expected, actualChainId: after }
2337
+ );
3382
2338
  }
3383
- return out;
3384
2339
  }
3385
2340
 
3386
- // src/client.ts
3387
- import {
3388
- createPublicClient as createPublicClient4,
3389
- createWalletClient as createWalletClient3,
3390
- custom as custom3
3391
- } from "viem";
3392
- import { base as base4, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
2341
+ // src/lib/sponsored-deposit.ts
2342
+ var AUTH_WINDOW_SECONDS = 15 * 60;
2343
+ function makeSponsoredDepositCallback(deps) {
2344
+ const post = deps.httpPost ?? postSponsorTransferAuth;
2345
+ return async (smartWallet, chainId, amount) => {
2346
+ const cid = chainId;
2347
+ const token = deps.tokenAddressByChain[cid];
2348
+ if (!token) {
2349
+ throw new OwneyError(
2350
+ "CHAIN_UNSUPPORTED",
2351
+ `No sponsored token configured for chain ${chainId}`
2352
+ );
2353
+ }
2354
+ const pub = deps.getPublicClient(cid);
2355
+ const wallet = deps.getWalletClient(cid);
2356
+ await ensureWalletOnChain(pub, wallet, cid);
2357
+ try {
2358
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2359
+ if (balance < BigInt(amount)) {
2360
+ throw new OwneyError(
2361
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2362
+ "Insufficient balance for this deposit.",
2363
+ { token, chainId: cid, balance: balance.toString(), amount }
2364
+ );
2365
+ }
2366
+ } catch (err) {
2367
+ if (err instanceof OwneyError) throw err;
2368
+ console.warn(
2369
+ "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2370
+ err instanceof Error ? err.message : String(err)
2371
+ );
2372
+ }
2373
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2374
+ const validAfter = 0n;
2375
+ const validBefore = BigInt(
2376
+ Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2377
+ );
2378
+ const nonce = randomAuthNonce();
2379
+ const typedData = buildTransferWithAuthorizationTypedData({
2380
+ token,
2381
+ chainId: cid,
2382
+ tokenName,
2383
+ tokenVersion,
2384
+ message: {
2385
+ from: deps.ownerAddress,
2386
+ to: smartWallet,
2387
+ value: BigInt(amount),
2388
+ validAfter,
2389
+ validBefore,
2390
+ nonce
2391
+ }
2392
+ });
2393
+ const authSignature = await wallet.signTypedData({
2394
+ account: deps.ownerAddress,
2395
+ ...typedData
2396
+ });
2397
+ deps.onApproved?.();
2398
+ const result = await post({
2399
+ baseUrl: deps.baseUrl,
2400
+ apiKey: deps.apiKey,
2401
+ body: {
2402
+ chainId: cid,
2403
+ token,
2404
+ from: deps.ownerAddress,
2405
+ to: smartWallet,
2406
+ value: amount,
2407
+ validAfter: validAfter.toString(),
2408
+ validBefore: validBefore.toString(),
2409
+ nonce,
2410
+ authSignature,
2411
+ tokenName,
2412
+ tokenVersion
2413
+ }
2414
+ });
2415
+ return result.txHash;
2416
+ };
2417
+ }
3393
2418
 
3394
2419
  // src/lib/sponsored-weth-deposit.ts
3395
2420
  var PERMIT_WINDOW_SECONDS = 15 * 60;
3396
2421
  function makeSponsoredWethCallback(deps) {
3397
2422
  const get = deps.httpGet ?? getSponsorRelayerAddress;
3398
2423
  const post = deps.httpPost ?? postSponsorPermit2Transfer;
3399
- return makeVerificationAwareDepositCallback(
3400
- async (smartWallet, chainId, amount, verification) => {
3401
- const cid = chainId;
3402
- const token2 = deps.tokenAddressByChain[cid];
3403
- if (!token2) {
3404
- throw new OwneyError(
3405
- "CHAIN_UNSUPPORTED",
3406
- `No sponsored WETH configured for chain ${chainId}`
3407
- );
3408
- }
3409
- const amountWei = BigInt(amount);
3410
- const pub = deps.getPublicClient(cid);
3411
- const wallet = deps.getWalletClient(cid);
3412
- await ensureWalletOnChain(pub, wallet, cid);
3413
- try {
3414
- const balance = await readErc20Balance(pub, token2, deps.ownerAddress);
3415
- if (balance < amountWei) {
3416
- throw new OwneyError(
3417
- "DEPOSIT_INSUFFICIENT_BALANCE",
3418
- "Insufficient WETH balance for this deposit.",
3419
- { token: token2, chainId: cid, balance: balance.toString(), amount }
3420
- );
3421
- }
3422
- } catch (err) {
3423
- if (err instanceof OwneyError) throw err;
3424
- console.warn(
3425
- "[owney-sdk] WETH balance pre-check failed (non-fatal):",
3426
- err instanceof Error ? err.message : String(err)
3427
- );
3428
- }
3429
- const allowance = await readPermit2Allowance(
3430
- pub,
3431
- token2,
3432
- deps.ownerAddress
2424
+ return async (smartWallet, chainId, amount) => {
2425
+ const cid = chainId;
2426
+ const token = deps.tokenAddressByChain[cid];
2427
+ if (!token) {
2428
+ throw new OwneyError(
2429
+ "CHAIN_UNSUPPORTED",
2430
+ `No sponsored WETH configured for chain ${chainId}`
3433
2431
  );
3434
- if (allowance < amountWei) {
2432
+ }
2433
+ const amountWei = BigInt(amount);
2434
+ const pub = deps.getPublicClient(cid);
2435
+ const wallet = deps.getWalletClient(cid);
2436
+ await ensureWalletOnChain(pub, wallet, cid);
2437
+ try {
2438
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2439
+ if (balance < amountWei) {
3435
2440
  throw new OwneyError(
3436
- "PERMIT2_APPROVAL_REQUIRED",
3437
- "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
3438
- { token: token2, chainId: cid, allowance: allowance.toString(), amount }
2441
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2442
+ "Insufficient WETH balance for this deposit.",
2443
+ { token, chainId: cid, balance: balance.toString(), amount }
3439
2444
  );
3440
2445
  }
3441
- const relayer = await get({
3442
- baseUrl: deps.baseUrl,
3443
- apiKey: deps.apiKey,
3444
- chainId: cid
3445
- });
3446
- const nonce = randomPermit2Nonce();
3447
- const deadline = BigInt(
3448
- Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2446
+ } catch (err) {
2447
+ if (err instanceof OwneyError) throw err;
2448
+ console.warn(
2449
+ "[owney-sdk] WETH balance pre-check failed (non-fatal):",
2450
+ err instanceof Error ? err.message : String(err)
3449
2451
  );
3450
- const typedData = buildPermitTransferFromTypedData({
3451
- chainId: cid,
3452
- message: {
3453
- permitted: { token: token2, amount: amountWei },
3454
- spender: relayer,
3455
- nonce,
3456
- deadline
3457
- }
3458
- });
3459
- const signature = await wallet.signTypedData({
3460
- account: deps.ownerAddress,
3461
- ...typedData
3462
- });
3463
- deps.onApproved?.();
3464
- const result = await post({
3465
- baseUrl: deps.baseUrl,
3466
- apiKey: deps.apiKey,
3467
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
3468
- body: {
3469
- chainId: cid,
3470
- token: token2,
3471
- from: deps.ownerAddress,
3472
- to: smartWallet,
3473
- amount,
3474
- nonce: nonce.toString(),
3475
- deadline: deadline.toString(),
3476
- signature
3477
- }
3478
- });
3479
- return result.txHash;
3480
2452
  }
3481
- );
2453
+ const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
2454
+ if (allowance < amountWei) {
2455
+ throw new OwneyError(
2456
+ "PERMIT2_APPROVAL_REQUIRED",
2457
+ "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
2458
+ { token, chainId: cid, allowance: allowance.toString(), amount }
2459
+ );
2460
+ }
2461
+ const relayer = await get({
2462
+ baseUrl: deps.baseUrl,
2463
+ apiKey: deps.apiKey,
2464
+ chainId: cid
2465
+ });
2466
+ const nonce = randomPermit2Nonce();
2467
+ const deadline = BigInt(
2468
+ Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2469
+ );
2470
+ const typedData = buildPermitTransferFromTypedData({
2471
+ chainId: cid,
2472
+ message: {
2473
+ permitted: { token, amount: amountWei },
2474
+ spender: relayer,
2475
+ nonce,
2476
+ deadline
2477
+ }
2478
+ });
2479
+ const signature = await wallet.signTypedData({
2480
+ account: deps.ownerAddress,
2481
+ ...typedData
2482
+ });
2483
+ deps.onApproved?.();
2484
+ const result = await post({
2485
+ baseUrl: deps.baseUrl,
2486
+ apiKey: deps.apiKey,
2487
+ body: {
2488
+ chainId: cid,
2489
+ token,
2490
+ from: deps.ownerAddress,
2491
+ to: smartWallet,
2492
+ amount,
2493
+ nonce: nonce.toString(),
2494
+ deadline: deadline.toString(),
2495
+ signature
2496
+ }
2497
+ });
2498
+ return result.txHash;
2499
+ };
3482
2500
  }
3483
2501
 
3484
2502
  // src/lib/sponsored-calls-deposit.ts
@@ -3510,8 +2528,8 @@ function makeSponsoredCallsCallback(deps) {
3510
2528
  };
3511
2529
  return async (smartWallet, chainId, amount) => {
3512
2530
  const cid = chainId;
3513
- const token2 = deps.tokenAddressByChain[cid];
3514
- if (!token2) {
2531
+ const token = deps.tokenAddressByChain[cid];
2532
+ if (!token) {
3515
2533
  throw new OwneyError(
3516
2534
  "CHAIN_UNSUPPORTED",
3517
2535
  `No sponsored token configured for chain ${chainId}`
@@ -3537,7 +2555,7 @@ function makeSponsoredCallsCallback(deps) {
3537
2555
  from: deps.ownerAddress,
3538
2556
  chainId: toHex(chainId),
3539
2557
  atomicRequired: false,
3540
- calls: [{ to: token2, value: "0x0", data }],
2558
+ calls: [{ to: token, value: "0x0", data }],
3541
2559
  capabilities: {
3542
2560
  paymasterService: { url: absolutePaymasterUrl() }
3543
2561
  }
@@ -3576,10 +2594,10 @@ function makeSponsoredCallsCallback(deps) {
3576
2594
  function encodeMultiAgentCursor(map) {
3577
2595
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
3578
2596
  }
3579
- function decodeMultiAgentCursor(token2) {
2597
+ function decodeMultiAgentCursor(token) {
3580
2598
  let parsed;
3581
2599
  try {
3582
- const json = Buffer.from(token2, "base64").toString("utf8");
2600
+ const json = Buffer.from(token, "base64").toString("utf8");
3583
2601
  parsed = JSON.parse(json);
3584
2602
  } catch {
3585
2603
  throw new InvalidHistoryCursorError(
@@ -3599,7 +2617,7 @@ var SPONSORED_USDC_BY_CHAIN = {
3599
2617
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
3600
2618
  };
3601
2619
  var VIEM_CHAIN2 = {
3602
- 8453: base4,
2620
+ 8453: base2,
3603
2621
  42161: arbitrum2,
3604
2622
  1: mainnet2
3605
2623
  };
@@ -3629,7 +2647,6 @@ var OwneySDK = class {
3629
2647
  orgAgentConfig;
3630
2648
  orgAgentConfigPromise = null;
3631
2649
  zyfaiRpcUrls;
3632
- yieldseekerApiBaseUrl;
3633
2650
  routingApiBaseUrl;
3634
2651
  referralSource;
3635
2652
  cachedSponsoredCallback = null;
@@ -3641,7 +2658,6 @@ var OwneySDK = class {
3641
2658
  this.apiKey = config.apiKey;
3642
2659
  if (config.debug) setOwneyDebug(true);
3643
2660
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
3644
- this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
3645
2661
  this.routingApiBaseUrl = config.routingApiBaseUrl;
3646
2662
  this.paymasterServiceUrl = config.paymasterServiceUrl;
3647
2663
  this.referralSource = config.referralSource;
@@ -3744,14 +2760,14 @@ var OwneySDK = class {
3744
2760
  // Casts work around viem's chain-narrowed Client vs the generic
3745
2761
  // PublicClient/WalletClient param types — structurally identical at
3746
2762
  // runtime, but the two share a name TS treats as unrelated.
3747
- getPublicClient: (cid) => createPublicClient4({
2763
+ getPublicClient: (cid) => createPublicClient2({
3748
2764
  chain: VIEM_CHAIN2[cid],
3749
- transport: custom3(provider)
2765
+ transport: custom(provider)
3750
2766
  }),
3751
- getWalletClient: (cid) => createWalletClient3({
2767
+ getWalletClient: (cid) => createWalletClient({
3752
2768
  account: owner,
3753
2769
  chain: VIEM_CHAIN2[cid],
3754
- transport: custom3(provider)
2770
+ transport: custom(provider)
3755
2771
  })
3756
2772
  });
3757
2773
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -3797,14 +2813,14 @@ var OwneySDK = class {
3797
2813
  // Casts work around viem's chain-narrowed Client vs the generic
3798
2814
  // PublicClient/WalletClient param types — structurally identical at
3799
2815
  // runtime, but the two share a name TS treats as unrelated.
3800
- getPublicClient: (cid) => createPublicClient4({
2816
+ getPublicClient: (cid) => createPublicClient2({
3801
2817
  chain: VIEM_CHAIN2[cid],
3802
- transport: custom3(provider)
2818
+ transport: custom(provider)
3803
2819
  }),
3804
- getWalletClient: (cid) => createWalletClient3({
2820
+ getWalletClient: (cid) => createWalletClient({
3805
2821
  account: owner,
3806
2822
  chain: VIEM_CHAIN2[cid],
3807
- transport: custom3(provider)
2823
+ transport: custom(provider)
3808
2824
  })
3809
2825
  });
3810
2826
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -3835,10 +2851,12 @@ var OwneySDK = class {
3835
2851
  this.orgAgentConfigPromise = fetchOrgAgentConfig(
3836
2852
  this.apiKey,
3837
2853
  this.routingApiBaseUrl
3838
- ).then((config) => {
3839
- this.orgAgentConfig = config;
3840
- return config;
3841
- });
2854
+ ).then(
2855
+ (config) => {
2856
+ this.orgAgentConfig = config;
2857
+ return config;
2858
+ }
2859
+ );
3842
2860
  }
3843
2861
  return this.orgAgentConfigPromise;
3844
2862
  }
@@ -3878,14 +2896,7 @@ var OwneySDK = class {
3878
2896
  this.routingApiBaseUrl
3879
2897
  );
3880
2898
  this.disabledAgents.clear();
3881
- for (const {
3882
- key: key2,
3883
- agent_type,
3884
- is_enabled,
3885
- is_configured
3886
- } of agentKeys) {
3887
- const configured = is_configured ?? Boolean(key2);
3888
- if (!configured) continue;
2899
+ for (const { key: key2, agent_type, is_enabled } of agentKeys) {
3889
2900
  const agent = this.createAgent(agent_type, key2);
3890
2901
  if (!agent) continue;
3891
2902
  this.agents.set(agent_type, agent);
@@ -3909,47 +2920,10 @@ var OwneySDK = class {
3909
2920
  }
3910
2921
  createAgent(agentId, key2) {
3911
2922
  if (agentId === "zyfai") {
3912
- if (!key2) return null;
3913
2923
  return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
3914
2924
  }
3915
- if (agentId === "yieldseeker") {
3916
- return new YieldseekerAgent(this.apiKey, {
3917
- baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl)
3918
- });
3919
- }
3920
2925
  return null;
3921
2926
  }
3922
- /**
3923
- * Discover the agents actually returned by routing for this organization.
3924
- * Consumers should use this instead of hardcoding a global agent roster.
3925
- */
3926
- async getAvailableAgents(options = {}) {
3927
- await this.ensureAgentsInitialized();
3928
- const { chainId, asset, includeDisabled = false } = options;
3929
- const available = [];
3930
- for (const [id, agent] of this.agents) {
3931
- const isEnabled = !this.isAgentDisabled(id);
3932
- if (!includeDisabled && !isEnabled) continue;
3933
- if (chainId !== void 0 && !agent.supportedChainIds.includes(chainId)) {
3934
- continue;
3935
- }
3936
- if (asset !== void 0) {
3937
- const supportsAsset = agent.supportedAssets.some(
3938
- (entry) => (chainId === void 0 || entry.chainId === chainId) && entry.assets.some((candidate) => candidate.symbol === asset)
3939
- );
3940
- if (!supportsAsset) {
3941
- continue;
3942
- }
3943
- }
3944
- available.push({
3945
- id,
3946
- isEnabled,
3947
- supportedChainIds: agent.supportedChainIds,
3948
- supportedAssets: agent.supportedAssets
3949
- });
3950
- }
3951
- return available;
3952
- }
3953
2927
  // --- Account lifecycle ---
3954
2928
  /**
3955
2929
  * Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted.
@@ -3961,7 +2935,7 @@ var OwneySDK = class {
3961
2935
  * If provided, ALL specified agents must support the chainId or the call
3962
2936
  * throws before activating any agent.
3963
2937
  */
3964
- async activateAgent(chainId, agentId, asset) {
2938
+ async activateAgent(chainId, agentId) {
3965
2939
  const state = this.requireState();
3966
2940
  await this.ensureAgentsInitialized();
3967
2941
  if (agentId !== void 0) {
@@ -3997,7 +2971,9 @@ var OwneySDK = class {
3997
2971
  this.activeAgents.add(id);
3998
2972
  }
3999
2973
  state.chainId = chainId;
4000
- await this.activateAgentsInTurn(agents, state, chainId, asset);
2974
+ this.activateAgentsInTurn(agents, state, chainId).catch((error) => {
2975
+ console.error("activateAgent background init failed:", error);
2976
+ });
4001
2977
  return;
4002
2978
  }
4003
2979
  const compatible = [...this.agents.values()].filter(
@@ -4018,7 +2994,11 @@ var OwneySDK = class {
4018
2994
  const enabledCompatible = compatible.filter(
4019
2995
  (agent) => !this.isAgentDisabled(agent.id)
4020
2996
  );
4021
- await this.activateAgentsInTurn(enabledCompatible, state, chainId, asset);
2997
+ this.activateAgentsInTurn(enabledCompatible, state, chainId).catch(
2998
+ (error) => {
2999
+ console.error("activateAgent background init failed:", error);
3000
+ }
3001
+ );
4022
3002
  }
4023
3003
  /**
4024
3004
  * Activate agents ONE AT A TIME, each followed by its org policy.
@@ -4038,11 +3018,11 @@ var OwneySDK = class {
4038
3018
  * rethrown (matching the previous `Promise.all` rejection) once all agents
4039
3019
  * have had a chance to activate.
4040
3020
  */
4041
- async activateAgentsInTurn(agents, state, chainId, asset) {
3021
+ async activateAgentsInTurn(agents, state, chainId) {
4042
3022
  let firstError = null;
4043
3023
  for (const agent of agents) {
4044
3024
  try {
4045
- await agent.activateAgent(state, chainId, asset);
3025
+ await agent.activateAgent(state, chainId);
4046
3026
  await this.applyOrgPolicyTo(agent, state, chainId);
4047
3027
  } catch (error) {
4048
3028
  if (firstError === null) {
@@ -4251,10 +3231,10 @@ var OwneySDK = class {
4251
3231
  try {
4252
3232
  const balance = await agent.getBalances(state, chainId);
4253
3233
  const target = asset.toLowerCase();
4254
- const token2 = balance.tokens.find(
3234
+ const token = balance.tokens.find(
4255
3235
  (t) => t.chainId === chainId && t.asset.toLowerCase() === target
4256
3236
  );
4257
- return !!token2 && Number(token2.amount) > 0;
3237
+ return !!token && Number(token.amount) > 0;
4258
3238
  } catch {
4259
3239
  return false;
4260
3240
  }
@@ -4305,9 +3285,9 @@ var OwneySDK = class {
4305
3285
  const { asset, amount, agentId } = options;
4306
3286
  const state = this.requireState();
4307
3287
  const chainId = this.requireChainId();
4308
- const token2 = asset;
3288
+ const token = asset;
4309
3289
  const assetInfo = SupportedAssets.find(
4310
- (a) => a.chainId === chainId && a.symbol === token2
3290
+ (a) => a.chainId === chainId && a.symbol === token
4311
3291
  );
4312
3292
  if (!assetInfo) {
4313
3293
  throw new OwneyError(
@@ -4321,7 +3301,7 @@ var OwneySDK = class {
4321
3301
  return withFailureReporting(
4322
3302
  this.apiKey,
4323
3303
  agent.id,
4324
- () => agent.withdraw(state, chainId, token2, amount),
3304
+ () => agent.withdraw(state, chainId, token, amount),
4325
3305
  this.routingApiBaseUrl
4326
3306
  );
4327
3307
  }
@@ -4331,7 +3311,7 @@ var OwneySDK = class {
4331
3311
  const agentErrors2 = {};
4332
3312
  for (const agent of eligibleAgents) {
4333
3313
  try {
4334
- results2[agent.id] = await agent.withdraw(state, chainId, token2);
3314
+ results2[agent.id] = await agent.withdraw(state, chainId, token);
4335
3315
  } catch (err) {
4336
3316
  console.error(`withdraw failed for agent "${agent.id}":`, err);
4337
3317
  agentErrors2[agent.id] = err instanceof Error ? err.message : String(err);
@@ -4358,10 +3338,6 @@ var OwneySDK = class {
4358
3338
  }
4359
3339
  const requested = BigInt(amount);
4360
3340
  const aggregated = await this.getBalances();
4361
- const unavailableAgents = eligibleAgents.filter(
4362
- (agent) => !(agent.id in aggregated.agentBalances)
4363
- );
4364
- const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
4365
3341
  const balances = projectAgentBalancesForAsset(
4366
3342
  eligibleAgents,
4367
3343
  aggregated.agentBalances,
@@ -4370,18 +3346,7 @@ var OwneySDK = class {
4370
3346
  assetInfo.decimals
4371
3347
  );
4372
3348
  const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
4373
- if (totalAvailable === 0n && unavailableAgents.length > 0) {
4374
- throw new OwneyError(
4375
- "WITHDRAW_BALANCE_UNAVAILABLE",
4376
- `Cannot safely plan the withdrawal because balance data is unavailable for: ${unavailableAgentIds.join(", ")}.`,
4377
- {
4378
- asset,
4379
- unavailableAgents: unavailableAgentIds,
4380
- agentErrors: aggregated.agentErrors
4381
- }
4382
- );
4383
- }
4384
- if (totalAvailable < requested && unavailableAgents.length === 0) {
3349
+ if (totalAvailable < requested) {
4385
3350
  throw new OwneyError(
4386
3351
  "WITHDRAW_INSUFFICIENT_BALANCE",
4387
3352
  `Requested withdrawal "${amount}" exceeds available balance "${totalAvailable.toString()}" for asset "${asset}".`,
@@ -4392,7 +3357,6 @@ var OwneySDK = class {
4392
3357
  }
4393
3358
  );
4394
3359
  }
4395
- const plannedTarget = totalAvailable < requested ? totalAvailable : requested;
4396
3360
  const disabledBalances = balances.filter(
4397
3361
  (b) => this.isAgentDisabled(b.agent.id)
4398
3362
  );
@@ -4401,7 +3365,7 @@ var OwneySDK = class {
4401
3365
  );
4402
3366
  const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
4403
3367
  disabledBalances,
4404
- plannedTarget
3368
+ requested
4405
3369
  );
4406
3370
  const enabledTotal = enabledBalances.reduce((s, b) => s + b.balance, 0n);
4407
3371
  const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
@@ -4411,9 +3375,7 @@ var OwneySDK = class {
4411
3375
  }));
4412
3376
  const plans = [...disabledPlans, ...enabledPlans];
4413
3377
  const results = {};
4414
- const agentErrors = {
4415
- ...aggregated.agentErrors ?? {}
4416
- };
3378
+ const agentErrors = {};
4417
3379
  for (let i = 0; i < plans.length; i++) {
4418
3380
  const p = plans[i];
4419
3381
  if (p.planned === 0n) continue;
@@ -4421,7 +3383,7 @@ var OwneySDK = class {
4421
3383
  results[p.agent.id] = await p.agent.withdraw(
4422
3384
  state,
4423
3385
  chainId,
4424
- token2,
3386
+ token,
4425
3387
  p.planned.toString()
4426
3388
  );
4427
3389
  } catch (err) {
@@ -4460,8 +3422,7 @@ var OwneySDK = class {
4460
3422
  requested: amount,
4461
3423
  withdrawn: withdrawn.toString(),
4462
3424
  partialResults: results,
4463
- agentErrors,
4464
- ...unavailableAgentIds.length > 0 ? { unavailableAgents: unavailableAgentIds } : {}
3425
+ agentErrors
4465
3426
  }
4466
3427
  );
4467
3428
  }
@@ -4502,12 +3463,7 @@ var OwneySDK = class {
4502
3463
  continue;
4503
3464
  }
4504
3465
  const reason = settledResult.reason;
4505
- const message = reason instanceof Error ? reason.message : String(reason);
4506
- agentErrors[agentId2] = message;
4507
- console.error(
4508
- `[owney-sdk] Balance fetch failed for agent "${agentId2}":`,
4509
- reason
4510
- );
3466
+ agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
4511
3467
  }
4512
3468
  if (successCount === 0) {
4513
3469
  throw new OwneyError(
@@ -4519,8 +3475,7 @@ var OwneySDK = class {
4519
3475
  return {
4520
3476
  totalBalance: String(totalBalance),
4521
3477
  totalBalanceAsset: "usdc",
4522
- agentBalances: results,
4523
- ...Object.keys(agentErrors).length > 0 ? { agentErrors } : {}
3478
+ agentBalances: results
4524
3479
  };
4525
3480
  }
4526
3481
  /**
@@ -4614,10 +3569,7 @@ var OwneySDK = class {
4614
3569
  Promise.all(
4615
3570
  entries.map(async ([id, agent]) => {
4616
3571
  const b = await agent.getBalances(state, chainId);
4617
- return [
4618
- id,
4619
- balanceForApyScope(b, chainId, tokenSymbol)
4620
- ];
3572
+ return [id, Number(b.totalBalance)];
4621
3573
  })
4622
3574
  )
4623
3575
  ]);
@@ -4645,12 +3597,10 @@ var OwneySDK = class {
4645
3597
  }
4646
3598
  }
4647
3599
  const apyByChainAndAsset = aggregateApyByChainAndAsset(results, balances);
4648
- const history = aggregateApyHistory(results, balances);
4649
3600
  return {
4650
3601
  totalApy: String(totalApy),
4651
3602
  agentApy: results,
4652
- apyByChainAndAsset,
4653
- history
3603
+ apyByChainAndAsset
4654
3604
  };
4655
3605
  }
4656
3606
  /**
@@ -4772,30 +3722,30 @@ var OwneySDK = class {
4772
3722
  const state = this.requireState();
4773
3723
  const chainId = this.requireChainId();
4774
3724
  this.validateAssetSupport(this.getAgent("zyfai"), chainId, "WETH");
4775
- const token2 = SPONSORED_WETH_BY_CHAIN[chainId];
4776
- if (!token2) {
3725
+ const token = SPONSORED_WETH_BY_CHAIN[chainId];
3726
+ if (!token) {
4777
3727
  throw new OwneyError(
4778
3728
  "CHAIN_UNSUPPORTED",
4779
3729
  `No sponsored WETH on chain ${chainId}`
4780
3730
  );
4781
3731
  }
4782
3732
  const provider = this.requireConnectedProvider();
4783
- const wallet = createWalletClient3({
3733
+ const wallet = createWalletClient({
4784
3734
  account: state.walletAddress,
4785
3735
  chain: VIEM_CHAIN2[chainId],
4786
- transport: custom3(provider)
3736
+ transport: custom(provider)
4787
3737
  });
4788
3738
  const hash = await wallet.writeContract({
4789
- address: token2,
3739
+ address: token,
4790
3740
  abi: ERC20_ALLOWANCE_ABI,
4791
3741
  functionName: "approve",
4792
3742
  args: [PERMIT2_ADDRESS, MAX_UINT256],
4793
3743
  account: state.walletAddress,
4794
3744
  chain: VIEM_CHAIN2[chainId]
4795
3745
  });
4796
- const publicClient = createPublicClient4({
3746
+ const publicClient = createPublicClient2({
4797
3747
  chain: VIEM_CHAIN2[chainId],
4798
- transport: custom3(provider)
3748
+ transport: custom(provider)
4799
3749
  });
4800
3750
  const receipt = await publicClient.waitForTransactionReceipt({
4801
3751
  hash,
@@ -4831,9 +3781,7 @@ var OwneySDK = class {
4831
3781
  return this.getAgent(agentId).getAgentApy(days, agentOptions);
4832
3782
  }
4833
3783
  const results = {};
4834
- const agentEntries = [...this.agents.entries()].filter(
4835
- ([id]) => !this.isAgentDisabled(id)
4836
- );
3784
+ const agentEntries = [...this.agents.entries()];
4837
3785
  const apyResults = await Promise.all(
4838
3786
  agentEntries.map(async ([id, agent]) => {
4839
3787
  const apy = await agent.getAgentApy(days, agentOptions);
@@ -4906,13 +3854,13 @@ var OwneySDK = class {
4906
3854
  };
4907
3855
 
4908
3856
  // src/agents/zyfai/zyfai.siwx.ts
4909
- import { getAddress as getAddress3 } from "viem";
4910
- import { SiweMessage as SiweMessage2 } from "siwe";
3857
+ import { getAddress } from "viem";
3858
+ import { SiweMessage } from "siwe";
4911
3859
  import { ZyfaiSDK as ZyfaiSDK2 } from "@zyfai/sdk";
4912
3860
 
4913
3861
  // src/agents/zyfai/zyfai.siwx-cache.ts
4914
- var KEY_PREFIX3 = "owney.siwx.session";
4915
- var storage3 = () => {
3862
+ var KEY_PREFIX2 = "owney.siwx.session";
3863
+ var storage2 = () => {
4916
3864
  if (typeof window === "undefined") return null;
4917
3865
  try {
4918
3866
  return window.localStorage;
@@ -4920,8 +3868,8 @@ var storage3 = () => {
4920
3868
  return null;
4921
3869
  }
4922
3870
  };
4923
- var buildKey3 = (address) => `${KEY_PREFIX3}:${address.toLowerCase()}`;
4924
- var legacyKeyPrefix2 = (address) => `${KEY_PREFIX3}:${address.toLowerCase()}:`;
3871
+ var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
3872
+ var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
4925
3873
  var memorySiwxSessions = /* @__PURE__ */ new Map();
4926
3874
  var readLegacySiwxSession = (store, address) => {
4927
3875
  if (!store) return null;
@@ -4952,8 +3900,8 @@ var readLegacySiwxSession = (store, address) => {
4952
3900
  };
4953
3901
  var readSiwxSession = (address, chainId) => {
4954
3902
  if (typeof window === "undefined") return null;
4955
- const key2 = buildKey3(address);
4956
- const store = storage3();
3903
+ const key2 = buildKey2(address);
3904
+ const store = storage2();
4957
3905
  let raw = null;
4958
3906
  try {
4959
3907
  raw = store?.getItem(key2) ?? null;
@@ -4981,18 +3929,18 @@ var readSiwxSession = (address, chainId) => {
4981
3929
  };
4982
3930
  var writeSiwxSession = (address, _chainId, session) => {
4983
3931
  if (typeof window === "undefined") return;
4984
- const key2 = buildKey3(address);
3932
+ const key2 = buildKey2(address);
4985
3933
  memorySiwxSessions.set(key2, session);
4986
- const store = storage3();
3934
+ const store = storage2();
4987
3935
  try {
4988
3936
  store?.setItem(key2, JSON.stringify(session));
4989
3937
  } catch {
4990
3938
  }
4991
3939
  };
4992
3940
  var clearSiwxSession = (address, _chainId) => {
4993
- const key2 = buildKey3(address);
3941
+ const key2 = buildKey2(address);
4994
3942
  memorySiwxSessions.delete(key2);
4995
- const store = storage3();
3943
+ const store = storage2();
4996
3944
  try {
4997
3945
  store?.removeItem(key2);
4998
3946
  } catch {
@@ -5032,8 +3980,8 @@ function buildSIWXConfig(deps) {
5032
3980
  statement: STATEMENT,
5033
3981
  issuedAt,
5034
3982
  toString() {
5035
- return new SiweMessage2({
5036
- address: getAddress3(accountAddress),
3983
+ return new SiweMessage({
3984
+ address: getAddress(accountAddress),
5037
3985
  chainId: numericChainId(chainId),
5038
3986
  domain,
5039
3987
  uri,
@@ -5075,7 +4023,7 @@ function buildSIWXConfig(deps) {
5075
4023
  const persistSession = async (session) => {
5076
4024
  const address = session.data.accountAddress;
5077
4025
  const id = numericChainId(session.data.chainId);
5078
- const message = new SiweMessage2(session.message);
4026
+ const message = new SiweMessage(session.message);
5079
4027
  const login = await post("/auth/login", {
5080
4028
  message,
5081
4029
  signature: session.signature,
@@ -5123,7 +4071,6 @@ export {
5123
4071
  NotConnectedError,
5124
4072
  OwneyError,
5125
4073
  OwneySDK,
5126
- YieldseekerAgent,
5127
4074
  createOwneySIWX,
5128
4075
  setOwneyDebug
5129
4076
  };