@owney/sdk 0.7.21-beta.3 → 0.7.22-beta.1

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
@@ -1,51 +1,18 @@
1
- // src/errors.ts
2
- var OwneyError = class extends Error {
3
- code;
4
- details;
5
- agentId;
6
- constructor(code, message, details, agentId) {
7
- const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
8
- super(`${prefix} ${message}`);
9
- this.name = "OwneyError";
10
- this.code = code;
11
- this.details = details;
12
- this.agentId = agentId;
13
- }
14
- };
15
- var AgentNotFoundError = class extends OwneyError {
16
- constructor(agentId, available) {
17
- super(
18
- "AGENT_NOT_FOUND",
19
- `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
20
- { agentId, available },
21
- agentId
22
- );
23
- this.name = "AgentNotFoundError";
24
- }
25
- };
26
- var NotConnectedError = class extends OwneyError {
27
- constructor() {
28
- super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
29
- this.name = "NotConnectedError";
30
- }
31
- };
32
- var AgentChainIncompatibleError = class extends OwneyError {
33
- incompatibleAgents;
34
- connectedChainId;
35
- constructor(incompatibleAgents, connectedChainId) {
36
- const details = incompatibleAgents.map(
37
- ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
38
- ).join("; ");
39
- super(
40
- "AGENT_CHAIN_INCOMPATIBLE",
41
- `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
42
- { incompatibleAgents, connectedChainId }
43
- );
44
- this.name = "AgentChainIncompatibleError";
45
- this.incompatibleAgents = incompatibleAgents;
46
- this.connectedChainId = connectedChainId;
47
- }
48
- };
1
+ import {
2
+ AgentChainIncompatibleError,
3
+ AgentNotFoundError,
4
+ NotConnectedError,
5
+ OwneyError,
6
+ debugLog,
7
+ fetchAgentKeys,
8
+ fetchOrgAgentConfig,
9
+ setOwneyDebug
10
+ } from "./chunk-XBDJWZXY.js";
11
+ import {
12
+ buildTransferWithAuthorizationTypedData,
13
+ randomAuthNonce,
14
+ readTokenMeta
15
+ } from "./chunk-AURO3C3R.js";
49
16
 
50
17
  // src/lib/rate-limit.ts
51
18
  function rateLimitDelay(error, now = Date.now()) {
@@ -212,23 +179,6 @@ var SupportedAssets = [
212
179
  }
213
180
  ];
214
181
 
215
- // src/lib/debug.ts
216
- var configuredDebug = false;
217
- function setOwneyDebug(enabled) {
218
- configuredDebug = enabled;
219
- }
220
- function isOwneyDebug() {
221
- return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
222
- }
223
- function debugLog(scope, message, data) {
224
- if (!isOwneyDebug()) return;
225
- if (data === void 0) {
226
- console.log(`[${scope}] ${message}`);
227
- } else {
228
- console.log(`[${scope}] ${message}`, data);
229
- }
230
- }
231
-
232
182
  // src/lib/utils.ts
233
183
  var isValidChainId = (chainId) => {
234
184
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
@@ -240,6 +190,12 @@ var isValidChainId = (chainId) => {
240
190
  }
241
191
  return chainId;
242
192
  };
193
+ function isSameAsset(tokenSymbol, asset) {
194
+ const token = tokenSymbol.toLowerCase();
195
+ const target = asset.toLowerCase();
196
+ if (token === target) return true;
197
+ return target === "weth" && token === "eth" || target === "eth" && token === "weth";
198
+ }
243
199
  function hexToDecimal(hex, decimals = 6) {
244
200
  const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
245
201
  const parsed = BigInt(normalized);
@@ -277,18 +233,18 @@ function tokenDecimals(symbol, explicit) {
277
233
  return explicit;
278
234
  return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
279
235
  }
280
- function mapDeposit(raw2) {
236
+ function mapDeposit(raw) {
281
237
  return {
282
- txHash: raw2.txHash,
283
- smartWallet: raw2.smartWallet,
284
- amount: raw2.amount
238
+ txHash: raw.txHash,
239
+ smartWallet: raw.smartWallet,
240
+ amount: raw.amount
285
241
  };
286
242
  }
287
- function mapWithdraw(raw2) {
243
+ function mapWithdraw(raw) {
288
244
  return {
289
- txHash: raw2.txHash,
290
- type: raw2.type,
291
- amount: raw2.amount
245
+ txHash: raw.txHash,
246
+ type: raw.type,
247
+ amount: raw.amount
292
248
  };
293
249
  }
294
250
  var CHAIN_ID_TO_NAME = {
@@ -307,10 +263,10 @@ function resolveChainId(chain) {
307
263
  if (Number.isFinite(asNum) && asNum > 0) return asNum;
308
264
  return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
309
265
  }
310
- function mapPendingAllocations(raw2) {
311
- if (!Array.isArray(raw2)) return void 0;
266
+ function mapPendingAllocations(raw) {
267
+ if (!Array.isArray(raw)) return void 0;
312
268
  const pending = [];
313
- for (const entry of raw2) {
269
+ for (const entry of raw) {
314
270
  if (typeof entry !== "object" || entry === null) continue;
315
271
  const e = entry;
316
272
  if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
@@ -333,8 +289,8 @@ function mapPendingAllocations(raw2) {
333
289
  }
334
290
  return pending.length > 0 ? pending : void 0;
335
291
  }
336
- function mapBalances(raw2, _chainId, smartWallet) {
337
- const portfolio = raw2.portfolio;
292
+ function mapBalances(raw, _chainId, smartWallet) {
293
+ const portfolio = raw.portfolio;
338
294
  const portfolioByChain = portfolio.portfolioByChain ?? {};
339
295
  let totalBalance = 0;
340
296
  const tokens = [];
@@ -403,8 +359,8 @@ function sumTokenValues(tokens) {
403
359
  function sumTokenEarnings(tokens) {
404
360
  return Object.values(tokens).reduce((sum, val) => sum + Number(val), 0);
405
361
  }
406
- function mapEarnings(raw2, smartWallet) {
407
- const totalEarningsByChain = raw2.data.totalEarningsByChainWithFee ?? raw2.data.totalEarningsByChain ?? {};
362
+ function mapEarnings(raw, smartWallet) {
363
+ const totalEarningsByChain = raw.data.totalEarningsByChainWithFee ?? raw.data.totalEarningsByChain ?? {};
408
364
  const tokens = [];
409
365
  for (const [chainIdKey, tokensBySymbol] of Object.entries(
410
366
  totalEarningsByChain
@@ -423,15 +379,15 @@ function mapEarnings(raw2, smartWallet) {
423
379
  return {
424
380
  smartWallet,
425
381
  lifetimeEarnings: sumTokenEarnings(
426
- raw2.data.totalEarningsByTokenWithFee ?? raw2.data.totalEarningsByToken
382
+ raw.data.totalEarningsByTokenWithFee ?? raw.data.totalEarningsByToken
427
383
  ),
428
384
  tokens
429
385
  };
430
386
  }
431
- function mapWeightedApyByChain(raw2) {
432
- if (!raw2) return void 0;
387
+ function mapWeightedApyByChain(raw) {
388
+ if (!raw) return void 0;
433
389
  const out = {};
434
- for (const [chainKey, tokenApy] of Object.entries(raw2)) {
390
+ for (const [chainKey, tokenApy] of Object.entries(raw)) {
435
391
  const chainId = Number(chainKey);
436
392
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
437
393
  const perAsset = {};
@@ -471,8 +427,8 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
471
427
  }
472
428
  return totalBalance > 0 ? weightedSum / totalBalance : null;
473
429
  }
474
- function mapApyHistory(raw2, chainId, tokenSymbol) {
475
- const history = Object.entries(raw2.history ?? {}).map(([date, entry]) => ({
430
+ function mapApyHistory(raw, chainId, tokenSymbol) {
431
+ const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
476
432
  date,
477
433
  apy: rawPoolApyForChain(entry, chainId, tokenSymbol),
478
434
  // Provider position balances are treated as decimal amounts of the
@@ -488,9 +444,9 @@ function mapApyHistory(raw2, chainId, tokenSymbol) {
488
444
  } : {}
489
445
  })).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
490
446
  return {
491
- walletAddress: raw2.walletAddress,
492
- weightedApyAfterFee: raw2.weightedApyAfterFee ? sumTokenValues(raw2.weightedApyAfterFee) : void 0,
493
- apyByChainAndAsset: mapWeightedApyByChain(raw2.weightedApyAfterFeeByChain),
447
+ walletAddress: raw.walletAddress,
448
+ weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
449
+ apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain),
494
450
  history
495
451
  };
496
452
  }
@@ -586,23 +542,23 @@ function mapEntries(rawEntries, chainId) {
586
542
  };
587
543
  });
588
544
  }
589
- function mapUserProfile(raw2, userAddress) {
545
+ function mapUserProfile(raw, userAddress) {
590
546
  return {
591
547
  address: userAddress,
592
- smartWallet: raw2.smartWallet || "",
593
- chains: raw2.chains || [],
594
- strategy: raw2.strategy,
595
- hasActiveSessionKey: raw2.hasActiveSessionKey || false,
596
- protocols: raw2.protocols || [],
597
- splitting: raw2.splitting,
598
- minSplits: raw2.minSplits
548
+ smartWallet: raw.smartWallet || "",
549
+ chains: raw.chains || [],
550
+ strategy: raw.strategy,
551
+ hasActiveSessionKey: raw.hasActiveSessionKey || false,
552
+ protocols: raw.protocols || [],
553
+ splitting: raw.splitting,
554
+ minSplits: raw.minSplits
599
555
  };
600
556
  }
601
- function mapApyByStrategy(raw2) {
557
+ function mapApyByStrategy(raw) {
602
558
  const apyPerAsset = {};
603
559
  let apySum = 0;
604
560
  let apyCount = 0;
605
- for (const entry of raw2.data) {
561
+ for (const entry of raw.data) {
606
562
  const supported = SupportedAssets.find(
607
563
  (asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
608
564
  );
@@ -773,15 +729,15 @@ var readSession = (address, _chainId) => {
773
729
  if (typeof window === "undefined") return null;
774
730
  const key2 = buildKey(address);
775
731
  const store = storage();
776
- let raw2 = null;
732
+ let raw = null;
777
733
  try {
778
- raw2 = store?.getItem(key2) ?? null;
734
+ raw = store?.getItem(key2) ?? null;
779
735
  } catch {
780
- raw2 = null;
736
+ raw = null;
781
737
  }
782
- if (raw2) {
738
+ if (raw) {
783
739
  try {
784
- const parsed = JSON.parse(raw2);
740
+ const parsed = JSON.parse(raw);
785
741
  if (isFreshSession(parsed)) return parsed;
786
742
  } catch {
787
743
  }
@@ -949,8 +905,8 @@ function buildChainsByProtocol(protocols, dashboardChainIds) {
949
905
  }
950
906
  return result;
951
907
  }
952
- function flattenAvailablePools(raw2) {
953
- const byChain = raw2 ?? {};
908
+ function flattenAvailablePools(raw) {
909
+ const byChain = raw ?? {};
954
910
  const names = [];
955
911
  for (const byToken of Object.values(byChain ?? {})) {
956
912
  for (const entry of Object.values(byToken ?? {})) {
@@ -1453,8 +1409,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
1453
1409
  const poolResults = await Promise.all(
1454
1410
  universe.map(async (protocol) => {
1455
1411
  try {
1456
- const raw2 = await this.sdk.getAvailablePools(protocol.id, strategy);
1457
- return [protocol.id, flattenAvailablePools(raw2)];
1412
+ const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
1413
+ return [protocol.id, flattenAvailablePools(raw)];
1458
1414
  } catch (error) {
1459
1415
  console.warn(
1460
1416
  `[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
@@ -1493,6 +1449,37 @@ var ZyfaiAgent = class _ZyfaiAgent {
1493
1449
  );
1494
1450
  }
1495
1451
  }
1452
+ /**
1453
+ * Records the deposit with Zyfai, retrying transient failures.
1454
+ *
1455
+ * This runs AFTER the transfer has already landed on-chain, so it must never
1456
+ * fail the deposit — the funds moved. But it is also the ONLY source of the
1457
+ * "Top up wallet" entry the history is built from: Zyfai auto-deploys the
1458
+ * balance it detects either way, so when this call is lost the user's deposit
1459
+ * never appears in Activity (an earlier withdrawal stays the newest row) and
1460
+ * nothing ever backfills it. Retry, then log loudly enough to be recoverable.
1461
+ */
1462
+ async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
1463
+ const ATTEMPTS = 3;
1464
+ const RETRY_DELAY_MS = 1e3;
1465
+ for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
1466
+ try {
1467
+ await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
1468
+ return;
1469
+ } catch (logError) {
1470
+ if (attempt === ATTEMPTS) {
1471
+ console.error(
1472
+ "[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
1473
+ { txHash, chainId, amount, tokenAddress, error: logError }
1474
+ );
1475
+ return;
1476
+ }
1477
+ await new Promise(
1478
+ (resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
1479
+ );
1480
+ }
1481
+ }
1482
+ }
1496
1483
  /**
1497
1484
  * True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
1498
1485
  * to this EOA — the "new wallet" kind that is predeployed on the chains it
@@ -1520,14 +1507,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
1520
1507
  async readWalletState(ownerAddress) {
1521
1508
  try {
1522
1509
  const { portfolio } = await this.sdk.getPositions(ownerAddress);
1523
- const raw2 = portfolio;
1510
+ const raw = portfolio;
1524
1511
  debugLog("zyfai:onboard", "wallet state from getPositions", {
1525
- predeployed: raw2?.predeployed,
1526
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1512
+ predeployed: raw?.predeployed,
1513
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1527
1514
  });
1528
1515
  return {
1529
- predeployed: raw2?.predeployed,
1530
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1516
+ predeployed: raw?.predeployed,
1517
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1531
1518
  };
1532
1519
  } catch (error) {
1533
1520
  console.warn(
@@ -1802,25 +1789,23 @@ var ZyfaiAgent = class _ZyfaiAgent {
1802
1789
  );
1803
1790
  const txHash = await depositCallback(smartWallet, validChainId, amount);
1804
1791
  const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
1805
- try {
1806
- await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
1807
- } catch (logError) {
1808
- console.warn(
1809
- "[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
1810
- logError
1811
- );
1812
- }
1792
+ await this.logDepositWithRetry(
1793
+ validChainId,
1794
+ txHash,
1795
+ amount,
1796
+ tokenAddress
1797
+ );
1813
1798
  return { txHash, smartWallet, amount };
1814
1799
  }
1815
1800
  await this.ensureWalletDeployed(this.getAddress(), validChainId);
1816
- const raw2 = await this.sdk.depositFunds(
1801
+ const raw = await this.sdk.depositFunds(
1817
1802
  this.getAddress(),
1818
1803
  validChainId,
1819
1804
  amount,
1820
1805
  asset,
1821
1806
  "aggressive"
1822
1807
  );
1823
- return mapDeposit(raw2);
1808
+ return mapDeposit(raw);
1824
1809
  } catch (error) {
1825
1810
  throw error;
1826
1811
  }
@@ -1829,27 +1814,27 @@ var ZyfaiAgent = class _ZyfaiAgent {
1829
1814
  async withdraw(state, chainId, token, amount) {
1830
1815
  const validChainId = isValidChainId(chainId);
1831
1816
  await this.ensureConnected(state, validChainId);
1832
- const raw2 = await this.sdk.withdrawFunds(
1817
+ const raw = await this.sdk.withdrawFunds(
1833
1818
  this.getAddress(),
1834
1819
  validChainId,
1835
1820
  amount,
1836
1821
  token
1837
1822
  );
1838
- if (!raw2.success) {
1823
+ if (!raw.success) {
1839
1824
  throw new OwneyError(
1840
1825
  "WITHDRAW_FAILED",
1841
- raw2.message || "Zyfai withdraw failed.",
1842
- { chainId: validChainId, token, amount, response: raw2 },
1826
+ raw.message || "Zyfai withdraw failed.",
1827
+ { chainId: validChainId, token, amount, response: raw },
1843
1828
  this.id
1844
1829
  );
1845
1830
  }
1846
- return mapWithdraw(raw2);
1831
+ return mapWithdraw(raw);
1847
1832
  }
1848
1833
  // --- IAgent: Portfolio reads ---
1849
1834
  async getBalances(state, chainId) {
1850
1835
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
1851
- const raw2 = await this.sdk.getPortfolio(this.getAddress());
1852
- return mapBalances(raw2, validChainId, smartWallet);
1836
+ const raw = await this.sdk.getPortfolio(this.getAddress());
1837
+ return mapBalances(raw, validChainId, smartWallet);
1853
1838
  }
1854
1839
  earningsKey(state, chainId, smartWallet) {
1855
1840
  return JSON.stringify([
@@ -1862,11 +1847,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
1862
1847
  const existing = this.earningsReads.get(key2);
1863
1848
  if (existing) return existing;
1864
1849
  const generation = this.earningsGeneration;
1865
- const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw2) => {
1850
+ const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw) => {
1866
1851
  if (generation === this.earningsGeneration) {
1867
- this.earningsSnapshot = { key: key2, raw: raw2, at: Date.now() };
1852
+ this.earningsSnapshot = { key: key2, raw, at: Date.now() };
1868
1853
  }
1869
- return raw2;
1854
+ return raw;
1870
1855
  }).finally(() => {
1871
1856
  if (this.earningsReads.get(key2) === pending)
1872
1857
  this.earningsReads.delete(key2);
@@ -1876,11 +1861,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
1876
1861
  }
1877
1862
  async getEarnings(state, chainId) {
1878
1863
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
1879
- const raw2 = await this.readEarnings(
1864
+ const raw = await this.readEarnings(
1880
1865
  this.earningsKey(state, chainId, smartWallet),
1881
1866
  smartWallet
1882
1867
  );
1883
- return mapEarnings(raw2, smartWallet);
1868
+ return mapEarnings(raw, smartWallet);
1884
1869
  }
1885
1870
  async refreshEarnings(state, chainId) {
1886
1871
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
@@ -1907,8 +1892,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
1907
1892
  }
1908
1893
  async getAccountApy(state, chainId, days, tokenSymbol) {
1909
1894
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
1910
- const raw2 = await this.sdk.getDailyApyHistory(smartWallet, days);
1911
- return mapApyHistory(raw2, chainId, tokenSymbol);
1895
+ const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
1896
+ return mapApyHistory(raw, chainId, tokenSymbol);
1912
1897
  }
1913
1898
  /**
1914
1899
  * Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
@@ -1943,7 +1928,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1943
1928
  const matched = [];
1944
1929
  let backendExhausted = false;
1945
1930
  for (let i = 0; i < MAX_BACKEND_CALLS && matched.length < limit; i++) {
1946
- const raw2 = await this.sdk.getHistory(smartWallet, validChainId, {
1931
+ const raw = await this.sdk.getHistory(smartWallet, validChainId, {
1947
1932
  limit: backendPageSize,
1948
1933
  offset,
1949
1934
  fromDate: options?.fromDate,
@@ -1954,13 +1939,13 @@ var ZyfaiAgent = class _ZyfaiAgent {
1954
1939
  // asset's rows and handing back a page that filters to nothing.
1955
1940
  assetType
1956
1941
  });
1957
- raw2.data.forEach((entry, idx) => {
1942
+ raw.data.forEach((entry, idx) => {
1958
1943
  if (entry.chainId === validChainId) {
1959
1944
  matched.push({ entry, rawIdx: offset + idx });
1960
1945
  }
1961
1946
  });
1962
- offset += raw2.data.length;
1963
- if (raw2.data.length < backendPageSize) {
1947
+ offset += raw.data.length;
1948
+ if (raw.data.length < backendPageSize) {
1964
1949
  backendExhausted = true;
1965
1950
  break;
1966
1951
  }
@@ -1982,18 +1967,18 @@ var ZyfaiAgent = class _ZyfaiAgent {
1982
1967
  }
1983
1968
  async getUserProfile(state, chainId) {
1984
1969
  await this.connectAuth(state, chainId);
1985
- const raw2 = await this.sdk.getUserDetails();
1970
+ const raw = await this.sdk.getUserDetails();
1986
1971
  debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
1987
1972
  asset: "USDC (default \u2014 no asset passed)",
1988
- splitting: raw2.splitting,
1989
- minSplits: raw2.minSplits,
1990
- strategy: raw2.strategy,
1991
- chains: raw2.chains,
1992
- protocolCount: raw2.protocols?.length,
1993
- hasActiveSessionKey: raw2.hasActiveSessionKey,
1994
- smartWallet: raw2.smartWallet
1973
+ splitting: raw.splitting,
1974
+ minSplits: raw.minSplits,
1975
+ strategy: raw.strategy,
1976
+ chains: raw.chains,
1977
+ protocolCount: raw.protocols?.length,
1978
+ hasActiveSessionKey: raw.hasActiveSessionKey,
1979
+ smartWallet: raw.smartWallet
1995
1980
  });
1996
- return mapUserProfile(raw2, this.connectedAddress);
1981
+ return mapUserProfile(raw, this.connectedAddress);
1997
1982
  }
1998
1983
  async ensureAutoSelectProtocols(state, chainId, asset) {
1999
1984
  await this.connectAuth(state, chainId);
@@ -2012,210 +1997,282 @@ var ZyfaiAgent = class _ZyfaiAgent {
2012
1997
  }
2013
1998
  // --- IAgent: Discovery (no wallet required) ---
2014
1999
  async getAgentApy(days, options) {
2015
- const raw2 = await this.sdk.getAPYPerStrategy(
2000
+ const raw = await this.sdk.getAPYPerStrategy(
2016
2001
  false,
2017
2002
  DayFilterMapping[days],
2018
2003
  "aggressive",
2019
2004
  options?.chainId,
2020
2005
  options?.tokenSymbol
2021
2006
  );
2022
- return mapApyByStrategy(raw2);
2007
+ return mapApyByStrategy(raw);
2023
2008
  }
2024
2009
  };
2025
2010
 
2026
- // src/agents/yieldseeker/yieldseeker.agent.ts
2027
- import {
2028
- createPublicClient as createPublicClient3,
2029
- createWalletClient as createWalletClient2,
2030
- custom as custom2,
2031
- encodeFunctionData,
2032
- erc20Abi,
2033
- getAddress as getAddress2,
2034
- isAddress as isAddress2
2035
- } from "viem";
2036
- import { base as base3 } from "viem/chains";
2037
-
2038
- // src/lib/chain-guard.ts
2039
- var CHAIN_NAMES = {
2040
- 1: "Ethereum",
2041
- 8453: "Base",
2042
- 42161: "Arbitrum"
2043
- };
2044
- function chainName(chainId) {
2045
- return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
2046
- }
2047
- async function ensureWalletOnChain(pub, wallet, expected) {
2048
- const actual = await pub.getChainId();
2049
- if (actual === expected) return;
2050
- try {
2051
- await wallet.switchChain({ id: expected });
2052
- } catch (error) {
2053
- throw new OwneyError(
2054
- "CHAIN_MISMATCH",
2055
- `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2056
- {
2057
- expectedChainId: expected,
2058
- actualChainId: actual,
2059
- cause: error instanceof Error ? error.message : String(error)
2060
- }
2061
- );
2062
- }
2063
- const after = await pub.getChainId();
2064
- if (after !== expected) {
2065
- throw new OwneyError(
2066
- "CHAIN_MISMATCH",
2067
- `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2068
- { expectedChainId: expected, actualChainId: after }
2069
- );
2070
- }
2071
- }
2072
-
2073
- // src/lib/transfer-auth.ts
2074
- import { bytesToHex } from "viem";
2075
- var ERC20_META_ABI = [
2076
- { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
2077
- { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
2078
- ];
2079
- function buildTransferWithAuthorizationTypedData(input) {
2080
- return {
2081
- domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
2082
- types: {
2083
- TransferWithAuthorization: [
2084
- { name: "from", type: "address" },
2085
- { name: "to", type: "address" },
2086
- { name: "value", type: "uint256" },
2087
- { name: "validAfter", type: "uint256" },
2088
- { name: "validBefore", type: "uint256" },
2089
- { name: "nonce", type: "bytes32" }
2090
- ]
2091
- },
2092
- primaryType: "TransferWithAuthorization",
2093
- message: input.message
2094
- };
2095
- }
2096
- async function readTokenMeta(publicClient, token) {
2097
- const [tokenName, tokenVersion] = await Promise.all([
2098
- publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
2099
- publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
2100
- ]);
2101
- return { tokenName, tokenVersion };
2102
- }
2103
- function randomAuthNonce() {
2104
- const bytes = new Uint8Array(32);
2105
- globalThis.crypto.getRandomValues(bytes);
2106
- return bytesToHex(bytes);
2107
- }
2108
-
2109
- // src/lib/sponsor-client.ts
2011
+ // src/lib/health-report.ts
2110
2012
  var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2111
- async function postPaymasterIntent(input) {
2112
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2113
- let res;
2013
+ async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL) {
2114
2014
  try {
2115
- res = await fetch(`${base5}/api/v1/sponsor/paymaster-intent`, {
2015
+ await fetch(`${baseUrl}/api/v1/agent/health-report`, {
2116
2016
  method: "POST",
2117
2017
  headers: {
2118
- "content-type": "application/json",
2119
- "x-owney-api-key": input.apiKey,
2120
- Authorization: `Signature ${input.yieldseekerSignature}`
2018
+ "Content-Type": "application/json",
2019
+ "x-owney-api-key": apiKey
2121
2020
  },
2122
- body: JSON.stringify(input.body)
2021
+ body: JSON.stringify({
2022
+ agent_type: agentType,
2023
+ error_code: errorCode,
2024
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2025
+ })
2123
2026
  });
2124
- } catch (networkError) {
2125
- throw new OwneyError(
2126
- "SPONSOR_REQUEST_FAILED",
2127
- `Paymaster intent network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2128
- { cause: String(networkError), safeToFallback: true }
2027
+ } catch (err) {
2028
+ console.warn(
2029
+ `[owney-sdk] health-report failed for agent "${agentType}":`,
2030
+ err instanceof Error ? err.message : err
2129
2031
  );
2130
2032
  }
2131
- const text = await res.text();
2132
- let parsed = null;
2033
+ }
2034
+ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
2133
2035
  try {
2134
- parsed = JSON.parse(text);
2135
- } catch {
2136
- }
2137
- if (!res.ok || !parsed?.success || typeof parsed.data?.intent !== "string" || typeof parsed.data.expiresAt !== "number") {
2138
- throw new OwneyError(
2139
- "SPONSOR_REQUEST_FAILED",
2140
- `Paymaster intent API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2141
- {
2142
- statusCode: res.status,
2143
- responseBody: text.slice(0, 500),
2144
- safeToFallback: true
2145
- }
2146
- );
2036
+ return await fn();
2037
+ } catch (err) {
2038
+ const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
2039
+ void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
2040
+ throw err;
2147
2041
  }
2148
- return parsed.data;
2149
2042
  }
2150
- async function postSponsorTransferAuth(input) {
2151
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2152
- let res;
2153
- try {
2154
- res = await fetch(`${base5}/api/v1/sponsor/erc20-transfer-auth`, {
2155
- method: "POST",
2156
- headers: {
2157
- "content-type": "application/json",
2158
- "x-owney-api-key": input.apiKey,
2159
- ...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
2160
- },
2161
- body: JSON.stringify(input.body)
2162
- });
2163
- } catch (networkError) {
2164
- throw new OwneyError(
2165
- "SPONSOR_REQUEST_FAILED",
2166
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2167
- { cause: String(networkError) }
2043
+
2044
+ // src/lib/helpers/withdraw-helper.ts
2045
+ import { parseUnits } from "viem";
2046
+ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
2047
+ return agents.map((agent) => {
2048
+ const agentBalance = aggregated[agent.id];
2049
+ const tokenBalance = agentBalance?.tokens.find(
2050
+ (t) => t.chainId === chainId && isSameAsset(t.asset, asset)
2168
2051
  );
2052
+ if (!tokenBalance) return { agent, balance: 0n };
2053
+ return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
2054
+ });
2055
+ }
2056
+ function planProportionalShares(balances, requested, totalAvailable) {
2057
+ const plans = balances.map(({ agent, balance }) => ({
2058
+ agent,
2059
+ balance,
2060
+ planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
2061
+ }));
2062
+ const assigned = plans.reduce((s, p) => s + p.planned, 0n);
2063
+ let remainder = requested - assigned;
2064
+ const byHeadroom = [...plans].sort((a, b) => {
2065
+ const diff = b.balance - b.planned - (a.balance - a.planned);
2066
+ return diff > 0n ? 1 : diff < 0n ? -1 : 0;
2067
+ });
2068
+ for (const p of byHeadroom) {
2069
+ if (remainder === 0n) break;
2070
+ const headroom = p.balance - p.planned;
2071
+ if (headroom <= 0n) continue;
2072
+ const take = headroom < remainder ? headroom : remainder;
2073
+ p.planned += take;
2074
+ remainder -= take;
2169
2075
  }
2170
- const text = await res.text();
2171
- let parsed = null;
2172
- try {
2173
- parsed = JSON.parse(text);
2174
- } catch {
2175
- }
2176
- if (!res.ok || !parsed?.success || !parsed.data) {
2177
- throw new OwneyError(
2178
- "SPONSOR_REQUEST_FAILED",
2179
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2180
- {
2181
- statusCode: res.status,
2182
- responseBody: text.slice(0, 500),
2183
- // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2184
- // before broadcast, so it is safe to fall back to a user-paid deposit.
2185
- safeToFallback: res.status === 503
2186
- }
2187
- );
2076
+ return plans;
2077
+ }
2078
+ function planDisabledDrain(disabled, requested) {
2079
+ const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
2080
+ const plans = [];
2081
+ let remaining = requested;
2082
+ for (const { agent, balance } of sorted) {
2083
+ if (remaining === 0n) {
2084
+ plans.push({ agent, balance, planned: 0n });
2085
+ continue;
2086
+ }
2087
+ const take = balance < remaining ? balance : remaining;
2088
+ plans.push({ agent, balance, planned: take });
2089
+ remaining -= take;
2188
2090
  }
2189
- return parsed.data;
2091
+ return { plans, remaining };
2190
2092
  }
2191
- async function postSponsorPermit2Transfer(input) {
2192
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2193
- let res;
2194
- try {
2195
- res = await fetch(`${base5}/api/v1/sponsor/permit2-transfer`, {
2196
- method: "POST",
2197
- headers: {
2198
- "content-type": "application/json",
2199
- "x-owney-api-key": input.apiKey,
2200
- ...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
2201
- },
2202
- body: JSON.stringify(input.body)
2203
- });
2204
- } catch (networkError) {
2205
- throw new OwneyError(
2206
- "SPONSOR_REQUEST_FAILED",
2207
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2208
- { cause: String(networkError), safeToFallback: false }
2209
- );
2093
+ function redistributeShare(plans, fromIndex, amount, candidatePool) {
2094
+ const pool = candidatePool ?? plans.slice(fromIndex + 1);
2095
+ const candidates = pool.filter((c) => c.balance - c.planned > 0n);
2096
+ const totalHeadroom = candidates.reduce(
2097
+ (s, c) => s + (c.balance - c.planned),
2098
+ 0n
2099
+ );
2100
+ if (totalHeadroom === 0n) return;
2101
+ let distributed = 0n;
2102
+ for (const c of candidates) {
2103
+ const headroom = c.balance - c.planned;
2104
+ const proportional = headroom * amount / totalHeadroom;
2105
+ const give = proportional > headroom ? headroom : proportional;
2106
+ c.planned += give;
2107
+ distributed += give;
2210
2108
  }
2211
- const text = await res.text();
2212
- let parsed = null;
2213
- try {
2214
- parsed = JSON.parse(text);
2215
- } catch {
2109
+ let leftover = amount - distributed;
2110
+ for (const c of candidates) {
2111
+ if (leftover === 0n) break;
2112
+ const headroom = c.balance - c.planned;
2113
+ if (headroom <= 0n) continue;
2114
+ const take = headroom < leftover ? headroom : leftover;
2115
+ c.planned += take;
2116
+ leftover -= take;
2216
2117
  }
2217
- if (!res.ok || !parsed?.success || !parsed.data) {
2218
- throw new OwneyError(
2118
+ }
2119
+ function sumWithdrawnAmount(results) {
2120
+ return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
2121
+ }
2122
+
2123
+ // src/lib/helpers/account-apy-helper.ts
2124
+ function balanceForApyScope(balance, chainId, tokenSymbol) {
2125
+ if (!tokenSymbol) {
2126
+ const total = Number(balance.totalBalance);
2127
+ return Number.isFinite(total) && total > 0 ? total : 0;
2128
+ }
2129
+ const normalizedToken = tokenSymbol.toUpperCase();
2130
+ return balance.tokens.reduce((total, token) => {
2131
+ if (Number(token.chainId) !== chainId || String(token.asset).toUpperCase() !== normalizedToken) {
2132
+ return total;
2133
+ }
2134
+ const amount = Number(token.amount);
2135
+ return Number.isFinite(amount) && amount > 0 ? total + amount : total;
2136
+ }, 0);
2137
+ }
2138
+ function aggregateApyHistory(agentApys) {
2139
+ const byDate = /* @__PURE__ */ new Map();
2140
+ for (const accountApy of Object.values(agentApys)) {
2141
+ const seen = /* @__PURE__ */ new Set();
2142
+ for (const point of accountApy.history ?? []) {
2143
+ if (!point.date || seen.has(point.date) || !Number.isFinite(point.apy)) continue;
2144
+ seen.add(point.date);
2145
+ const points = byDate.get(point.date) ?? [];
2146
+ points.push(point);
2147
+ byDate.set(point.date, points);
2148
+ }
2149
+ }
2150
+ return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).flatMap(([date, points]) => {
2151
+ if (points.length === 1 && !points[0].historicalBalance) {
2152
+ return [{ date, apy: points[0].apy }];
2153
+ }
2154
+ const unit = points[0].historicalBalance?.unit;
2155
+ if (!unit || points.some(
2156
+ ({ historicalBalance: balance }) => !balance || balance.unit !== unit || !Number.isFinite(balance.amount) || balance.amount < 0
2157
+ )) return [];
2158
+ const total = points.reduce((sum, p) => sum + p.historicalBalance.amount, 0);
2159
+ if (total <= 0 || !Number.isFinite(total)) return [];
2160
+ const apy = points.reduce((sum, p) => sum + p.apy * (p.historicalBalance.amount / total), 0);
2161
+ return Number.isFinite(apy) ? [{ date, apy }] : [];
2162
+ });
2163
+ }
2164
+ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
2165
+ const sums = {};
2166
+ const weights = {};
2167
+ for (const id of Object.keys(agentApys)) {
2168
+ const cells = agentApys[id].apyByChainAndAsset;
2169
+ const balance = agentBalances[id] ?? 0;
2170
+ if (!cells || balance <= 0) continue;
2171
+ for (const [chainKey, perAsset] of Object.entries(cells)) {
2172
+ if (!perAsset) continue;
2173
+ const chainId = Number(chainKey);
2174
+ for (const [asset, apyValue] of Object.entries(perAsset)) {
2175
+ const apy = Number(apyValue ?? 0);
2176
+ if (apy === 0) continue;
2177
+ sums[chainId] ??= {};
2178
+ weights[chainId] ??= {};
2179
+ sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
2180
+ weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2181
+ }
2182
+ }
2183
+ }
2184
+ const out = {};
2185
+ for (const chainKey of Object.keys(sums)) {
2186
+ const chainId = Number(chainKey);
2187
+ const perAssetOut = {};
2188
+ for (const asset of Object.keys(sums[chainId])) {
2189
+ const w = weights[chainId][asset];
2190
+ if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
2191
+ }
2192
+ if (Object.keys(perAssetOut).length > 0) {
2193
+ out[chainId] = perAssetOut;
2194
+ }
2195
+ }
2196
+ return out;
2197
+ }
2198
+
2199
+ // src/client.ts
2200
+ import {
2201
+ createPublicClient as createPublicClient2,
2202
+ createWalletClient,
2203
+ custom
2204
+ } from "viem";
2205
+ import { base as base2, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
2206
+
2207
+ // src/lib/sponsor-client.ts
2208
+ var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2209
+ async function postSponsorTransferAuth(input) {
2210
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL2;
2211
+ let res;
2212
+ try {
2213
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2214
+ method: "POST",
2215
+ headers: {
2216
+ "content-type": "application/json",
2217
+ "x-owney-api-key": input.apiKey
2218
+ },
2219
+ body: JSON.stringify(input.body)
2220
+ });
2221
+ } catch (networkError) {
2222
+ throw new OwneyError(
2223
+ "SPONSOR_REQUEST_FAILED",
2224
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2225
+ { cause: String(networkError) }
2226
+ );
2227
+ }
2228
+ const text = await res.text();
2229
+ let parsed = null;
2230
+ try {
2231
+ parsed = JSON.parse(text);
2232
+ } catch {
2233
+ }
2234
+ if (!res.ok || !parsed?.success || !parsed.data) {
2235
+ throw new OwneyError(
2236
+ "SPONSOR_REQUEST_FAILED",
2237
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2238
+ {
2239
+ statusCode: res.status,
2240
+ responseBody: text.slice(0, 500),
2241
+ // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2242
+ // before broadcast, so it is safe to fall back to a user-paid deposit.
2243
+ safeToFallback: res.status === 503
2244
+ }
2245
+ );
2246
+ }
2247
+ return parsed.data;
2248
+ }
2249
+ async function postSponsorPermit2Transfer(input) {
2250
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL2;
2251
+ let res;
2252
+ try {
2253
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2254
+ method: "POST",
2255
+ headers: {
2256
+ "content-type": "application/json",
2257
+ "x-owney-api-key": input.apiKey
2258
+ },
2259
+ body: JSON.stringify(input.body)
2260
+ });
2261
+ } catch (networkError) {
2262
+ throw new OwneyError(
2263
+ "SPONSOR_REQUEST_FAILED",
2264
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2265
+ { cause: String(networkError), safeToFallback: false }
2266
+ );
2267
+ }
2268
+ const text = await res.text();
2269
+ let parsed = null;
2270
+ try {
2271
+ parsed = JSON.parse(text);
2272
+ } catch {
2273
+ }
2274
+ if (!res.ok || !parsed?.success || !parsed.data) {
2275
+ throw new OwneyError(
2219
2276
  "SPONSOR_REQUEST_FAILED",
2220
2277
  `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2221
2278
  {
@@ -2228,11 +2285,11 @@ async function postSponsorPermit2Transfer(input) {
2228
2285
  return parsed.data;
2229
2286
  }
2230
2287
  async function getSponsorRelayerAddress(input) {
2231
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2288
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL2;
2232
2289
  let res;
2233
2290
  try {
2234
2291
  res = await fetch(
2235
- `${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2292
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2236
2293
  {
2237
2294
  headers: { "x-owney-api-key": input.apiKey }
2238
2295
  }
@@ -2265,7 +2322,7 @@ async function getSponsorRelayerAddress(input) {
2265
2322
  }
2266
2323
 
2267
2324
  // src/lib/permit2.ts
2268
- import { bytesToHex as bytesToHex2 } from "viem";
2325
+ import { bytesToHex } from "viem";
2269
2326
  var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2270
2327
  var MAX_UINT256 = 2n ** 256n - 1n;
2271
2328
  var ERC20_ALLOWANCE_ABI = [
@@ -2323,2090 +2380,223 @@ function buildPermitTransferFromTypedData(input) {
2323
2380
  function randomPermit2Nonce() {
2324
2381
  const bytes = new Uint8Array(32);
2325
2382
  globalThis.crypto.getRandomValues(bytes);
2326
- return BigInt(bytesToHex2(bytes));
2383
+ return BigInt(bytesToHex(bytes));
2327
2384
  }
2328
2385
  async function readPermit2Allowance(publicClient, token, owner) {
2329
- return publicClient.readContract({
2330
- address: token,
2331
- abi: ERC20_ALLOWANCE_ABI,
2332
- functionName: "allowance",
2333
- args: [owner, PERMIT2_ADDRESS]
2334
- });
2335
- }
2336
- async function readErc20Balance(publicClient, token, owner) {
2337
- return publicClient.readContract({
2338
- address: token,
2339
- abi: ERC20_ALLOWANCE_ABI,
2340
- functionName: "balanceOf",
2341
- args: [owner]
2342
- });
2343
- }
2344
-
2345
- // src/lib/sponsored-deposit.ts
2346
- var AUTH_WINDOW_SECONDS = 15 * 60;
2347
- var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
2348
- function provideDepositVerificationContext(callback, context) {
2349
- callback[verificationSetter]?.(context);
2350
- }
2351
- function makeVerificationAwareDepositCallback(implementation) {
2352
- let nextVerification;
2353
- const callback = async (smartWallet, chainId, amount) => {
2354
- const verification = nextVerification;
2355
- nextVerification = void 0;
2356
- return implementation(smartWallet, chainId, amount, verification);
2357
- };
2358
- Object.defineProperty(callback, verificationSetter, {
2359
- value: (context) => {
2360
- nextVerification = context;
2361
- }
2362
- });
2363
- return callback;
2364
- }
2365
- function makeSponsoredDepositCallback(deps) {
2366
- const post = deps.httpPost ?? postSponsorTransferAuth;
2367
- return makeVerificationAwareDepositCallback(
2368
- async (smartWallet, chainId, amount, verification) => {
2369
- const cid = chainId;
2370
- const token = deps.tokenAddressByChain[cid];
2371
- if (!token) {
2372
- throw new OwneyError(
2373
- "CHAIN_UNSUPPORTED",
2374
- `No sponsored token configured for chain ${chainId}`
2375
- );
2376
- }
2377
- const pub = deps.getPublicClient(cid);
2378
- const wallet = deps.getWalletClient(cid);
2379
- await ensureWalletOnChain(pub, wallet, cid);
2380
- try {
2381
- const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2382
- if (balance < BigInt(amount)) {
2383
- throw new OwneyError(
2384
- "DEPOSIT_INSUFFICIENT_BALANCE",
2385
- "Insufficient balance for this deposit.",
2386
- { token, chainId: cid, balance: balance.toString(), amount }
2387
- );
2388
- }
2389
- } catch (err) {
2390
- if (err instanceof OwneyError) throw err;
2391
- console.warn(
2392
- "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2393
- err instanceof Error ? err.message : String(err)
2394
- );
2395
- }
2396
- const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2397
- const validAfter = 0n;
2398
- const validBefore = BigInt(
2399
- Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2400
- );
2401
- const nonce = randomAuthNonce();
2402
- const typedData = buildTransferWithAuthorizationTypedData({
2403
- token,
2404
- chainId: cid,
2405
- tokenName,
2406
- tokenVersion,
2407
- message: {
2408
- from: deps.ownerAddress,
2409
- to: smartWallet,
2410
- value: BigInt(amount),
2411
- validAfter,
2412
- validBefore,
2413
- nonce
2414
- }
2415
- });
2416
- const authSignature = await wallet.signTypedData({
2417
- account: deps.ownerAddress,
2418
- ...typedData
2419
- });
2420
- deps.onApproved?.();
2421
- const result = await post({
2422
- baseUrl: deps.baseUrl,
2423
- apiKey: deps.apiKey,
2424
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
2425
- body: {
2426
- chainId: cid,
2427
- token,
2428
- from: deps.ownerAddress,
2429
- to: smartWallet,
2430
- value: amount,
2431
- validAfter: validAfter.toString(),
2432
- validBefore: validBefore.toString(),
2433
- nonce,
2434
- authSignature,
2435
- tokenName,
2436
- tokenVersion,
2437
- ...verification?.agentId === "yieldseeker" ? {
2438
- yieldseekerUserId: verification.userId,
2439
- yieldseekerAgentId: verification.yieldseekerAgentId
2440
- } : {}
2441
- }
2442
- });
2443
- return result.txHash;
2444
- }
2445
- );
2446
- }
2447
-
2448
- // src/agents/yieldseeker/yieldseeker.auth.ts
2449
- import { SiweMessage, generateNonce } from "siwe";
2450
- import {
2451
- createPublicClient as createPublicClient2,
2452
- createWalletClient,
2453
- custom,
2454
- getAddress
2455
- } from "viem";
2456
- import { base as base2 } from "viem/chains";
2457
-
2458
- // src/agents/yieldseeker/yieldseeker.auth-cache.ts
2459
- var KEY_PREFIX2 = "owney.yieldseeker.session.v5";
2460
- var INVALIDATED_KEY_PREFIXES = [
2461
- "owney.yieldseeker.session",
2462
- "owney.yieldseeker.session.v3",
2463
- "owney.yieldseeker.session.v4"
2464
- ];
2465
- var storage2 = () => {
2466
- if (typeof window === "undefined") return null;
2467
- try {
2468
- return window.localStorage;
2469
- } catch {
2470
- return null;
2471
- }
2472
- };
2473
- var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2474
- var invalidatedKeys = (address, chainId) => INVALIDATED_KEY_PREFIXES.map(
2475
- (prefix) => `${prefix}:${address.toLowerCase()}:${chainId}`
2476
- );
2477
- var clearInvalidatedSessions = (store, address, chainId) => {
2478
- for (const key2 of invalidatedKeys(address, chainId)) {
2479
- memorySessions2.delete(key2);
2480
- try {
2481
- store?.removeItem(key2);
2482
- } catch {
2483
- }
2484
- }
2485
- };
2486
- var memorySessions2 = /* @__PURE__ */ new Map();
2487
- var isValidSession = (session) => {
2488
- if (!session?.token) return false;
2489
- try {
2490
- const parsed = JSON.parse(atob(session.token));
2491
- return typeof parsed.message === "string" && typeof parsed.signature === "string" && parsed.signature.startsWith("0x");
2492
- } catch {
2493
- return false;
2494
- }
2495
- };
2496
- var readYieldseekerSession = (address, chainId) => {
2497
- if (typeof window === "undefined") return null;
2498
- const key2 = buildKey2(address, chainId);
2499
- const store = storage2();
2500
- clearInvalidatedSessions(store, address, chainId);
2501
- let raw2 = null;
2502
- try {
2503
- raw2 = store?.getItem(key2) ?? null;
2504
- } catch {
2505
- raw2 = null;
2506
- }
2507
- if (raw2) {
2508
- try {
2509
- const parsed = JSON.parse(raw2);
2510
- if (isValidSession(parsed)) return parsed.token;
2511
- } catch {
2512
- }
2513
- memorySessions2.delete(key2);
2514
- try {
2515
- store?.removeItem(key2);
2516
- } catch {
2517
- }
2518
- return null;
2519
- }
2520
- const cached = memorySessions2.get(key2);
2521
- if (isValidSession(cached)) return cached.token;
2522
- if (cached) memorySessions2.delete(key2);
2523
- return null;
2524
- };
2525
- var writeYieldseekerSession = (address, chainId, token) => {
2526
- if (typeof window === "undefined") return;
2527
- const session = { token };
2528
- if (!isValidSession(session)) return;
2529
- const key2 = buildKey2(address, chainId);
2530
- memorySessions2.set(key2, session);
2531
- const store = storage2();
2532
- try {
2533
- store?.setItem(key2, JSON.stringify(session));
2534
- } catch {
2535
- }
2536
- };
2537
- var clearYieldseekerSession = (address, chainId) => {
2538
- const key2 = buildKey2(address, chainId);
2539
- memorySessions2.delete(key2);
2540
- const store = storage2();
2541
- clearInvalidatedSessions(store, address, chainId);
2542
- try {
2543
- store?.removeItem(key2);
2544
- } catch {
2545
- }
2546
- };
2547
-
2548
- // src/agents/yieldseeker/yieldseeker.auth.ts
2549
- function resolveSiweOrigin(override) {
2550
- const origin = override?.trim() || (typeof window !== "undefined" ? window.location?.origin : void 0);
2551
- if (!origin || origin === "null") {
2552
- throw new Error("Yieldseeker sign-in requires the requesting app's browser origin.");
2553
- }
2554
- const url = new URL(origin);
2555
- if (url.protocol !== "https:" && url.protocol !== "http:") {
2556
- throw new Error("Yieldseeker sign-in requires an HTTP or HTTPS app origin.");
2557
- }
2558
- if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
2559
- throw new Error("Yieldseeker SIWE override must be an origin without credentials, path, query, or fragment.");
2560
- }
2561
- return url;
2562
- }
2563
- function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
2564
- const url = resolveSiweOrigin(dependencies.origin);
2565
- return new SiweMessage({
2566
- scheme: url.protocol.slice(0, -1),
2567
- domain: url.host,
2568
- address: getAddress(address),
2569
- uri: url.origin,
2570
- version: "1",
2571
- chainId,
2572
- nonce: (dependencies.nonce ?? generateNonce)(),
2573
- issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
2574
- }).prepareMessage();
2575
- }
2576
- function encodeYieldseekerAuthToken(token) {
2577
- const bytes = new TextEncoder().encode(JSON.stringify(token));
2578
- let binary = "";
2579
- for (const byte of bytes) binary += String.fromCharCode(byte);
2580
- return btoa(binary);
2581
- }
2582
- var YieldseekerAuth = class {
2583
- constructor(dependencies = {}) {
2584
- this.dependencies = dependencies;
2585
- }
2586
- dependencies;
2587
- tokens = /* @__PURE__ */ new Map();
2588
- pending = /* @__PURE__ */ new Map();
2589
- scopes = /* @__PURE__ */ new Map();
2590
- key(state, chainId) {
2591
- return `${state.walletAddress.toLowerCase()}:${chainId}:${resolveSiweOrigin(this.dependencies.origin).origin}`;
2592
- }
2593
- async getToken(state, chainId) {
2594
- const key2 = this.key(state, chainId);
2595
- const scope = { address: state.walletAddress, chainId };
2596
- this.scopes.set(key2, scope);
2597
- const cached = this.tokens.get(key2);
2598
- if (cached) return cached;
2599
- const persisted = readYieldseekerSession(scope.address, scope.chainId);
2600
- if (persisted && this.matchesOrigin(persisted)) {
2601
- this.tokens.set(key2, persisted);
2602
- return persisted;
2603
- }
2604
- if (persisted) clearYieldseekerSession(scope.address, scope.chainId);
2605
- const inFlight = this.pending.get(key2);
2606
- if (inFlight) return inFlight;
2607
- const request = this.sign(state, chainId).then((token) => {
2608
- if (this.pending.get(key2) !== request) throw new Error("Wallet sign-in session changed. Please try again.");
2609
- this.tokens.set(key2, token);
2610
- writeYieldseekerSession(scope.address, scope.chainId, token);
2611
- return token;
2612
- });
2613
- this.pending.set(key2, request);
2614
- try {
2615
- return await request;
2616
- } finally {
2617
- if (this.pending.get(key2) === request) this.pending.delete(key2);
2618
- }
2619
- }
2620
- async refreshToken(state, chainId, rejectedToken) {
2621
- const key2 = this.key(state, chainId);
2622
- if (this.tokens.get(key2) === rejectedToken) {
2623
- this.tokens.delete(key2);
2624
- clearYieldseekerSession(state.walletAddress, chainId);
2625
- }
2626
- return this.getToken(state, chainId);
2627
- }
2628
- matchesOrigin(token) {
2629
- try {
2630
- const message = new SiweMessage(JSON.parse(atob(token)).message);
2631
- const url = resolveSiweOrigin(this.dependencies.origin);
2632
- return message.domain === url.host && message.uri === url.origin && message.scheme === url.protocol.slice(0, -1);
2633
- } catch {
2634
- return false;
2635
- }
2636
- }
2637
- clear(state, chainId) {
2638
- if (!state || chainId === void 0) {
2639
- for (const scope of this.scopes.values()) {
2640
- clearYieldseekerSession(scope.address, scope.chainId);
2641
- }
2642
- this.tokens.clear();
2643
- this.pending.clear();
2644
- this.scopes.clear();
2645
- return;
2646
- }
2647
- const key2 = this.key(state, chainId);
2648
- this.tokens.delete(key2);
2649
- this.pending.delete(key2);
2650
- this.scopes.delete(key2);
2651
- clearYieldseekerSession(state.walletAddress, chainId);
2652
- }
2653
- async sign(state, chainId) {
2654
- const account = getAddress(state.walletAddress);
2655
- const publicClient = createPublicClient2({
2656
- chain: base2,
2657
- transport: custom(state.provider)
2658
- });
2659
- const walletClient = createWalletClient({
2660
- account,
2661
- chain: base2,
2662
- transport: custom(state.provider)
2663
- });
2664
- await ensureWalletOnChain(
2665
- publicClient,
2666
- walletClient,
2667
- 8453
2668
- );
2669
- const message = createYieldseekerSiweMessage(
2670
- account,
2671
- chainId,
2672
- this.dependencies
2673
- );
2674
- const signature = await walletClient.signMessage({ account, message });
2675
- return encodeYieldseekerAuthToken({ message, signature });
2676
- }
2677
- };
2678
-
2679
- // src/agents/yieldseeker/yieldseeker.identity-cache.ts
2680
- var KEY_PREFIX3 = "owney.yieldseeker.identity.v1";
2681
- var YIELDSEEKER_IDENTITY_TTL_MS = 24 * 60 * 60 * 1e3;
2682
- var memoryIdentities = /* @__PURE__ */ new Map();
2683
- var storage3 = () => {
2684
- if (typeof window === "undefined") return null;
2685
- try {
2686
- return window.localStorage;
2687
- } catch {
2688
- return null;
2689
- }
2690
- };
2691
- var keyFor = (walletAddress, chainId) => `${KEY_PREFIX3}:${walletAddress.toLowerCase()}:${chainId}`;
2692
- function valid(value, walletAddress, chainId, now) {
2693
- return Boolean(
2694
- value && typeof value.userId === "string" && /^[a-zA-Z0-9_-]{1,128}$/.test(value.userId) && value.walletAddress.toLowerCase() === walletAddress.toLowerCase() && value.chainId === chainId && Number.isSafeInteger(value.expiresAt) && value.expiresAt > now
2695
- );
2696
- }
2697
- function readYieldseekerIdentity(walletAddress, chainId, now = Date.now()) {
2698
- if (typeof window === "undefined") return null;
2699
- const key2 = keyFor(walletAddress, chainId);
2700
- const store = storage3();
2701
- let parsed = null;
2702
- try {
2703
- const raw2 = store?.getItem(key2);
2704
- parsed = raw2 ? JSON.parse(raw2) : null;
2705
- } catch {
2706
- parsed = null;
2707
- }
2708
- const candidate = parsed ?? memoryIdentities.get(key2);
2709
- if (valid(candidate, walletAddress, chainId, now)) {
2710
- memoryIdentities.set(key2, candidate);
2711
- return { userId: candidate.userId };
2712
- }
2713
- memoryIdentities.delete(key2);
2714
- try {
2715
- store?.removeItem(key2);
2716
- } catch {
2717
- }
2718
- return null;
2719
- }
2720
- function writeYieldseekerIdentity(walletAddress, chainId, userId, now = Date.now()) {
2721
- if (typeof window === "undefined") return;
2722
- const identity = {
2723
- userId,
2724
- walletAddress,
2725
- chainId,
2726
- expiresAt: now + YIELDSEEKER_IDENTITY_TTL_MS
2727
- };
2728
- if (!valid(identity, walletAddress, chainId, now)) return;
2729
- const key2 = keyFor(walletAddress, chainId);
2730
- memoryIdentities.set(key2, identity);
2731
- try {
2732
- storage3()?.setItem(key2, JSON.stringify(identity));
2733
- } catch {
2734
- }
2735
- }
2736
- function clearYieldseekerIdentity(walletAddress, chainId) {
2737
- const key2 = keyFor(walletAddress, chainId);
2738
- memoryIdentities.delete(key2);
2739
- try {
2740
- storage3()?.removeItem(key2);
2741
- } catch {
2742
- }
2743
- }
2744
-
2745
- // src/agents/yieldseeker/yieldseeker.client.ts
2746
- var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2747
- function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
2748
- return `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/agent/yieldseeker`;
2749
- }
2750
- var YIELDSEEKER_API_BASE_URL = getYieldseekerProxyBaseUrl();
2751
- var YieldseekerApiError = class extends Error {
2752
- constructor(status, providerCode, responseFields) {
2753
- super(`Yieldseeker request failed (${status}): ${providerCode}`);
2754
- this.status = status;
2755
- this.providerCode = providerCode;
2756
- this.responseFields = responseFields;
2757
- this.name = "YieldseekerApiError";
2758
- }
2759
- status;
2760
- providerCode;
2761
- responseFields;
2762
- get isAuthenticationError() {
2763
- return this.status === 401 || this.status === 403;
2764
- }
2765
- };
2766
- function providerError(body, fallback) {
2767
- if (!body || typeof body !== "object") return { code: fallback };
2768
- const record = body;
2769
- return {
2770
- code: typeof record.message === "string" ? record.message : fallback,
2771
- fields: record.fields && typeof record.fields === "object" ? record.fields : void 0
2772
- };
2773
- }
2774
- var YieldseekerApiClient = class {
2775
- constructor(owneyApiKey, baseUrl = YIELDSEEKER_API_BASE_URL, fetchFn = fetch.bind(globalThis)) {
2776
- this.owneyApiKey = owneyApiKey;
2777
- this.baseUrl = baseUrl;
2778
- this.fetchFn = fetchFn;
2779
- }
2780
- owneyApiKey;
2781
- baseUrl;
2782
- fetchFn;
2783
- async request(path, options = {}) {
2784
- const controller = new AbortController();
2785
- const timer = setTimeout(
2786
- () => controller.abort(),
2787
- options.timeoutMs ?? 15e3
2788
- );
2789
- try {
2790
- const response = await this.fetchFn(`${this.baseUrl}${path}`, {
2791
- method: options.method ?? "GET",
2792
- headers: {
2793
- "Content-Type": "application/json",
2794
- "x-owney-api-key": this.owneyApiKey,
2795
- ...options.signature ? { Authorization: `Signature ${options.signature}` } : {}
2796
- },
2797
- body: options.body ? JSON.stringify(options.body) : void 0,
2798
- signal: controller.signal
2799
- });
2800
- const payload = await response.json().catch(() => null);
2801
- if (!response.ok) {
2802
- const error = providerError(payload, `HTTP_${response.status}`);
2803
- throw new YieldseekerApiError(
2804
- response.status,
2805
- error.code,
2806
- error.fields
2807
- );
2808
- }
2809
- if (payload && typeof payload === "object" && payload.success === true && "data" in payload) {
2810
- return payload.data;
2811
- }
2812
- return payload;
2813
- } catch (error) {
2814
- if (error instanceof YieldseekerApiError) throw error;
2815
- if (error instanceof DOMException && error.name === "AbortError") {
2816
- throw new YieldseekerApiError(408, "REQUEST_TIMEOUT");
2817
- }
2818
- throw new YieldseekerApiError(0, "NETWORK_ERROR", {
2819
- cause: error instanceof Error ? error.message : String(error)
2820
- });
2821
- } finally {
2822
- clearTimeout(timer);
2823
- }
2824
- }
2825
- };
2826
-
2827
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2828
- import { formatUnits, isAddress } from "viem";
2829
-
2830
- // src/lib/helpers/snapshot-apy.ts
2831
- var DAY_MS = 864e5;
2832
- function snapshotTime(date) {
2833
- if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return void 0;
2834
- const time = Date.parse(date);
2835
- return Number.isFinite(time) && new Date(time).toISOString().slice(0, 10) === date ? time : void 0;
2836
- }
2837
- function returnFactor(value) {
2838
- if (typeof value !== "number" && typeof value !== "string") return void 0;
2839
- if (typeof value === "string" && value.trim() === "") return void 0;
2840
- const factor = Number(value);
2841
- return Number.isFinite(factor) && factor >= 0 ? factor : void 0;
2842
- }
2843
- function calculateSnapshotApy(snapshots, lookbackDays, now = Date.now()) {
2844
- if (!Number.isFinite(lookbackDays) || lookbackDays <= 0 || !Number.isFinite(now)) {
2845
- return void 0;
2846
- }
2847
- const points = snapshots.flatMap((snapshot) => {
2848
- const time = snapshotTime(snapshot.date);
2849
- return time !== void 0 && time <= now ? [{ snapshot, time }] : [];
2850
- }).sort((a, b) => a.time - b.time);
2851
- const end = points.at(-1);
2852
- if (!end) return void 0;
2853
- const cutoff = end.time - lookbackDays * DAY_MS;
2854
- const start = points.find((point) => point.time >= cutoff);
2855
- const actualDays = (end.time - start.time) / DAY_MS;
2856
- if (actualDays <= 0) return void 0;
2857
- const startFactor = returnFactor(start.snapshot.cumulativeReturnFactor);
2858
- const endFactor = returnFactor(end.snapshot.cumulativeReturnFactor);
2859
- if (startFactor === void 0 || startFactor === 0 || endFactor === void 0) {
2860
- return void 0;
2861
- }
2862
- const periodReturn = endFactor / startFactor - 1;
2863
- const apy = Math.pow(1 + periodReturn, 365 / actualDays) - 1;
2864
- return Number.isFinite(apy) ? apy : void 0;
2865
- }
2866
-
2867
- // src/agents/yieldseeker/yieldseeker.types.ts
2868
- var YIELDSEEKER_ASSET_METADATA = {
2869
- USDC: {
2870
- address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
2871
- decimals: 6
2872
- },
2873
- WETH: {
2874
- address: "0x4200000000000000000000000000000000000006",
2875
- decimals: 18
2876
- }
2877
- };
2878
-
2879
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2880
- function invalid(endpoint, detail) {
2881
- throw new OwneyError(
2882
- "AGENT_INVALID_RESPONSE",
2883
- `Yieldseeker returned an invalid ${endpoint} response: ${detail}.`,
2884
- { endpoint, detail },
2885
- "yieldseeker"
2886
- );
2887
- }
2888
- function raw(value, endpoint) {
2889
- if (typeof value !== "string" || !/^-?[0-9]+$/.test(value)) {
2890
- return invalid(endpoint, "expected a base-10 integer string");
2891
- }
2892
- return BigInt(value);
2893
- }
2894
- function decimal(value, decimals, endpoint) {
2895
- return formatUnits(raw(value, endpoint), decimals);
2896
- }
2897
- function usd(rawAmount, decimals, price) {
2898
- return Number(formatUnits(rawAmount, decimals)) * price;
2899
- }
2900
- function percent(value) {
2901
- const result = Number(value);
2902
- return Number.isFinite(result) ? result * 100 : 0;
2903
- }
2904
- var YIELDSEEKER_POSITIVE_YIELD_FEE_RATE = 0.1;
2905
- function publicApyAfterYieldseekerFee(value) {
2906
- const grossPercent = percent(value);
2907
- if (grossPercent <= 0) return grossPercent;
2908
- const netPercent = grossPercent * (1 - YIELDSEEKER_POSITIVE_YIELD_FEE_RATE);
2909
- return Math.round(netPercent * 1e12) / 1e12;
2910
- }
2911
- function riskAdjustedApyForDays(option, days) {
2912
- if (days === "7D") return option.riskAdjustedApy7dAverage;
2913
- if (days === "30D") return option.riskAdjustedApy30dAverage;
2914
- return (option.riskAdjustedApy7dAverage + option.riskAdjustedApy30dAverage) / 2;
2915
- }
2916
- function assetAddressValue(record, address) {
2917
- const entry = Object.entries(record).find(
2918
- ([key2]) => key2.toLowerCase() === address.toLowerCase()
2919
- );
2920
- return entry?.[1] ?? "0";
2921
- }
2922
- function position(value, asset, baseAssetDecimals) {
2923
- const option = value?.yieldOption;
2924
- if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !isAddress(option.address)) {
2925
- return invalid("yield positions", "missing vault metadata");
2926
- }
2927
- return {
2928
- chain: "BASE",
2929
- protocol: option.provider,
2930
- protocolId: option.address,
2931
- pool: option.name,
2932
- asset,
2933
- // `assetsRaw` is the ERC-4626 vault-share quantity, whose decimals can
2934
- // differ from the underlying asset. Yieldseeker already converts it to
2935
- // underlying base-asset units in `assetsBase`; pair that value with the
2936
- // snapshot's corresponding `baseAssetDecimals` for display. Keep the raw
2937
- // share quantity separately because withdraw-from-position expects it.
2938
- amount: decimal(
2939
- value.assetsBase,
2940
- baseAssetDecimals,
2941
- "yield positions"
2942
- ),
2943
- amountRaw: String(value.assetsRaw),
2944
- apy: percent(option.riskAdjustedApy),
2945
- tvl: Number(option.totalDepositsUsd),
2946
- liquidity: Number(option.withdrawableDepositsUsd)
2947
- };
2948
- }
2949
- function mapYieldseekerBalances(contexts) {
2950
- const tokens = [];
2951
- const assetBalances = [];
2952
- const positions = [];
2953
- let totalUsd = 0;
2954
- for (const context of contexts) {
2955
- const metadata = YIELDSEEKER_ASSET_METADATA[context.asset];
2956
- assetBalances.push({
2957
- chain: "BASE",
2958
- chainId: 8453,
2959
- asset: context.asset,
2960
- amount: decimal(context.snapshot.totalValueBase, context.snapshot.baseAssetDecimals, "snapshot")
2961
- });
2962
- const idle = assetAddressValue(
2963
- context.snapshot.tokenBalances,
2964
- metadata.address
2965
- );
2966
- tokens.push({
2967
- chain: "BASE",
2968
- chainId: 8453,
2969
- asset: context.asset,
2970
- amount: decimal(idle, metadata.decimals, "snapshot")
2971
- });
2972
- positions.push(
2973
- ...context.positions.map(
2974
- (entry) => position(
2975
- entry,
2976
- context.asset,
2977
- context.snapshot.baseAssetDecimals
2978
- )
2979
- )
2980
- );
2981
- totalUsd += usd(
2982
- raw(context.snapshot.totalValueBase, "snapshot"),
2983
- context.snapshot.baseAssetDecimals,
2984
- context.snapshot.baseAssetPriceUsd
2985
- );
2986
- }
2987
- return {
2988
- ...contexts.length === 1 ? { smartWallet: contexts[0].wallet.walletAddress } : {},
2989
- totalBalance: String(totalUsd),
2990
- totalBalanceAsset: "usdc",
2991
- assetBalances,
2992
- tokens,
2993
- positions
2994
- };
2995
- }
2996
- function mapYieldseekerEarnings(contexts) {
2997
- const tokens = [];
2998
- let lifetimeEarnings = 0;
2999
- for (const context of contexts) {
3000
- const amount = raw(context.snapshot.cumulativeYieldBase, "snapshot");
3001
- tokens.push({
3002
- chain: "BASE",
3003
- chainId: 8453,
3004
- asset: context.asset,
3005
- amount: formatUnits(amount, context.snapshot.baseAssetDecimals)
3006
- });
3007
- lifetimeEarnings += usd(
3008
- amount,
3009
- context.snapshot.baseAssetDecimals,
3010
- context.snapshot.baseAssetPriceUsd
3011
- );
3012
- }
3013
- return {
3014
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
3015
- lifetimeEarnings,
3016
- tokens
3017
- };
3018
- }
3019
- function apyForDays(context, days, now) {
3020
- if (days === "7D") return percent(context.snapshot.apy7d);
3021
- if (days === "30D") return percent(context.snapshot.apy30d);
3022
- const apy = calculateSnapshotApy(context.historic?.dailyYieldSnapshots ?? [], 14, now);
3023
- const apyPercent = apy === void 0 ? void 0 : apy * 100;
3024
- return apyPercent !== void 0 && Number.isFinite(apyPercent) ? apyPercent : void 0;
3025
- }
3026
- function dailyApy(point) {
3027
- const total = raw(point.totalValueBase, "historic position");
3028
- const earned = raw(point.dailyYieldBase, "historic position");
3029
- const principal = total - earned;
3030
- if (principal <= 0n || earned === 0n) return 0;
3031
- return Number(earned) / Number(principal) * 365 * 100;
3032
- }
3033
- function aggregateHistory(contexts, dayCount, now) {
3034
- const today = new Date(now).toISOString().slice(0, 10);
3035
- const cutoff = new Date(Date.parse(today) - (dayCount - 1) * 864e5).toISOString().slice(0, 10);
3036
- const assets = new Set(contexts.map((context) => context.asset.toUpperCase()));
3037
- const unit = assets.size === 1 ? [...assets][0] : "USD";
3038
- const byDate = /* @__PURE__ */ new Map();
3039
- for (const context of contexts) {
3040
- const points = context.historic?.dailyYieldSnapshots ?? [];
3041
- for (const point of points) {
3042
- if (!/^\d{4}-\d{2}-\d{2}$/.test(point.date) || !Number.isFinite(Date.parse(point.date)) || point.date < cutoff || point.date > today) continue;
3043
- const tokens = Number(decimal(point.totalValueBase, point.baseAssetDecimals, "historic position"));
3044
- const amount = assets.size === 1 ? tokens : tokens * point.baseAssetPriceUsd;
3045
- if (!Number.isFinite(amount) || amount < 0) {
3046
- invalid("historic position", "expected a finite non-negative balance");
3047
- }
3048
- const current = byDate.get(point.date) ?? { weighted: 0, amount: 0 };
3049
- current.weighted += dailyApy(point) * amount;
3050
- current.amount += amount;
3051
- byDate.set(point.date, current);
3052
- }
3053
- }
3054
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
3055
- date,
3056
- apy: value.amount > 0 ? value.weighted / value.amount : 0,
3057
- historicalBalance: { amount: value.amount, unit }
3058
- }));
3059
- }
3060
- function mapYieldseekerApy(walletAddress, contexts, days, now = Date.now()) {
3061
- let weighted = 0;
3062
- let totalUsd = 0;
3063
- const byAsset = {};
3064
- for (const context of contexts) {
3065
- const valueUsd = usd(
3066
- raw(context.snapshot.totalValueBase, "snapshot"),
3067
- context.snapshot.baseAssetDecimals,
3068
- context.snapshot.baseAssetPriceUsd
3069
- );
3070
- const apy = apyForDays(context, days, now);
3071
- if (apy === void 0) continue;
3072
- weighted += apy * valueUsd;
3073
- totalUsd += valueUsd;
3074
- byAsset[context.asset] = apy;
3075
- }
3076
- const dayCount = Number(days.slice(0, -1));
3077
- return {
3078
- walletAddress,
3079
- ...days !== "14D" || Object.keys(byAsset).length > 0 ? { weightedApyAfterFee: totalUsd > 0 ? weighted / totalUsd : 0 } : {},
3080
- apyByChainAndAsset: { 8453: byAsset },
3081
- history: aggregateHistory(contexts, dayCount, now)
3082
- };
3083
- }
3084
- function actionType(value) {
3085
- const normalized = value.toLowerCase();
3086
- if (normalized.includes("deposit")) return "Deposit";
3087
- if (normalized.includes("withdraw")) return "Withdraw";
3088
- if (normalized.includes("yield") || normalized.includes("earn"))
3089
- return "Earned";
3090
- return "Rebalance";
3091
- }
3092
- function transactionHashes(details) {
3093
- if (!details) return [];
3094
- const values = [
3095
- details.transactionHash,
3096
- details.txHash,
3097
- ...Array.isArray(details.transactionHashes) ? details.transactionHashes : [],
3098
- ...Array.isArray(details.txHashes) ? details.txHashes : []
3099
- ];
3100
- return values.filter(
3101
- (value) => typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value)
3102
- ).filter((value, index, all) => all.indexOf(value) === index);
3103
- }
3104
- function actionEntry(action) {
3105
- if (action.actionType.toLowerCase().includes("withdraw")) return void 0;
3106
- return {
3107
- agent: "yieldseeker",
3108
- action: actionType(action.actionType),
3109
- date: action.createdDate,
3110
- oldApy: null,
3111
- newApy: null,
3112
- transactions: [
3113
- {
3114
- txHashes: transactionHashes(action.details),
3115
- chainId: 8453
3116
- }
3117
- ],
3118
- rebalanceLog: []
3119
- };
3120
- }
3121
- function depositDestination(context, movement) {
3122
- const to = movement.toAddress.toLowerCase();
3123
- const option = context.positions.find(({ yieldOption }) => yieldOption.chainId === movement.chainId && yieldOption.assetAddress.toLowerCase() === context.agent.assetAddress.toLowerCase() && yieldOption.address.toLowerCase() === to)?.yieldOption;
3124
- if (option) return { protocol: option.provider || "Vault", pool: option.name, tokenSymbol: context.asset };
3125
- const receipt = context.historic?.assets.find((asset) => asset.chainId === movement.chainId && !asset.isSpam && asset.address.toLowerCase() === to && asset.address.toLowerCase() !== context.agent.assetAddress.toLowerCase());
3126
- const minted = receipt && context.historic?.movements.some((candidate) => candidate.chainId === movement.chainId && candidate.transactionHash.toLowerCase() === movement.transactionHash.toLowerCase() && candidate.assetAddress.toLowerCase() === receipt.address.toLowerCase() && candidate.fromAddress.toLowerCase() === "0x0000000000000000000000000000000000000000" && candidate.toAddress.toLowerCase() === context.wallet.walletAddress.toLowerCase() && raw(candidate.assetAmount, "historic position") > 0n);
3127
- if (receipt && minted) return { protocol: "Vault", pool: receipt.name || receipt.symbol, tokenSymbol: context.asset };
3128
- return void 0;
3129
- }
3130
- function movementEntry(movement, wallet, agent, asset, ownerAddress, destination) {
3131
- const from = movement.fromAddress.toLowerCase();
3132
- const to = movement.toAddress.toLowerCase();
3133
- const owner = ownerAddress.toLowerCase();
3134
- const agentWallet = wallet.walletAddress.toLowerCase();
3135
- const baseAsset = agent.assetAddress.toLowerCase();
3136
- if (movement.chainId !== agent.chainId || movement.assetAddress.toLowerCase() !== baseAsset) {
3137
- return void 0;
3138
- }
3139
- let action;
3140
- if (from === owner && to === agentWallet) {
3141
- action = "Top up";
3142
- } else if (from === agentWallet && to === owner) {
3143
- action = "Withdraw";
3144
- } else if (from === agentWallet && destination) {
3145
- action = "Deposit";
3146
- }
3147
- if (!action) return void 0;
3148
- return {
3149
- agent: "yieldseeker",
3150
- action,
3151
- ...action === "Deposit" && destination ? { positions: [{
3152
- ...destination,
3153
- amount: decimal(movement.assetAmount, YIELDSEEKER_ASSET_METADATA[asset].decimals, "historic position")
3154
- }] } : {},
3155
- date: movement.blockDate,
3156
- oldApy: null,
3157
- newApy: null,
3158
- transactions: [
3159
- {
3160
- txHashes: [movement.transactionHash],
3161
- chainId: agent.chainId,
3162
- tokenSymbol: asset,
3163
- amount: decimal(
3164
- movement.assetAmount,
3165
- YIELDSEEKER_ASSET_METADATA[asset].decimals,
3166
- "historic position"
3167
- )
3168
- }
3169
- ],
3170
- rebalanceLog: []
3171
- };
3172
- }
3173
- function mapYieldseekerHistory(contexts, options) {
3174
- const entries = contexts.flatMap((context) => {
3175
- const seenMovements = /* @__PURE__ */ new Set();
3176
- const movements = (context.historic?.movements ?? []).filter((movement) => {
3177
- const key2 = `${movement.chainId}:${movement.transactionHash.toLowerCase()}:${movement.logIndex}`;
3178
- if (seenMovements.has(key2)) return false;
3179
- seenMovements.add(key2);
3180
- return true;
3181
- });
3182
- return [
3183
- ...movements.map(
3184
- (movement) => movementEntry(
3185
- movement,
3186
- context.wallet,
3187
- context.agent,
3188
- context.asset,
3189
- options.ownerAddress,
3190
- depositDestination(context, movement)
3191
- )
3192
- ),
3193
- ...(context.actions ?? []).map(actionEntry)
3194
- ].filter((entry) => entry !== void 0);
3195
- });
3196
- const grouped = /* @__PURE__ */ new Map();
3197
- const ungrouped = [];
3198
- for (const entry of entries) {
3199
- const tx = entry.transactions[0];
3200
- const hash = tx?.txHashes[0];
3201
- if (!hash) {
3202
- ungrouped.push(entry);
3203
- continue;
3204
- }
3205
- const key2 = `${entry.agent}:${entry.action}:${tx.chainId}:${hash.toLowerCase()}`;
3206
- const previous = grouped.get(key2);
3207
- if (!previous) {
3208
- grouped.set(key2, entry);
3209
- continue;
3210
- }
3211
- if (entry.action === "Deposit" && entry.positions?.length) {
3212
- if (!previous.positions?.length) {
3213
- grouped.set(key2, entry);
3214
- continue;
3215
- }
3216
- previous.positions.push(...entry.positions);
3217
- previous.transactions.push(...entry.transactions);
3218
- }
3219
- }
3220
- const filtered = [...grouped.values(), ...ungrouped].filter((entry) => (!options.fromDate || entry.date >= options.fromDate) && (!options.toDate || entry.date <= options.toDate)).sort((left, right) => right.date.localeCompare(left.date));
3221
- return {
3222
- data: filtered.slice(0, options.limit),
3223
- // v1 returns the whole action/movement collection and defines no cursor.
3224
- // Report a terminal page so callers never loop over the same prefix.
3225
- hasMore: false
3226
- };
3227
- }
3228
- function mapYieldseekerProfile(address, contexts) {
3229
- const protocols = /* @__PURE__ */ new Set();
3230
- for (const context of contexts) {
3231
- for (const current of context.positions) {
3232
- if (current.yieldOption?.provider) {
3233
- protocols.add(String(current.yieldOption.provider));
3234
- }
3235
- }
3236
- }
3237
- return {
3238
- address,
3239
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
3240
- chains: contexts.length > 0 ? [8453] : [],
3241
- hasActiveSessionKey: contexts.some(
3242
- (context) => context.wallet.initializedDate != null
3243
- ),
3244
- protocols: [...protocols]
3245
- };
3246
- }
3247
- function mapYieldseekerAgentApy(options, days) {
3248
- const perAsset = {};
3249
- const all = [];
3250
- for (const entry of options) {
3251
- const apys = entry.yieldOptions.map(
3252
- (option) => publicApyAfterYieldseekerFee(riskAdjustedApyForDays(option, days))
3253
- ).filter(Number.isFinite);
3254
- if (apys.length === 0) continue;
3255
- const average = apys.reduce((sum, value) => sum + value, 0) / apys.length;
3256
- perAsset[entry.asset] = average;
3257
- all.push(average);
3258
- }
3259
- return {
3260
- averageApy: all.length > 0 ? all.reduce((sum, value) => sum + value, 0) / all.length : 0,
3261
- detailedApys: { apyPerAsset: { 8453: perAsset } }
3262
- };
3263
- }
3264
-
3265
- // src/agents/yieldseeker/yieldseeker.agent.ts
3266
- var OWNEY_AGENT_NAME = "owney";
3267
- var YIELDSEEKER_USERNAME_PREFIX = "owney_";
3268
- var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
3269
- var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
3270
- function generateYieldseekerUsername() {
3271
- const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
3272
- return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
3273
- }
3274
- function isUsernameConflict(error) {
3275
- if (!(error instanceof YieldseekerApiError)) return false;
3276
- const code = error.providerCode.toUpperCase();
3277
- return code.includes("USERNAME") && (code.includes("TAKEN") || code.includes("EXIST") || code.includes("UNAVAILABLE") || code.includes("IN_USE"));
3278
- }
3279
- var YIELDSEEKER_AGENT_WALLET_ABI = [
3280
- {
3281
- type: "function",
3282
- name: "withdrawAssetToUser",
3283
- stateMutability: "nonpayable",
3284
- inputs: [
3285
- { name: "recipient", type: "address" },
3286
- { name: "asset", type: "address" },
3287
- { name: "amount", type: "uint256" }
3288
- ],
3289
- outputs: []
3290
- },
3291
- {
3292
- type: "function",
3293
- name: "withdrawAllAssetToUser",
3294
- stateMutability: "nonpayable",
3295
- inputs: [
3296
- { name: "recipient", type: "address" },
3297
- { name: "asset", type: "address" }
3298
- ],
3299
- outputs: []
3300
- }
3301
- ];
3302
- function query(params) {
3303
- const search = new URLSearchParams();
3304
- for (const [key2, value] of Object.entries(params)) {
3305
- if (value !== void 0) search.set(key2, String(value));
3306
- }
3307
- const encoded = search.toString();
3308
- return encoded ? `?${encoded}` : "";
3309
- }
3310
- var YieldseekerAgent = class {
3311
- id = "yieldseeker";
3312
- balanceComposition = "tokens-plus-positions";
3313
- supportedChainIds = [8453];
3314
- supportedAssets = [
3315
- {
3316
- chainId: 8453,
3317
- chain: "BASE",
3318
- assets: [
3319
- { symbol: "USDC", minDepositAmount: "10000000" },
3320
- { symbol: "WETH", minDepositAmount: "1" }
3321
- ]
3322
- }
3323
- ];
3324
- api;
3325
- auth;
3326
- transactionExecutor;
3327
- unwindReceiptWaiter;
3328
- agentContexts = /* @__PURE__ */ new Map();
3329
- users = /* @__PURE__ */ new Map();
3330
- pendingAgents = /* @__PURE__ */ new Map();
3331
- constructor(owneyApiKey, options = {}) {
3332
- this.api = new YieldseekerApiClient(
3333
- owneyApiKey,
3334
- options.baseUrl ?? getYieldseekerProxyBaseUrl(),
3335
- options.fetchFn
3336
- );
3337
- this.auth = new YieldseekerAuth(options.auth);
3338
- this.transactionExecutor = options.transactionExecutor;
3339
- this.unwindReceiptWaiter = options.unwindReceiptWaiter;
3340
- }
3341
- async disconnect() {
3342
- this.auth.clear();
3343
- for (const key2 of this.users.keys()) {
3344
- const [walletAddress, chainId] = key2.split(":");
3345
- clearYieldseekerIdentity(walletAddress, Number(chainId));
3346
- }
3347
- this.users.clear();
3348
- this.agentContexts.clear();
3349
- this.pendingAgents.clear();
3350
- }
3351
- async activateAgent(state, chainId, asset) {
3352
- this.assertChain(chainId);
3353
- const targetAsset = asset ?? "USDC";
3354
- this.assertAsset(targetAsset);
3355
- await this.ensureAgent(state, chainId, targetAsset);
3356
- }
3357
- async deposit(state, chainId, amount, asset, depositCallback) {
3358
- this.assertChain(chainId);
3359
- this.assertAsset(asset);
3360
- if (BigInt(amount) <= 0n) {
3361
- throw new OwneyError(
3362
- "DEPOSIT_AMOUNT_BELOW_MINIMUM",
3363
- "Yieldseeker deposits must be greater than zero.",
3364
- { amount, minDepositAmount: "1" },
3365
- this.id
3366
- );
3367
- }
3368
- const context = await this.ensureAgent(state, chainId, asset);
3369
- let txHash;
3370
- try {
3371
- if (depositCallback) {
3372
- provideDepositVerificationContext(depositCallback, {
3373
- agentId: "yieldseeker",
3374
- signature: await this.auth.getToken(state, chainId),
3375
- userId: context.user.userId,
3376
- yieldseekerAgentId: context.agent.agentId
3377
- });
3378
- txHash = await depositCallback(
3379
- context.wallet.walletAddress,
3380
- chainId,
3381
- amount
3382
- );
3383
- await this.waitForReceipt(state, chainId, txHash);
3384
- } else {
3385
- txHash = await this.submitTransaction(state, chainId, {
3386
- from: getAddress2(state.walletAddress),
3387
- to: YIELDSEEKER_ASSET_METADATA[asset].address,
3388
- data: encodeFunctionData({
3389
- abi: erc20Abi,
3390
- functionName: "transfer",
3391
- args: [getAddress2(context.wallet.walletAddress), BigInt(amount)]
3392
- }),
3393
- value: "0",
3394
- chainId
3395
- });
3396
- }
3397
- await this.deployAfterFunding(state, chainId, context);
3398
- } finally {
3399
- await this.refreshSnapshotAfterMovement(
3400
- state,
3401
- chainId,
3402
- context,
3403
- "deposit"
3404
- );
3405
- }
3406
- return {
3407
- txHash,
3408
- smartWallet: context.wallet.walletAddress,
3409
- amount
3410
- };
3411
- }
3412
- async withdraw(state, chainId, asset, amount) {
3413
- this.assertChain(chainId);
3414
- this.assertAsset(asset);
3415
- if (amount !== void 0 && BigInt(amount) <= 0n) {
3416
- throw new OwneyError(
3417
- "WITHDRAW_FAILED",
3418
- "Yieldseeker withdrawals must be greater than zero.",
3419
- { amount },
3420
- this.id
3421
- );
3422
- }
3423
- const context = await this.findAgent(state, chainId, asset);
3424
- if (!context) {
3425
- throw new OwneyError(
3426
- "WITHDRAW_INSUFFICIENT_BALANCE",
3427
- `No Yieldseeker ${asset} agent exists for this wallet.`,
3428
- { asset, available: "0" },
3429
- this.id
3430
- );
3431
- }
3432
- try {
3433
- const portfolio = await this.loadPortfolioContext(
3434
- state,
3435
- chainId,
3436
- context
3437
- );
3438
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3439
- const idleEntry = Object.entries(portfolio.snapshot.tokenBalances).find(
3440
- ([address]) => address.toLowerCase() === metadata.address.toLowerCase()
3441
- );
3442
- const idle = BigInt(idleEntry?.[1] ?? "0");
3443
- const deployed = portfolio.positions.reduce(
3444
- (total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
3445
- 0n
3446
- );
3447
- const totalAvailable = idle + deployed;
3448
- const requested = amount === void 0 ? totalAvailable : BigInt(amount);
3449
- if (requested > totalAvailable) {
3450
- throw new OwneyError(
3451
- "WITHDRAW_INSUFFICIENT_BALANCE",
3452
- `Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
3453
- {
3454
- asset,
3455
- requested: requested.toString(),
3456
- available: totalAvailable.toString()
3457
- },
3458
- this.id
3459
- );
3460
- }
3461
- let remaining = requested > idle ? requested - idle : 0n;
3462
- for (const position2 of portfolio.positions) {
3463
- if (remaining === 0n) break;
3464
- const available = BigInt(position2.withdrawableAssetsRaw);
3465
- if (available <= 0n) continue;
3466
- const assetsRaw = available < remaining ? available : remaining;
3467
- const response = await this.walletRequest(
3468
- state,
3469
- chainId,
3470
- this.agentPath(context, "withdraw-from-position"),
3471
- {
3472
- method: "POST",
3473
- body: {
3474
- chainId,
3475
- vaultAddress: position2.yieldOption.address,
3476
- assetsRaw: assetsRaw.toString()
3477
- }
3478
- }
3479
- );
3480
- if (!this.isTransactionHash(response?.transactionHash)) {
3481
- throw this.invalidResponse("position withdrawal");
3482
- }
3483
- await this.waitForReceipt(state, chainId, response.transactionHash);
3484
- remaining -= assetsRaw;
3485
- }
3486
- if (remaining > 0n) {
3487
- throw this.invalidResponse("yield positions", {
3488
- reason: "Withdrawable positions could not cover the request.",
3489
- remaining: remaining.toString()
3490
- });
3491
- }
3492
- const account = getAddress2(state.walletAddress);
3493
- const txHash = await this.submitTransaction(state, chainId, {
3494
- from: account,
3495
- to: getAddress2(context.wallet.walletAddress),
3496
- data: amount === void 0 ? encodeFunctionData({
3497
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3498
- functionName: "withdrawAllAssetToUser",
3499
- args: [account, metadata.address]
3500
- }) : encodeFunctionData({
3501
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3502
- functionName: "withdrawAssetToUser",
3503
- args: [account, metadata.address, requested]
3504
- }),
3505
- value: "0",
3506
- chainId
3507
- });
3508
- return {
3509
- txHash,
3510
- type: amount === void 0 ? "full" : "partial",
3511
- amount: requested.toString()
3512
- };
3513
- } finally {
3514
- await this.refreshSnapshotAfterMovement(
3515
- state,
3516
- chainId,
3517
- context,
3518
- "withdrawal"
3519
- );
3520
- }
3521
- }
3522
- async getBalances(state, chainId) {
3523
- this.assertChain(chainId);
3524
- return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, {}));
3525
- }
3526
- async getEarnings(state, chainId) {
3527
- this.assertChain(chainId);
3528
- return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
3529
- }
3530
- async getAccountApy(state, chainId, days, tokenSymbol) {
3531
- this.assertChain(chainId);
3532
- const asset = tokenSymbol?.toUpperCase();
3533
- if (asset !== void 0) this.assertAsset(asset);
3534
- const contexts = await this.loadPortfolio(state, chainId, {
3535
- ...asset ? { asset } : {},
3536
- historic: true
3537
- });
3538
- return mapYieldseekerApy(state.walletAddress, contexts, days);
3539
- }
3540
- async getHistory(state, chainId, options) {
3541
- this.assertChain(chainId);
3542
- const asset = options?.tokenSymbol?.toUpperCase();
3543
- if (asset !== void 0) this.assertAsset(asset);
3544
- const contexts = await this.loadPortfolio(state, chainId, {
3545
- ...asset ? { asset } : {},
3546
- historic: true,
3547
- actions: true
3548
- });
3549
- return mapYieldseekerHistory(contexts, {
3550
- limit: options?.limit ?? 10,
3551
- ownerAddress: state.walletAddress,
3552
- ...options?.fromDate ? { fromDate: options.fromDate } : {},
3553
- ...options?.toDate ? { toDate: options.toDate } : {}
3554
- });
3555
- }
3556
- async getUserProfile(state, chainId) {
3557
- this.assertChain(chainId);
3558
- return mapYieldseekerProfile(
3559
- state.walletAddress,
3560
- await this.loadPortfolio(state, chainId, {})
3561
- );
3562
- }
3563
- async getAgentApy(days, options) {
3564
- this.assertOptionalChain(options?.chainId);
3565
- const requested = options?.tokenSymbol?.toUpperCase();
3566
- if (requested !== void 0) this.assertAsset(requested);
3567
- const assets = requested ? [requested] : ["USDC", "WETH"];
3568
- const values = await Promise.all(
3569
- assets.map(async (asset) => {
3570
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3571
- const response = await this.api.request(
3572
- `/chains/8453/assets/${metadata.address}/yield-options`
3573
- );
3574
- if (!Array.isArray(response?.yieldOptions)) {
3575
- throw this.invalidResponse("yield options");
3576
- }
3577
- return { asset, yieldOptions: response.yieldOptions };
3578
- })
3579
- );
3580
- return mapYieldseekerAgentApy(values, days);
3581
- }
3582
- userKey(state, chainId) {
3583
- return `${state.walletAddress.toLowerCase()}:${chainId}`;
3584
- }
3585
- contextKey(state, chainId, asset) {
3586
- return `${this.userKey(state, chainId)}:${asset}`;
3587
- }
3588
- async resolveUser(state, chainId) {
3589
- const key2 = this.userKey(state, chainId);
3590
- const inMemory = this.users.get(key2);
3591
- if (inMemory) return inMemory;
3592
- const persisted = readYieldseekerIdentity(state.walletAddress, chainId);
3593
- if (persisted) {
3594
- this.users.set(key2, persisted);
3595
- return persisted;
3596
- }
3597
- const walletAddress = getAddress2(state.walletAddress);
3598
- let user = null;
3599
- try {
3600
- const login = await this.providerRequest(
3601
- state,
3602
- chainId,
3603
- "/users/login-with-wallet",
3604
- { method: "POST", body: { walletAddress } }
3605
- );
3606
- user = login?.user ?? null;
3607
- if (!user) {
3608
- throw this.invalidResponse("wallet login", {
3609
- reason: "A successful login returned no user."
3610
- });
3611
- }
3612
- } catch (error) {
3613
- if (!(error instanceof YieldseekerApiError) || error.providerCode !== "NO_USER") {
3614
- if (error instanceof OwneyError) throw error;
3615
- throw this.mapApiError(error);
3616
- }
3617
- let created;
3618
- for (let attempt = 0; attempt < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS; attempt += 1) {
3619
- try {
3620
- created = await this.providerRequest(
3621
- state,
3622
- chainId,
3623
- "/users",
3624
- {
3625
- method: "POST",
3626
- body: {
3627
- walletAddress,
3628
- username: generateYieldseekerUsername()
3629
- }
3630
- }
3631
- );
3632
- break;
3633
- } catch (createError) {
3634
- const canRetry = isUsernameConflict(createError) && attempt + 1 < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS;
3635
- if (canRetry) continue;
3636
- throw this.mapApiError(createError);
3637
- }
3638
- }
3639
- user = created?.user ?? null;
3640
- }
3641
- if (!user || !/^[a-zA-Z0-9_-]{1,128}$/.test(user.userId)) {
3642
- throw this.invalidResponse("wallet identity");
3643
- }
3644
- const resolved = { userId: user.userId };
3645
- this.users.set(key2, resolved);
3646
- writeYieldseekerIdentity(state.walletAddress, chainId, resolved.userId);
3647
- return resolved;
3648
- }
3649
- forgetUser(state, chainId) {
3650
- this.users.delete(this.userKey(state, chainId));
3651
- clearYieldseekerIdentity(state.walletAddress, chainId);
3652
- }
3653
- async ensureAgent(state, chainId, asset) {
3654
- const key2 = this.contextKey(state, chainId, asset);
3655
- const cached = this.agentContexts.get(key2);
3656
- if (cached) return cached;
3657
- const pending = this.pendingAgents.get(key2);
3658
- if (pending) return pending;
3659
- const request = this.resolveAgent(state, chainId, asset, true).then(
3660
- (context) => {
3661
- if (!context) throw this.invalidResponse("agent creation");
3662
- this.agentContexts.set(key2, context);
3663
- return context;
3664
- }
3665
- );
3666
- this.pendingAgents.set(key2, request);
3667
- try {
3668
- return await request;
3669
- } finally {
3670
- this.pendingAgents.delete(key2);
3671
- }
3672
- }
3673
- async findAgent(state, chainId, asset) {
3674
- const key2 = this.contextKey(state, chainId, asset);
3675
- const cached = this.agentContexts.get(key2);
3676
- if (cached) return cached;
3677
- const context = await this.resolveAgent(state, chainId, asset, false);
3678
- if (context) this.agentContexts.set(key2, context);
3679
- return context;
3680
- }
3681
- async resolveAgent(state, chainId, asset, createIfMissing) {
3682
- const user = await this.resolveUser(state, chainId);
3683
- const response = await this.walletRequest(
3684
- state,
3685
- chainId,
3686
- `/users/${user.userId}/agents`
3687
- );
3688
- if (!Array.isArray(response?.agents)) {
3689
- throw this.invalidResponse("agent list");
3690
- }
3691
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3692
- let agent = response.agents.find(
3693
- (candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
3694
- );
3695
- if (!agent && createIfMissing) {
3696
- const created = await this.walletRequest(
3697
- state,
3698
- chainId,
3699
- `/users/${user.userId}/agents`,
3700
- {
3701
- method: "POST",
3702
- body: {
3703
- name: OWNEY_AGENT_NAME,
3704
- emoji: "\u{1F989}",
3705
- chainId,
3706
- assetAddress: metadata.address,
3707
- type: "vault",
3708
- rulePreset: null
3709
- }
3710
- }
3711
- );
3712
- agent = created?.agent;
3713
- }
3714
- if (!agent) return null;
3715
- this.assertAgent(agent);
3716
- const walletResponse = await this.walletRequest(
3717
- state,
3718
- chainId,
3719
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3720
- );
3721
- if (!walletResponse?.agentWallet || !isAddress2(walletResponse.agentWallet.walletAddress)) {
3722
- throw this.invalidResponse("agent wallet");
3723
- }
3724
- return { user, agent, wallet: walletResponse.agentWallet, asset };
3725
- }
3726
- async loadPortfolio(state, chainId, options) {
3727
- const user = await this.resolveUser(state, chainId);
3728
- const response = await this.walletRequest(
3729
- state,
3730
- chainId,
3731
- `/users/${user.userId}/agents`
3732
- );
3733
- if (!Array.isArray(response?.agents)) {
3734
- throw this.invalidResponse("agent list");
3735
- }
3736
- const contexts = [];
3737
- for (const agent of response.agents) {
3738
- const asset = this.assetForAgent(agent);
3739
- if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
3740
- continue;
3741
- }
3742
- this.assertAgent(agent);
3743
- const walletResponse = await this.walletRequest(
3744
- state,
3745
- chainId,
3746
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3747
- );
3748
- if (!walletResponse?.agentWallet || !isAddress2(walletResponse.agentWallet.walletAddress)) {
3749
- throw this.invalidResponse("agent wallet");
3750
- }
3751
- const context = {
3752
- user,
3753
- agent,
3754
- wallet: walletResponse.agentWallet,
3755
- asset
3756
- };
3757
- this.agentContexts.set(this.contextKey(state, chainId, asset), context);
3758
- contexts.push(context);
3759
- }
3760
- return Promise.all(
3761
- contexts.map(
3762
- (context) => this.loadPortfolioContext(state, chainId, context, options)
3763
- )
3764
- );
3765
- }
3766
- async loadPortfolioContext(state, chainId, context, options = {}) {
3767
- const [snapshot, positions, historic, actions] = await Promise.all([
3768
- this.walletRequest(
3769
- state,
3770
- chainId,
3771
- `${this.agentPath(context, "snapshot")}${query({
3772
- shouldOnlyUseRecentValue: true,
3773
- shouldAllowStaleOnError: true
3774
- })}`
3775
- ),
3776
- this.walletRequest(
3777
- state,
3778
- chainId,
3779
- this.agentPath(context, "yield-positions")
3780
- ),
3781
- options.historic ? this.walletRequest(
3782
- state,
3783
- chainId,
3784
- this.agentPath(context, "wallet/historic-position")
3785
- ) : Promise.resolve(void 0),
3786
- options.actions ? this.walletRequest(
3787
- state,
3788
- chainId,
3789
- this.agentPath(context, "actions")
3790
- ) : Promise.resolve(void 0)
3791
- ]);
3792
- if (!snapshot?.agentSnapshot) {
3793
- throw this.invalidResponse("agent snapshot");
3794
- }
3795
- if (!Array.isArray(positions?.yieldPositions)) {
3796
- throw this.invalidResponse("yield positions");
3797
- }
3798
- return {
3799
- ...context,
3800
- snapshot: snapshot.agentSnapshot,
3801
- positions: positions.yieldPositions,
3802
- ...historic?.position ? { historic: historic.position } : {},
3803
- ...actions?.actions ? { actions: actions.actions } : {}
3804
- };
3805
- }
3806
- async deployAfterFunding(state, chainId, context) {
3807
- if (context.wallet.initializedDate != null) return;
3808
- try {
3809
- const deployed = await this.walletRequest(
3810
- state,
3811
- chainId,
3812
- this.agentPath(context, "deploy"),
3813
- { method: "POST", body: {} }
3814
- );
3815
- if (deployed?.agentWallet) {
3816
- context.wallet = deployed.agentWallet;
3817
- }
3818
- } catch (error) {
3819
- console.warn(
3820
- "[owney-sdk] Yieldseeker deposit is funded but not deployable yet:",
3821
- error
3822
- );
3823
- }
3824
- }
3825
- async refreshSnapshotAfterMovement(state, chainId, context, movement) {
3826
- try {
3827
- const response = await this.walletRequest(
3828
- state,
3829
- chainId,
3830
- `${this.agentPath(context, "snapshot")}${query({
3831
- shouldForceRefresh: true
3832
- })}`
3833
- );
3834
- if (!response?.agentSnapshot) {
3835
- throw this.invalidResponse("agent snapshot refresh");
3836
- }
3837
- } catch (error) {
3838
- console.warn(
3839
- `[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
3840
- error
3841
- );
3842
- }
3843
- }
3844
- agentPath(context, suffix) {
3845
- return `/users/${context.user.userId}/agents/${context.agent.agentId}/${suffix}`;
3846
- }
3847
- async walletRequest(state, chainId, path, options = {}) {
3848
- try {
3849
- return await this.providerRequest(state, chainId, path, options);
3850
- } catch (error) {
3851
- throw this.mapApiError(error);
3852
- }
3853
- }
3854
- async providerRequest(state, chainId, path, options = {}) {
3855
- this.assertChain(chainId);
3856
- const request = (signature2) => this.api.request(path, {
3857
- ...options,
3858
- signature: signature2
3859
- });
3860
- let signature = await this.auth.getToken(state, chainId);
3861
- try {
3862
- return await request(signature);
3863
- } catch (error) {
3864
- if (!(error instanceof YieldseekerApiError)) throw error;
3865
- if (error.providerCode === "NO_USER") throw error;
3866
- if (!error.isAuthenticationError) throw error;
3867
- signature = await this.auth.refreshToken(state, chainId, signature);
3868
- try {
3869
- return await request(signature);
3870
- } catch (retryError) {
3871
- if (retryError instanceof YieldseekerApiError && retryError.isAuthenticationError) {
3872
- this.forgetUser(state, chainId);
3873
- }
3874
- throw retryError;
3875
- }
3876
- }
3877
- }
3878
- mapApiError(error) {
3879
- if (!(error instanceof YieldseekerApiError)) {
3880
- return new OwneyError(
3881
- "AGENT_API_ERROR",
3882
- "Yieldseeker request failed.",
3883
- { cause: error instanceof Error ? error.message : String(error) },
3884
- this.id
3885
- );
3886
- }
3887
- const code = error.isAuthenticationError ? "AGENT_AUTH_FAILED" : error.providerCode === "REQUEST_TIMEOUT" ? "AGENT_TIMEOUT" : "AGENT_API_ERROR";
3888
- return new OwneyError(
3889
- code,
3890
- `Yieldseeker request failed: ${error.providerCode}.`,
3891
- {
3892
- statusCode: error.status,
3893
- providerCode: error.providerCode,
3894
- ...error.responseFields ? { fields: error.responseFields } : {}
3895
- },
3896
- this.id
3897
- );
3898
- }
3899
- async submitTransaction(state, chainId, transaction) {
3900
- if (this.transactionExecutor) {
3901
- return this.transactionExecutor(state, chainId, transaction);
3902
- }
3903
- this.assertTransaction(transaction, state, chainId);
3904
- const account = getAddress2(state.walletAddress);
3905
- const walletClient = createWalletClient2({
3906
- account,
3907
- chain: base3,
3908
- transport: custom2(state.provider)
3909
- });
3910
- const publicClient = createPublicClient3({
3911
- chain: base3,
3912
- transport: custom2(state.provider)
3913
- });
3914
- await ensureWalletOnChain(
3915
- publicClient,
3916
- walletClient,
3917
- 8453
3918
- );
3919
- const hash = await walletClient.sendTransaction({
3920
- account,
3921
- chain: base3,
3922
- to: getAddress2(transaction.to),
3923
- data: transaction.data,
3924
- value: BigInt(transaction.value)
3925
- });
3926
- const receipt = await publicClient.waitForTransactionReceipt({
3927
- hash,
3928
- confirmations: 1
3929
- });
3930
- if (receipt.status !== "success") {
3931
- throw new OwneyError(
3932
- "AGENT_TRANSACTION_REVERTED",
3933
- `Yieldseeker transaction reverted (${hash}).`,
3934
- { transactionHash: hash },
3935
- this.id
3936
- );
3937
- }
3938
- return hash;
3939
- }
3940
- async waitForReceipt(state, chainId, transactionHash) {
3941
- if (this.unwindReceiptWaiter) {
3942
- await this.unwindReceiptWaiter(state, chainId, transactionHash);
3943
- return;
3944
- }
3945
- const publicClient = createPublicClient3({
3946
- chain: base3,
3947
- transport: custom2(state.provider)
3948
- });
3949
- const receipt = await publicClient.waitForTransactionReceipt({
3950
- hash: transactionHash,
3951
- confirmations: 1
3952
- });
3953
- if (receipt.status !== "success") {
3954
- throw new OwneyError(
3955
- "AGENT_TRANSACTION_REVERTED",
3956
- `Yieldseeker transaction reverted (${transactionHash}).`,
3957
- { transactionHash },
3958
- this.id
3959
- );
3960
- }
3961
- }
3962
- assertTransaction(transaction, state, chainId) {
3963
- if (!transaction || typeof transaction.from !== "string" || !isAddress2(transaction.from) || typeof transaction.to !== "string" || !isAddress2(transaction.to) || typeof transaction.data !== "string" || !/^0x[a-fA-F0-9]*$/.test(transaction.data) || typeof transaction.value !== "string" || !/^[0-9]+$/.test(transaction.value) || transaction.chainId !== chainId || getAddress2(transaction.from) !== getAddress2(state.walletAddress)) {
3964
- throw this.invalidResponse("transaction");
3965
- }
3966
- }
3967
- assertAgent(agent) {
3968
- if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !isAddress2(agent.assetAddress) || agent.chainId !== 8453) {
3969
- throw this.invalidResponse("agent");
3970
- }
3971
- }
3972
- isOwneyAgent(agent) {
3973
- return typeof agent.name === "string" && agent.name.trim().toLowerCase() === OWNEY_AGENT_NAME;
3974
- }
3975
- assetForAgent(agent) {
3976
- for (const asset of ["USDC", "WETH"]) {
3977
- if (agent.assetAddress.toLowerCase() === YIELDSEEKER_ASSET_METADATA[asset].address.toLowerCase()) {
3978
- return asset;
3979
- }
3980
- }
3981
- return null;
3982
- }
3983
- isTransactionHash(value) {
3984
- return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
3985
- }
3986
- assertChain(chainId) {
3987
- if (chainId !== 8453) {
3988
- throw new OwneyError(
3989
- "CHAIN_UNSUPPORTED",
3990
- `Yieldseeker does not support chain ${chainId}.`,
3991
- { chainId, supportedChainIds: [8453] },
3992
- this.id
3993
- );
3994
- }
3995
- }
3996
- assertOptionalChain(chainId) {
3997
- if (chainId !== void 0) this.assertChain(chainId);
3998
- }
3999
- assertAsset(asset) {
4000
- if (asset !== "USDC" && asset !== "WETH") {
4001
- throw new OwneyError(
4002
- "ASSET_UNSUPPORTED",
4003
- `Yieldseeker does not support asset ${asset} in the Owney rollout.`,
4004
- {
4005
- asset,
4006
- supportedAssets: ["USDC", "WETH"],
4007
- providerAlsoAdvertises: ["cbBTC"]
4008
- },
4009
- this.id
4010
- );
4011
- }
4012
- }
4013
- invalidResponse(operation, details = {}) {
4014
- return new OwneyError(
4015
- "AGENT_INVALID_RESPONSE",
4016
- `Yieldseeker returned an invalid ${operation} response.`,
4017
- details,
4018
- this.id
4019
- );
4020
- }
4021
- };
4022
-
4023
- // src/lib/routing-api.ts
4024
- var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
4025
- async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
4026
- const url = `${baseUrl}/api/v1/agent/org-config`;
4027
- try {
4028
- const res = await fetch(url, {
4029
- method: "GET",
4030
- headers: {
4031
- "Content-Type": "application/json",
4032
- "x-owney-api-key": `${apiKey}`
4033
- }
4034
- });
4035
- if (!res.ok) {
4036
- if (res.status !== 404) {
4037
- console.warn(
4038
- `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
4039
- );
4040
- }
4041
- return null;
4042
- }
4043
- const json = await res.json();
4044
- const policy = json.success ? json.data ?? null : null;
4045
- debugLog(
4046
- "owney-sdk",
4047
- policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
4048
- policy ?? void 0
4049
- );
4050
- return policy;
4051
- } catch (error) {
4052
- console.warn(
4053
- "[owney-sdk] Could not read org agent config (non-fatal):",
4054
- error instanceof Error ? error.message : String(error)
4055
- );
4056
- return null;
4057
- }
4058
- }
4059
- async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
4060
- const url = `${baseUrl}/api/v1/agent/keys`;
4061
- const res = await fetch(url, {
4062
- method: "GET",
4063
- headers: {
4064
- "Content-Type": "application/json",
4065
- "x-owney-api-key": `${apiKey}`
4066
- }
4067
- });
4068
- if (!res.ok) {
4069
- const text = await res.text().catch(() => "");
4070
- throw new OwneyError(
4071
- "API_ROUTING_ERROR",
4072
- `Routing API error ${res.status}: ${text}`,
4073
- { statusCode: res.status, responseBody: text }
4074
- );
4075
- }
4076
- const json = await res.json();
4077
- if (!json.success) {
4078
- throw new OwneyError(
4079
- "API_ROUTING_FAILED",
4080
- `Routing API request failed: ${json.message}`,
4081
- { message: json.message }
4082
- );
4083
- }
4084
- return json.data;
4085
- }
4086
-
4087
- // src/lib/health-report.ts
4088
- var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
4089
- async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL3) {
4090
- try {
4091
- await fetch(`${baseUrl}/api/v1/agent/health-report`, {
4092
- method: "POST",
4093
- headers: {
4094
- "Content-Type": "application/json",
4095
- "x-owney-api-key": apiKey
4096
- },
4097
- body: JSON.stringify({
4098
- agent_type: agentType,
4099
- error_code: errorCode,
4100
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
4101
- })
4102
- });
4103
- } catch (err) {
4104
- console.warn(
4105
- `[owney-sdk] health-report failed for agent "${agentType}":`,
4106
- err instanceof Error ? err.message : err
4107
- );
4108
- }
4109
- }
4110
- async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
4111
- try {
4112
- return await fn();
4113
- } catch (err) {
4114
- const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
4115
- void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
4116
- throw err;
4117
- }
4118
- }
4119
-
4120
- // src/lib/helpers/withdraw-helper.ts
4121
- import { parseUnits } from "viem";
4122
- function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
4123
- const target = asset.toUpperCase();
4124
- return agents.map((agent) => {
4125
- const agentBalance = aggregated[agent.id];
4126
- const tokenBalance = agentBalance?.tokens.find(
4127
- (t) => t.chainId === chainId && t.asset.toUpperCase() === target
4128
- );
4129
- let balance = tokenBalance ? parseUnits(tokenBalance.amount, decimals) : 0n;
4130
- if (agent.balanceComposition === "tokens-plus-positions") {
4131
- const chainNameById = {
4132
- 1: "ETHEREUM",
4133
- 8453: "BASE",
4134
- 42161: "ARBITRUM"
4135
- };
4136
- const targetChain = chainNameById[chainId];
4137
- for (const position2 of agentBalance?.positions ?? []) {
4138
- const positionChain = position2.chain.trim().toUpperCase();
4139
- const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
4140
- if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
4141
- if (position2.amountRaw !== void 0) {
4142
- try {
4143
- balance += BigInt(position2.amountRaw);
4144
- continue;
4145
- } catch {
4146
- }
4147
- }
4148
- balance += parseUnits(position2.amount, decimals);
4149
- }
4150
- }
4151
- return { agent, balance };
4152
- });
4153
- }
4154
- function planProportionalShares(balances, requested, totalAvailable) {
4155
- const plans = balances.map(({ agent, balance }) => ({
4156
- agent,
4157
- balance,
4158
- planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
4159
- }));
4160
- const assigned = plans.reduce((s, p) => s + p.planned, 0n);
4161
- let remainder = requested - assigned;
4162
- const byHeadroom = [...plans].sort((a, b) => {
4163
- const diff = b.balance - b.planned - (a.balance - a.planned);
4164
- return diff > 0n ? 1 : diff < 0n ? -1 : 0;
4165
- });
4166
- for (const p of byHeadroom) {
4167
- if (remainder === 0n) break;
4168
- const headroom = p.balance - p.planned;
4169
- if (headroom <= 0n) continue;
4170
- const take = headroom < remainder ? headroom : remainder;
4171
- p.planned += take;
4172
- remainder -= take;
4173
- }
4174
- return plans;
4175
- }
4176
- function planDisabledDrain(disabled, requested) {
4177
- const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
4178
- (a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
4179
- );
4180
- const plans = [];
4181
- let remaining = requested;
4182
- for (const { agent, balance } of sorted) {
4183
- if (remaining === 0n) {
4184
- plans.push({ agent, balance, planned: 0n });
4185
- continue;
4186
- }
4187
- const take = balance < remaining ? balance : remaining;
4188
- plans.push({ agent, balance, planned: take });
4189
- remaining -= take;
4190
- }
4191
- return { plans, remaining };
4192
- }
4193
- function redistributeShare(plans, fromIndex, amount, candidatePool) {
4194
- const pool = candidatePool ?? plans.slice(fromIndex + 1);
4195
- const candidates = pool.filter((c) => c.balance - c.planned > 0n);
4196
- const totalHeadroom = candidates.reduce(
4197
- (s, c) => s + (c.balance - c.planned),
4198
- 0n
4199
- );
4200
- if (totalHeadroom === 0n) return;
4201
- let distributed = 0n;
4202
- for (const c of candidates) {
4203
- const headroom = c.balance - c.planned;
4204
- const proportional = headroom * amount / totalHeadroom;
4205
- const give = proportional > headroom ? headroom : proportional;
4206
- c.planned += give;
4207
- distributed += give;
4208
- }
4209
- let leftover = amount - distributed;
4210
- for (const c of candidates) {
4211
- if (leftover === 0n) break;
4212
- const headroom = c.balance - c.planned;
4213
- if (headroom <= 0n) continue;
4214
- const take = headroom < leftover ? headroom : leftover;
4215
- c.planned += take;
4216
- leftover -= take;
4217
- }
2386
+ return publicClient.readContract({
2387
+ address: token,
2388
+ abi: ERC20_ALLOWANCE_ABI,
2389
+ functionName: "allowance",
2390
+ args: [owner, PERMIT2_ADDRESS]
2391
+ });
4218
2392
  }
4219
- function sumWithdrawnAmount(results) {
4220
- return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
2393
+ async function readErc20Balance(publicClient, token, owner) {
2394
+ return publicClient.readContract({
2395
+ address: token,
2396
+ abi: ERC20_ALLOWANCE_ABI,
2397
+ functionName: "balanceOf",
2398
+ args: [owner]
2399
+ });
4221
2400
  }
4222
2401
 
4223
- // src/lib/helpers/account-apy-helper.ts
4224
- function balanceForApyScope(balance, chainId, tokenSymbol) {
4225
- if (!tokenSymbol) {
4226
- const total = Number(balance.totalBalance);
4227
- return Number.isFinite(total) && total > 0 ? total : 0;
2402
+ // src/lib/chain-guard.ts
2403
+ var CHAIN_NAMES = {
2404
+ 1: "Ethereum",
2405
+ 8453: "Base",
2406
+ 42161: "Arbitrum"
2407
+ };
2408
+ function chainName(chainId) {
2409
+ return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
2410
+ }
2411
+ async function ensureWalletOnChain(pub, wallet, expected) {
2412
+ const actual = await pub.getChainId();
2413
+ if (actual === expected) return;
2414
+ try {
2415
+ await wallet.switchChain({ id: expected });
2416
+ } catch (error) {
2417
+ throw new OwneyError(
2418
+ "CHAIN_MISMATCH",
2419
+ `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2420
+ {
2421
+ expectedChainId: expected,
2422
+ actualChainId: actual,
2423
+ cause: error instanceof Error ? error.message : String(error)
2424
+ }
2425
+ );
4228
2426
  }
4229
- const normalizedToken = tokenSymbol.toUpperCase();
4230
- const snapshots = balance.assetBalances?.filter(
4231
- (token) => Number(token.chainId) === chainId && String(token.asset).toUpperCase() === normalizedToken
4232
- );
4233
- if (snapshots?.length) {
4234
- const amount = snapshots.reduce((sum, token) => sum + Number(token.amount), 0);
4235
- if (Number.isFinite(amount)) return Math.max(0, amount);
2427
+ const after = await pub.getChainId();
2428
+ if (after !== expected) {
2429
+ throw new OwneyError(
2430
+ "CHAIN_MISMATCH",
2431
+ `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2432
+ { expectedChainId: expected, actualChainId: after }
2433
+ );
4236
2434
  }
4237
- return balance.tokens.reduce((total, token) => {
4238
- if (Number(token.chainId) !== chainId || String(token.asset).toUpperCase() !== normalizedToken) {
4239
- return total;
4240
- }
4241
- const amount = Number(token.amount);
4242
- return Number.isFinite(amount) && amount > 0 ? total + amount : total;
4243
- }, 0);
4244
2435
  }
4245
- function aggregateApyHistory(agentApys) {
4246
- const byDate = /* @__PURE__ */ new Map();
4247
- for (const accountApy of Object.values(agentApys)) {
4248
- const seen = /* @__PURE__ */ new Set();
4249
- for (const point of accountApy.history ?? []) {
4250
- if (!point.date || seen.has(point.date) || !Number.isFinite(point.apy)) continue;
4251
- seen.add(point.date);
4252
- const points = byDate.get(point.date) ?? [];
4253
- points.push(point);
4254
- byDate.set(point.date, points);
4255
- }
4256
- }
4257
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).flatMap(([date, points]) => {
4258
- if (points.length === 1 && !points[0].historicalBalance) {
4259
- return [{ date, apy: points[0].apy }];
2436
+
2437
+ // src/lib/sponsored-deposit.ts
2438
+ var AUTH_WINDOW_SECONDS = 15 * 60;
2439
+ function makeSponsoredDepositCallback(deps) {
2440
+ const post = deps.httpPost ?? postSponsorTransferAuth;
2441
+ return async (smartWallet, chainId, amount) => {
2442
+ const cid = chainId;
2443
+ const token = deps.tokenAddressByChain[cid];
2444
+ if (!token) {
2445
+ throw new OwneyError(
2446
+ "CHAIN_UNSUPPORTED",
2447
+ `No sponsored token configured for chain ${chainId}`
2448
+ );
4260
2449
  }
4261
- const unit = points[0].historicalBalance?.unit;
4262
- if (!unit || points.some(
4263
- ({ historicalBalance: balance }) => !balance || balance.unit !== unit || !Number.isFinite(balance.amount) || balance.amount < 0
4264
- )) return [];
4265
- const total = points.reduce((sum, p) => sum + p.historicalBalance.amount, 0);
4266
- if (total <= 0 || !Number.isFinite(total)) return [];
4267
- const apy = points.reduce((sum, p) => sum + p.apy * (p.historicalBalance.amount / total), 0);
4268
- return Number.isFinite(apy) ? [{ date, apy }] : [];
4269
- });
4270
- }
4271
- function aggregateApyByChainAndAsset(agentApys, agentBalances) {
4272
- const sums = {};
4273
- const weights = {};
4274
- for (const id of Object.keys(agentApys)) {
4275
- const cells = agentApys[id].apyByChainAndAsset;
4276
- const balance = agentBalances[id] ?? 0;
4277
- if (!cells || balance <= 0) continue;
4278
- for (const [chainKey, perAsset] of Object.entries(cells)) {
4279
- if (!perAsset) continue;
4280
- const chainId = Number(chainKey);
4281
- for (const [asset, apyValue] of Object.entries(perAsset)) {
4282
- const apy = Number(apyValue ?? 0);
4283
- if (apy === 0) continue;
4284
- sums[chainId] ??= {};
4285
- weights[chainId] ??= {};
4286
- sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
4287
- weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
2450
+ const pub = deps.getPublicClient(cid);
2451
+ const wallet = deps.getWalletClient(cid);
2452
+ await ensureWalletOnChain(pub, wallet, cid);
2453
+ try {
2454
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2455
+ if (balance < BigInt(amount)) {
2456
+ throw new OwneyError(
2457
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2458
+ "Insufficient balance for this deposit.",
2459
+ { token, chainId: cid, balance: balance.toString(), amount }
2460
+ );
4288
2461
  }
2462
+ } catch (err) {
2463
+ if (err instanceof OwneyError) throw err;
2464
+ console.warn(
2465
+ "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2466
+ err instanceof Error ? err.message : String(err)
2467
+ );
4289
2468
  }
4290
- }
4291
- const out = {};
4292
- for (const chainKey of Object.keys(sums)) {
4293
- const chainId = Number(chainKey);
4294
- const perAssetOut = {};
4295
- for (const asset of Object.keys(sums[chainId])) {
4296
- const w = weights[chainId][asset];
4297
- if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
4298
- }
4299
- if (Object.keys(perAssetOut).length > 0) {
4300
- out[chainId] = perAssetOut;
4301
- }
4302
- }
4303
- return out;
2469
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2470
+ const validAfter = 0n;
2471
+ const validBefore = BigInt(
2472
+ Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2473
+ );
2474
+ const nonce = randomAuthNonce();
2475
+ const typedData = buildTransferWithAuthorizationTypedData({
2476
+ token,
2477
+ chainId: cid,
2478
+ tokenName,
2479
+ tokenVersion,
2480
+ message: {
2481
+ from: deps.ownerAddress,
2482
+ to: smartWallet,
2483
+ value: BigInt(amount),
2484
+ validAfter,
2485
+ validBefore,
2486
+ nonce
2487
+ }
2488
+ });
2489
+ const authSignature = await wallet.signTypedData({
2490
+ account: deps.ownerAddress,
2491
+ ...typedData
2492
+ });
2493
+ deps.onApproved?.();
2494
+ const result = await post({
2495
+ baseUrl: deps.baseUrl,
2496
+ apiKey: deps.apiKey,
2497
+ body: {
2498
+ chainId: cid,
2499
+ token,
2500
+ from: deps.ownerAddress,
2501
+ to: smartWallet,
2502
+ value: amount,
2503
+ validAfter: validAfter.toString(),
2504
+ validBefore: validBefore.toString(),
2505
+ nonce,
2506
+ authSignature,
2507
+ tokenName,
2508
+ tokenVersion
2509
+ }
2510
+ });
2511
+ return result.txHash;
2512
+ };
4304
2513
  }
4305
2514
 
4306
- // src/client.ts
4307
- import {
4308
- createPublicClient as createPublicClient4,
4309
- createWalletClient as createWalletClient3,
4310
- custom as custom3
4311
- } from "viem";
4312
- import { base as base4, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
4313
-
4314
2515
  // src/lib/sponsored-weth-deposit.ts
4315
2516
  var PERMIT_WINDOW_SECONDS = 15 * 60;
4316
2517
  function makeSponsoredWethCallback(deps) {
4317
2518
  const get = deps.httpGet ?? getSponsorRelayerAddress;
4318
2519
  const post = deps.httpPost ?? postSponsorPermit2Transfer;
4319
- return makeVerificationAwareDepositCallback(
4320
- async (smartWallet, chainId, amount, verification) => {
4321
- const cid = chainId;
4322
- const token = deps.tokenAddressByChain[cid];
4323
- if (!token) {
4324
- throw new OwneyError(
4325
- "CHAIN_UNSUPPORTED",
4326
- `No sponsored WETH configured for chain ${chainId}`
4327
- );
4328
- }
4329
- const amountWei = BigInt(amount);
4330
- const pub = deps.getPublicClient(cid);
4331
- const wallet = deps.getWalletClient(cid);
4332
- await ensureWalletOnChain(pub, wallet, cid);
4333
- try {
4334
- const balance = await readErc20Balance(pub, token, deps.ownerAddress);
4335
- if (balance < amountWei) {
4336
- throw new OwneyError(
4337
- "DEPOSIT_INSUFFICIENT_BALANCE",
4338
- "Insufficient WETH balance for this deposit.",
4339
- { token, chainId: cid, balance: balance.toString(), amount }
4340
- );
4341
- }
4342
- } catch (err) {
4343
- if (err instanceof OwneyError) throw err;
4344
- console.warn(
4345
- "[owney-sdk] WETH balance pre-check failed (non-fatal):",
4346
- err instanceof Error ? err.message : String(err)
4347
- );
4348
- }
4349
- const allowance = await readPermit2Allowance(
4350
- pub,
4351
- token,
4352
- deps.ownerAddress
2520
+ return async (smartWallet, chainId, amount) => {
2521
+ const cid = chainId;
2522
+ const token = deps.tokenAddressByChain[cid];
2523
+ if (!token) {
2524
+ throw new OwneyError(
2525
+ "CHAIN_UNSUPPORTED",
2526
+ `No sponsored WETH configured for chain ${chainId}`
4353
2527
  );
4354
- if (allowance < amountWei) {
2528
+ }
2529
+ const amountWei = BigInt(amount);
2530
+ const pub = deps.getPublicClient(cid);
2531
+ const wallet = deps.getWalletClient(cid);
2532
+ await ensureWalletOnChain(pub, wallet, cid);
2533
+ try {
2534
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2535
+ if (balance < amountWei) {
4355
2536
  throw new OwneyError(
4356
- "PERMIT2_APPROVAL_REQUIRED",
4357
- "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
4358
- { token, chainId: cid, allowance: allowance.toString(), amount }
2537
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2538
+ "Insufficient WETH balance for this deposit.",
2539
+ { token, chainId: cid, balance: balance.toString(), amount }
4359
2540
  );
4360
2541
  }
4361
- const relayer = await get({
4362
- baseUrl: deps.baseUrl,
4363
- apiKey: deps.apiKey,
4364
- chainId: cid
4365
- });
4366
- const nonce = randomPermit2Nonce();
4367
- const deadline = BigInt(
4368
- Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2542
+ } catch (err) {
2543
+ if (err instanceof OwneyError) throw err;
2544
+ console.warn(
2545
+ "[owney-sdk] WETH balance pre-check failed (non-fatal):",
2546
+ err instanceof Error ? err.message : String(err)
4369
2547
  );
4370
- const typedData = buildPermitTransferFromTypedData({
4371
- chainId: cid,
4372
- message: {
4373
- permitted: { token, amount: amountWei },
4374
- spender: relayer,
4375
- nonce,
4376
- deadline
4377
- }
4378
- });
4379
- const signature = await wallet.signTypedData({
4380
- account: deps.ownerAddress,
4381
- ...typedData
4382
- });
4383
- deps.onApproved?.();
4384
- const result = await post({
4385
- baseUrl: deps.baseUrl,
4386
- apiKey: deps.apiKey,
4387
- ...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
4388
- body: {
4389
- chainId: cid,
4390
- token,
4391
- from: deps.ownerAddress,
4392
- to: smartWallet,
4393
- amount,
4394
- nonce: nonce.toString(),
4395
- deadline: deadline.toString(),
4396
- signature,
4397
- ...verification?.agentId === "yieldseeker" ? {
4398
- yieldseekerUserId: verification.userId,
4399
- yieldseekerAgentId: verification.yieldseekerAgentId
4400
- } : {}
4401
- }
4402
- });
4403
- return result.txHash;
4404
2548
  }
4405
- );
2549
+ const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
2550
+ if (allowance < amountWei) {
2551
+ throw new OwneyError(
2552
+ "PERMIT2_APPROVAL_REQUIRED",
2553
+ "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
2554
+ { token, chainId: cid, allowance: allowance.toString(), amount }
2555
+ );
2556
+ }
2557
+ const relayer = await get({
2558
+ baseUrl: deps.baseUrl,
2559
+ apiKey: deps.apiKey,
2560
+ chainId: cid
2561
+ });
2562
+ const nonce = randomPermit2Nonce();
2563
+ const deadline = BigInt(
2564
+ Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2565
+ );
2566
+ const typedData = buildPermitTransferFromTypedData({
2567
+ chainId: cid,
2568
+ message: {
2569
+ permitted: { token, amount: amountWei },
2570
+ spender: relayer,
2571
+ nonce,
2572
+ deadline
2573
+ }
2574
+ });
2575
+ const signature = await wallet.signTypedData({
2576
+ account: deps.ownerAddress,
2577
+ ...typedData
2578
+ });
2579
+ deps.onApproved?.();
2580
+ const result = await post({
2581
+ baseUrl: deps.baseUrl,
2582
+ apiKey: deps.apiKey,
2583
+ body: {
2584
+ chainId: cid,
2585
+ token,
2586
+ from: deps.ownerAddress,
2587
+ to: smartWallet,
2588
+ amount,
2589
+ nonce: nonce.toString(),
2590
+ deadline: deadline.toString(),
2591
+ signature
2592
+ }
2593
+ });
2594
+ return result.txHash;
2595
+ };
4406
2596
  }
4407
2597
 
4408
2598
  // src/lib/sponsored-calls-deposit.ts
4409
- import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi2, toHex } from "viem";
2599
+ import { encodeFunctionData, erc20Abi, toHex } from "viem";
4410
2600
  var DEFAULT_POLL_INTERVAL_MS = 1500;
4411
2601
  var DEFAULT_MAX_POLLS = 30;
4412
2602
  async function paymasterSupported(provider, owner, chainId) {
@@ -4432,7 +2622,7 @@ function makeSponsoredCallsCallback(deps) {
4432
2622
  }
4433
2623
  return new URL(configured, origin).toString();
4434
2624
  };
4435
- return makeVerificationAwareDepositCallback(async (smartWallet, chainId, amount, verification) => {
2625
+ return async (smartWallet, chainId, amount) => {
4436
2626
  const cid = chainId;
4437
2627
  const token = deps.tokenAddressByChain[cid];
4438
2628
  if (!token) {
@@ -4448,37 +2638,11 @@ function makeSponsoredCallsCallback(deps) {
4448
2638
  { chainId }
4449
2639
  );
4450
2640
  }
4451
- const data = encodeFunctionData2({
4452
- abi: erc20Abi2,
2641
+ const data = encodeFunctionData({
2642
+ abi: erc20Abi,
4453
2643
  functionName: "transfer",
4454
2644
  args: [smartWallet, BigInt(amount)]
4455
2645
  });
4456
- let paymasterUrl = absolutePaymasterUrl();
4457
- if (verification?.agentId === "yieldseeker") {
4458
- if (chainId !== 8453) {
4459
- throw new OwneyError(
4460
- "CHAIN_UNSUPPORTED",
4461
- `Yieldseeker Base Account sponsorship is not available on chain ${chainId}.`
4462
- );
4463
- }
4464
- const { intent } = await postPaymasterIntent({
4465
- baseUrl: deps.routingApiBaseUrl,
4466
- apiKey: deps.apiKey,
4467
- yieldseekerSignature: verification.signature,
4468
- body: {
4469
- chainId,
4470
- token,
4471
- from: deps.ownerAddress,
4472
- to: smartWallet,
4473
- amount,
4474
- yieldseekerUserId: verification.userId,
4475
- yieldseekerAgentId: verification.yieldseekerAgentId
4476
- }
4477
- });
4478
- const url = new URL(paymasterUrl);
4479
- url.searchParams.set("owneyIntent", intent);
4480
- paymasterUrl = url.toString();
4481
- }
4482
2646
  const sendResult = await deps.provider.request({
4483
2647
  method: "wallet_sendCalls",
4484
2648
  params: [
@@ -4489,7 +2653,7 @@ function makeSponsoredCallsCallback(deps) {
4489
2653
  atomicRequired: false,
4490
2654
  calls: [{ to: token, value: "0x0", data }],
4491
2655
  capabilities: {
4492
- paymasterService: { url: paymasterUrl }
2656
+ paymasterService: { url: absolutePaymasterUrl() }
4493
2657
  }
4494
2658
  }
4495
2659
  ]
@@ -4519,7 +2683,7 @@ function makeSponsoredCallsCallback(deps) {
4519
2683
  `No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
4520
2684
  { chainId, callsId }
4521
2685
  );
4522
- });
2686
+ };
4523
2687
  }
4524
2688
 
4525
2689
  // src/client.ts
@@ -4549,7 +2713,7 @@ var SPONSORED_USDC_BY_CHAIN = {
4549
2713
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
4550
2714
  };
4551
2715
  var VIEM_CHAIN2 = {
4552
- 8453: base4,
2716
+ 8453: base2,
4553
2717
  42161: arbitrum2,
4554
2718
  1: mainnet2
4555
2719
  };
@@ -4561,6 +2725,7 @@ var SPONSORED_WETH_BY_CHAIN = {
4561
2725
  function shouldFallbackToUserPaid(error, asset, appCallback) {
4562
2726
  return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
4563
2727
  }
2728
+ var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai"];
4564
2729
  var OwneySDK = class {
4565
2730
  agents = /* @__PURE__ */ new Map();
4566
2731
  activeAgents = /* @__PURE__ */ new Set();
@@ -4579,8 +2744,6 @@ var OwneySDK = class {
4579
2744
  orgAgentConfig;
4580
2745
  orgAgentConfigPromise = null;
4581
2746
  zyfaiRpcUrls;
4582
- yieldseekerApiBaseUrl;
4583
- yieldseekerSiweOrigin;
4584
2747
  routingApiBaseUrl;
4585
2748
  referralSource;
4586
2749
  cachedSponsoredCallback = null;
@@ -4603,8 +2766,6 @@ var OwneySDK = class {
4603
2766
  this.apiKey = config.apiKey;
4604
2767
  if (config.debug) setOwneyDebug(true);
4605
2768
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
4606
- this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
4607
- this.yieldseekerSiweOrigin = config.yieldseekerSiweOrigin;
4608
2769
  this.routingApiBaseUrl = config.routingApiBaseUrl;
4609
2770
  this.paymasterServiceUrl = config.paymasterServiceUrl;
4610
2771
  this.referralSource = config.referralSource;
@@ -4638,7 +2799,6 @@ var OwneySDK = class {
4638
2799
  * After calling this, `connect()` must be called again before using agent methods.
4639
2800
  */
4640
2801
  async disconnect() {
4641
- this.state = null;
4642
2802
  for (const agent of this.agents.values()) {
4643
2803
  await agent.disconnect();
4644
2804
  }
@@ -4712,14 +2872,14 @@ var OwneySDK = class {
4712
2872
  // Casts work around viem's chain-narrowed Client vs the generic
4713
2873
  // PublicClient/WalletClient param types — structurally identical at
4714
2874
  // runtime, but the two share a name TS treats as unrelated.
4715
- getPublicClient: (cid) => createPublicClient4({
2875
+ getPublicClient: (cid) => createPublicClient2({
4716
2876
  chain: VIEM_CHAIN2[cid],
4717
- transport: custom3(provider)
2877
+ transport: custom(provider)
4718
2878
  }),
4719
- getWalletClient: (cid) => createWalletClient3({
2879
+ getWalletClient: (cid) => createWalletClient({
4720
2880
  account: owner,
4721
2881
  chain: VIEM_CHAIN2[cid],
4722
- transport: custom3(provider)
2882
+ transport: custom(provider)
4723
2883
  })
4724
2884
  });
4725
2885
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -4736,8 +2896,6 @@ var OwneySDK = class {
4736
2896
  if (!onApproved && cached) return cached;
4737
2897
  const provider = this.requireConnectedProvider();
4738
2898
  const callback = makeSponsoredCallsCallback({
4739
- apiKey: this.apiKey,
4740
- routingApiBaseUrl: this.routingApiBaseUrl,
4741
2899
  provider,
4742
2900
  ownerAddress: this.state.walletAddress,
4743
2901
  paymasterServiceUrl: this.paymasterServiceUrl,
@@ -4767,14 +2925,14 @@ var OwneySDK = class {
4767
2925
  // Casts work around viem's chain-narrowed Client vs the generic
4768
2926
  // PublicClient/WalletClient param types — structurally identical at
4769
2927
  // runtime, but the two share a name TS treats as unrelated.
4770
- getPublicClient: (cid) => createPublicClient4({
2928
+ getPublicClient: (cid) => createPublicClient2({
4771
2929
  chain: VIEM_CHAIN2[cid],
4772
- transport: custom3(provider)
2930
+ transport: custom(provider)
4773
2931
  }),
4774
- getWalletClient: (cid) => createWalletClient3({
2932
+ getWalletClient: (cid) => createWalletClient({
4775
2933
  account: owner,
4776
2934
  chain: VIEM_CHAIN2[cid],
4777
- transport: custom3(provider)
2935
+ transport: custom(provider)
4778
2936
  })
4779
2937
  });
4780
2938
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -4805,10 +2963,12 @@ var OwneySDK = class {
4805
2963
  this.orgAgentConfigPromise = fetchOrgAgentConfig(
4806
2964
  this.apiKey,
4807
2965
  this.routingApiBaseUrl
4808
- ).then((config) => {
4809
- this.orgAgentConfig = config;
4810
- return config;
4811
- });
2966
+ ).then(
2967
+ (config) => {
2968
+ this.orgAgentConfig = config;
2969
+ return config;
2970
+ }
2971
+ );
4812
2972
  }
4813
2973
  return this.orgAgentConfigPromise;
4814
2974
  }
@@ -4848,15 +3008,8 @@ var OwneySDK = class {
4848
3008
  this.routingApiBaseUrl
4849
3009
  );
4850
3010
  this.disabledAgents.clear();
4851
- for (const {
4852
- key: key2,
4853
- agent_type,
4854
- is_enabled,
4855
- is_configured
4856
- } of agentKeys) {
4857
- const configured = is_configured ?? Boolean(key2);
4858
- if (!configured) continue;
4859
- const agent = this.createAgent(agent_type, key2);
3011
+ for (const { key: key2, agent_type, is_enabled } of agentKeys) {
3012
+ const agent = await this.createAgent(agent_type, key2);
4860
3013
  if (!agent) continue;
4861
3014
  this.agents.set(agent_type, agent);
4862
3015
  if (is_enabled === false) {
@@ -4877,15 +3030,16 @@ var OwneySDK = class {
4877
3030
  this.initializingAgentsPromise = null;
4878
3031
  }
4879
3032
  }
4880
- createAgent(agentId, key2) {
3033
+ async createAgent(agentId, key2) {
4881
3034
  if (agentId === "zyfai") {
4882
- if (!key2) return null;
4883
3035
  return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
4884
3036
  }
4885
- if (agentId === "yieldseeker") {
4886
- return new YieldseekerAgent(this.apiKey, {
4887
- auth: { origin: this.yieldseekerSiweOrigin },
4888
- baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl)
3037
+ if (agentId === "surfliquid") {
3038
+ if (!key2) return null;
3039
+ const { SurfLiquidAgent } = await import("./surfliquid.agent-AE7RZ66F.js");
3040
+ return new SurfLiquidAgent({
3041
+ apiKey: this.apiKey,
3042
+ routingApiBaseUrl: this.routingApiBaseUrl
4889
3043
  });
4890
3044
  }
4891
3045
  return null;
@@ -4932,10 +3086,9 @@ var OwneySDK = class {
4932
3086
  * If provided, ALL specified agents must support the chainId or the call
4933
3087
  * throws before activating any agent.
4934
3088
  */
4935
- async activateAgent(chainId, agentId, asset) {
3089
+ async activateAgent(chainId, agentId) {
4936
3090
  const state = this.requireState();
4937
3091
  await this.ensureAgentsInitialized();
4938
- this.assertActivationSession(state);
4939
3092
  if (agentId !== void 0) {
4940
3093
  if (agentId.length === 0) {
4941
3094
  throw new OwneyError(
@@ -4969,7 +3122,7 @@ var OwneySDK = class {
4969
3122
  this.activeAgents.add(id);
4970
3123
  }
4971
3124
  state.chainId = chainId;
4972
- await this.activateAgentsInTurn(agents, state, chainId, asset);
3125
+ await this.activateAgentsInTurn(agents, state, chainId);
4973
3126
  return;
4974
3127
  }
4975
3128
  const compatible = [...this.agents.values()].filter(
@@ -4990,12 +3143,7 @@ var OwneySDK = class {
4990
3143
  const enabledCompatible = compatible.filter(
4991
3144
  (agent) => !this.isAgentDisabled(agent.id)
4992
3145
  );
4993
- await this.activateAgentsInTurn(enabledCompatible, state, chainId, asset);
4994
- }
4995
- assertActivationSession(state) {
4996
- if (this.state !== state) {
4997
- throw new OwneyError("NOT_CONNECTED", "Wallet connection changed. Please try again.");
4998
- }
3146
+ await this.activateAgentsInTurn(enabledCompatible, state, chainId);
4999
3147
  }
5000
3148
  /**
5001
3149
  * Activate agents ONE AT A TIME, each followed by its org policy.
@@ -5011,31 +3159,17 @@ var OwneySDK = class {
5011
3159
  * at a time anyway.
5012
3160
  *
5013
3161
  * Every agent is attempted even if an earlier one fails, so one declined
5014
- * signature can't deny the remaining agents their turn. Once all agents have
5015
- * had a chance, a partial failure identifies the agents that still need a
5016
- * retry; if none activated, the original provider error is preserved.
3162
+ * signature can't deny the remaining agents their turn. The first failure is
3163
+ * rethrown (matching the previous `Promise.all` rejection) once all agents
3164
+ * have had a chance to activate.
5017
3165
  */
5018
- async activateAgentsInTurn(agents, state, chainId, asset) {
3166
+ async activateAgentsInTurn(agents, state, chainId) {
5019
3167
  let firstError = null;
5020
- const activatedAgentIds = [];
5021
- const failedAgents = [];
5022
3168
  for (const agent of agents) {
5023
- this.assertActivationSession(state);
5024
3169
  try {
5025
- await agent.activateAgent(state, chainId, asset);
5026
- this.assertActivationSession(state);
3170
+ await agent.activateAgent(state, chainId);
5027
3171
  await this.applyOrgPolicyTo(agent, state, chainId);
5028
- this.assertActivationSession(state);
5029
- activatedAgentIds.push(agent.id);
5030
3172
  } catch (error) {
5031
- this.assertActivationSession(state);
5032
- const message = error !== null && typeof error === "object" && "message" in error && typeof error.message === "string" ? error.message : typeof error === "string" ? error : "No activation error message was returned.";
5033
- failedAgents.push({
5034
- agentId: agent.id,
5035
- code: error instanceof OwneyError ? error.code : void 0,
5036
- message,
5037
- ...error instanceof OwneyError && error.details ? { details: error.details } : {}
5038
- });
5039
3173
  if (firstError === null) {
5040
3174
  firstError = error;
5041
3175
  } else {
@@ -5043,18 +3177,7 @@ var OwneySDK = class {
5043
3177
  }
5044
3178
  }
5045
3179
  }
5046
- if (firstError === null) return;
5047
- if (activatedAgentIds.length === 0) throw firstError;
5048
- const failedAgentIds = failedAgents.map(({ agentId }) => agentId);
5049
- const activeNames = activatedAgentIds.map(this.formatAgentName).join(", ");
5050
- const failureMessages = failedAgents.map(
5051
- ({ agentId, message }) => `${this.formatAgentName(agentId)} activation failed: ${message}`
5052
- ).join(" ");
5053
- throw new OwneyError(
5054
- "AGENT_ACTIVATION_PARTIAL_FAILURE",
5055
- `${activeNames} activated. ${failureMessages}`,
5056
- { activatedAgentIds, failedAgentIds, failures: failedAgents }
5057
- );
3180
+ if (firstError !== null) throw firstError;
5058
3181
  }
5059
3182
  /**
5060
3183
  * Deposit into a specific agent, or distribute across all eligible agents.
@@ -5268,10 +3391,10 @@ var OwneySDK = class {
5268
3391
  agent,
5269
3392
  amount: i === agents.length - 1 ? perAgent + remainder : perAgent
5270
3393
  }));
5271
- const valid2 = splits.filter(
3394
+ const valid = splits.filter(
5272
3395
  (s) => s.amount > 0n && (exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset))
5273
3396
  );
5274
- if (valid2.length === agents.length) {
3397
+ if (valid.length === agents.length) {
5275
3398
  return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
5276
3399
  }
5277
3400
  const targets = agentsRequiringActivation.length > 0 ? agentsRequiringActivation : agents;
@@ -5290,11 +3413,6 @@ var OwneySDK = class {
5290
3413
  )
5291
3414
  }));
5292
3415
  }
5293
- formatAgentName(agentId) {
5294
- if (agentId === "zyfai") return "Zyfai";
5295
- if (agentId === "yieldseeker") return "Yieldseeker";
5296
- return agentId;
5297
- }
5298
3416
  async validateMinDepositAmount(agent, state, chainId, asset, amount) {
5299
3417
  const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
5300
3418
  const parsedAmount = BigInt(amount);
@@ -5321,17 +3439,16 @@ var OwneySDK = class {
5321
3439
  async hasExistingBalance(agent, state, chainId, asset, requireReliableRead = false) {
5322
3440
  try {
5323
3441
  const balance = await agent.getBalances(state, chainId);
5324
- const target = asset.toLowerCase();
5325
3442
  const token = balance.tokens.find(
5326
- (t) => t.chainId === chainId && t.asset.toLowerCase() === target
3443
+ (t) => t.chainId === chainId && isSameAsset(t.asset, asset)
5327
3444
  );
5328
3445
  const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
5329
- const position2 = (balance.positions ?? []).find((p) => {
3446
+ const position = (balance.positions ?? []).find((p) => {
5330
3447
  const positionChain = p.chain.trim().toUpperCase();
5331
3448
  const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
5332
- return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
3449
+ return matchesChain && isSameAsset(p.asset, asset) && Number(p.amount) > 0;
5333
3450
  });
5334
- return !!token && Number(token.amount) > 0 || !!position2;
3451
+ return !!token && Number(token.amount) > 0 || !!position;
5335
3452
  } catch (error) {
5336
3453
  if (requireReliableRead) {
5337
3454
  throw new OwneyError(
@@ -5376,6 +3493,34 @@ var OwneySDK = class {
5376
3493
  }
5377
3494
  return eligible;
5378
3495
  }
3496
+ /**
3497
+ * Agent ids the routing API provisioned for this org that support the given
3498
+ * chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
3499
+ * surfliquid first). Returns `[]` when the org has no compatible agent — never
3500
+ * throws on an empty org. Loads agent keys on first call (apiKey only, no
3501
+ * wallet), so the UI can resolve which agent to use before the user connects.
3502
+ *
3503
+ * This is the source of truth for agent availability: an agent appears here
3504
+ * iff the routing API returned its key. No per-app feature flags.
3505
+ */
3506
+ async getEligibleAgentIds(chainId, asset) {
3507
+ try {
3508
+ await this.ensureAgentsInitialized();
3509
+ } catch (error) {
3510
+ if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
3511
+ return [];
3512
+ }
3513
+ throw error;
3514
+ }
3515
+ return [...this.agents.values()].filter((agent) => {
3516
+ const chainAssets = agent.supportedAssets.find(
3517
+ (sa) => sa.chainId === chainId
3518
+ );
3519
+ return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
3520
+ }).map((agent) => agent.id).sort(
3521
+ (a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
3522
+ );
3523
+ }
5379
3524
  // --- Fund operations ---
5380
3525
  /**
5381
3526
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
@@ -5412,9 +3557,19 @@ var OwneySDK = class {
5412
3557
  }
5413
3558
  const eligibleAgents = this.getEligibleAgents(chainId, asset);
5414
3559
  if (!amount) {
3560
+ const aggregated2 = await this.getBalances();
3561
+ const funded = projectAgentBalancesForAsset(
3562
+ eligibleAgents,
3563
+ aggregated2.agentBalances,
3564
+ chainId,
3565
+ asset,
3566
+ assetInfo.decimals
3567
+ ).filter(
3568
+ ({ agent, balance }) => balance > 0n || aggregated2.agentErrors?.[agent.id] !== void 0
3569
+ ).map(({ agent }) => agent);
5415
3570
  const results2 = {};
5416
3571
  const agentErrors2 = {};
5417
- for (const agent of eligibleAgents) {
3572
+ for (const agent of funded) {
5418
3573
  try {
5419
3574
  results2[agent.id] = await agent.withdraw(state, chainId, token);
5420
3575
  } catch (err) {
@@ -5446,10 +3601,6 @@ var OwneySDK = class {
5446
3601
  }
5447
3602
  const requested = BigInt(amount);
5448
3603
  const aggregated = await this.getBalances();
5449
- const unavailableAgents = eligibleAgents.filter(
5450
- (agent) => !(agent.id in aggregated.agentBalances)
5451
- );
5452
- const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
5453
3604
  const balances = projectAgentBalancesForAsset(
5454
3605
  eligibleAgents,
5455
3606
  aggregated.agentBalances,
@@ -5458,18 +3609,7 @@ var OwneySDK = class {
5458
3609
  assetInfo.decimals
5459
3610
  );
5460
3611
  const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
5461
- if (totalAvailable === 0n && unavailableAgents.length > 0) {
5462
- throw new OwneyError(
5463
- "WITHDRAW_BALANCE_UNAVAILABLE",
5464
- `Cannot safely plan the withdrawal because balance data is unavailable for: ${unavailableAgentIds.join(", ")}.`,
5465
- {
5466
- asset,
5467
- unavailableAgents: unavailableAgentIds,
5468
- agentErrors: aggregated.agentErrors
5469
- }
5470
- );
5471
- }
5472
- if (totalAvailable < requested && unavailableAgents.length === 0) {
3612
+ if (totalAvailable < requested) {
5473
3613
  throw new OwneyError(
5474
3614
  "WITHDRAW_INSUFFICIENT_BALANCE",
5475
3615
  `Requested withdrawal "${amount}" exceeds available balance "${totalAvailable.toString()}" for asset "${asset}".`,
@@ -5480,7 +3620,6 @@ var OwneySDK = class {
5480
3620
  }
5481
3621
  );
5482
3622
  }
5483
- const plannedTarget = totalAvailable < requested ? totalAvailable : requested;
5484
3623
  const disabledBalances = balances.filter(
5485
3624
  (b) => this.isAgentDisabled(b.agent.id)
5486
3625
  );
@@ -5489,7 +3628,7 @@ var OwneySDK = class {
5489
3628
  );
5490
3629
  const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
5491
3630
  disabledBalances,
5492
- plannedTarget
3631
+ requested
5493
3632
  );
5494
3633
  const enabledTotal = enabledBalances.reduce((s, b) => s + b.balance, 0n);
5495
3634
  const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
@@ -5499,9 +3638,7 @@ var OwneySDK = class {
5499
3638
  }));
5500
3639
  const plans = [...disabledPlans, ...enabledPlans];
5501
3640
  const results = {};
5502
- const agentErrors = {
5503
- ...aggregated.agentErrors ?? {}
5504
- };
3641
+ const agentErrors = {};
5505
3642
  for (let i = 0; i < plans.length; i++) {
5506
3643
  const p = plans[i];
5507
3644
  if (p.planned === 0n) continue;
@@ -5548,8 +3685,7 @@ var OwneySDK = class {
5548
3685
  requested: amount,
5549
3686
  withdrawn: withdrawn.toString(),
5550
3687
  partialResults: results,
5551
- agentErrors,
5552
- ...unavailableAgentIds.length > 0 ? { unavailableAgents: unavailableAgentIds } : {}
3688
+ agentErrors
5553
3689
  }
5554
3690
  );
5555
3691
  }
@@ -5567,10 +3703,7 @@ var OwneySDK = class {
5567
3703
  if (agentId) {
5568
3704
  const agent = this.getAgent(agentId);
5569
3705
  const result = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
5570
- return {
5571
- ...result,
5572
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
5573
- };
3706
+ return result;
5574
3707
  }
5575
3708
  let totalBalance = 0;
5576
3709
  const results = {};
@@ -5578,13 +3711,7 @@ var OwneySDK = class {
5578
3711
  const balanceResults = await Promise.allSettled(
5579
3712
  entries.map(async ([id, agent]) => {
5580
3713
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
5581
- return [
5582
- id,
5583
- {
5584
- ...b,
5585
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
5586
- }
5587
- ];
3714
+ return [id, b];
5588
3715
  })
5589
3716
  );
5590
3717
  let successCount = 0;
@@ -5606,7 +3733,6 @@ var OwneySDK = class {
5606
3733
  const retryDelay = rateLimitDelay(reason);
5607
3734
  if (retryDelay !== void 0) agentRetryAt[agentId2] = Date.now() + retryDelay;
5608
3735
  agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
5609
- console.error(`[owney-sdk] Balance fetch failed for agent "${agentId2}":`, reason);
5610
3736
  }
5611
3737
  if (successCount === 0) {
5612
3738
  throw new OwneyError(
@@ -5719,10 +3845,7 @@ var OwneySDK = class {
5719
3845
  Promise.all(
5720
3846
  entries.map(async ([id, agent]) => {
5721
3847
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
5722
- return [
5723
- id,
5724
- balanceForApyScope(b, chainId, tokenSymbol)
5725
- ];
3848
+ return [id, balanceForApyScope(b, chainId, tokenSymbol)];
5726
3849
  })
5727
3850
  )
5728
3851
  ]);
@@ -5903,10 +4026,10 @@ var OwneySDK = class {
5903
4026
  );
5904
4027
  }
5905
4028
  const provider = this.requireConnectedProvider();
5906
- const wallet = createWalletClient3({
4029
+ const wallet = createWalletClient({
5907
4030
  account: state.walletAddress,
5908
4031
  chain: VIEM_CHAIN2[chainId],
5909
- transport: custom3(provider)
4032
+ transport: custom(provider)
5910
4033
  });
5911
4034
  const hash = await wallet.writeContract({
5912
4035
  address: token,
@@ -5916,9 +4039,9 @@ var OwneySDK = class {
5916
4039
  account: state.walletAddress,
5917
4040
  chain: VIEM_CHAIN2[chainId]
5918
4041
  });
5919
- const publicClient = createPublicClient4({
4042
+ const publicClient = createPublicClient2({
5920
4043
  chain: VIEM_CHAIN2[chainId],
5921
- transport: custom3(provider)
4044
+ transport: custom(provider)
5922
4045
  });
5923
4046
  const receipt = await publicClient.waitForTransactionReceipt({
5924
4047
  hash,
@@ -5955,9 +4078,7 @@ var OwneySDK = class {
5955
4078
  return this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
5956
4079
  }
5957
4080
  const results = {};
5958
- const agentEntries = [...this.agents.entries()].filter(
5959
- ([id]) => !this.isAgentDisabled(id)
5960
- );
4081
+ const agentEntries = [...this.agents.entries()];
5961
4082
  const apyResults = await Promise.all(
5962
4083
  agentEntries.map(async ([id, agent]) => {
5963
4084
  const apy = await this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
@@ -6032,13 +4153,13 @@ var OwneySDK = class {
6032
4153
  };
6033
4154
 
6034
4155
  // src/agents/zyfai/zyfai.siwx.ts
6035
- import { getAddress as getAddress3 } from "viem";
6036
- import { SiweMessage as SiweMessage2 } from "siwe";
4156
+ import { getAddress } from "viem";
4157
+ import { SiweMessage } from "siwe";
6037
4158
  import { ZyfaiSDK as ZyfaiSDK2 } from "@zyfai/sdk";
6038
4159
 
6039
4160
  // src/agents/zyfai/zyfai.siwx-cache.ts
6040
- var KEY_PREFIX4 = "owney.siwx.session";
6041
- var storage4 = () => {
4161
+ var KEY_PREFIX2 = "owney.siwx.session";
4162
+ var storage2 = () => {
6042
4163
  if (typeof window === "undefined") return null;
6043
4164
  try {
6044
4165
  return window.localStorage;
@@ -6046,8 +4167,8 @@ var storage4 = () => {
6046
4167
  return null;
6047
4168
  }
6048
4169
  };
6049
- var buildKey3 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}`;
6050
- var legacyKeyPrefix2 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}:`;
4170
+ var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
4171
+ var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
6051
4172
  var memorySiwxSessions = /* @__PURE__ */ new Map();
6052
4173
  var readLegacySiwxSession = (store, address) => {
6053
4174
  if (!store) return null;
@@ -6078,17 +4199,17 @@ var readLegacySiwxSession = (store, address) => {
6078
4199
  };
6079
4200
  var readSiwxSession = (address, chainId) => {
6080
4201
  if (typeof window === "undefined") return null;
6081
- const key2 = buildKey3(address);
6082
- const store = storage4();
6083
- let raw2 = null;
4202
+ const key2 = buildKey2(address);
4203
+ const store = storage2();
4204
+ let raw = null;
6084
4205
  try {
6085
- raw2 = store?.getItem(key2) ?? null;
4206
+ raw = store?.getItem(key2) ?? null;
6086
4207
  } catch {
6087
- raw2 = null;
4208
+ raw = null;
6088
4209
  }
6089
- if (raw2) {
4210
+ if (raw) {
6090
4211
  try {
6091
- return JSON.parse(raw2);
4212
+ return JSON.parse(raw);
6092
4213
  } catch {
6093
4214
  memorySiwxSessions.delete(key2);
6094
4215
  try {
@@ -6107,18 +4228,18 @@ var readSiwxSession = (address, chainId) => {
6107
4228
  };
6108
4229
  var writeSiwxSession = (address, _chainId, session) => {
6109
4230
  if (typeof window === "undefined") return;
6110
- const key2 = buildKey3(address);
4231
+ const key2 = buildKey2(address);
6111
4232
  memorySiwxSessions.set(key2, session);
6112
- const store = storage4();
4233
+ const store = storage2();
6113
4234
  try {
6114
4235
  store?.setItem(key2, JSON.stringify(session));
6115
4236
  } catch {
6116
4237
  }
6117
4238
  };
6118
4239
  var clearSiwxSession = (address, _chainId) => {
6119
- const key2 = buildKey3(address);
4240
+ const key2 = buildKey2(address);
6120
4241
  memorySiwxSessions.delete(key2);
6121
- const store = storage4();
4242
+ const store = storage2();
6122
4243
  try {
6123
4244
  store?.removeItem(key2);
6124
4245
  } catch {
@@ -6158,8 +4279,8 @@ function buildSIWXConfig(deps) {
6158
4279
  statement: STATEMENT,
6159
4280
  issuedAt,
6160
4281
  toString() {
6161
- return new SiweMessage2({
6162
- address: getAddress3(accountAddress),
4282
+ return new SiweMessage({
4283
+ address: getAddress(accountAddress),
6163
4284
  chainId: numericChainId(chainId),
6164
4285
  domain,
6165
4286
  uri,
@@ -6201,7 +4322,7 @@ function buildSIWXConfig(deps) {
6201
4322
  const persistSession = async (session) => {
6202
4323
  const address = session.data.accountAddress;
6203
4324
  const id = numericChainId(session.data.chainId);
6204
- const message = new SiweMessage2(session.message);
4325
+ const message = new SiweMessage(session.message);
6205
4326
  const login = await post("/auth/login", {
6206
4327
  message,
6207
4328
  signature: session.signature,
@@ -6250,7 +4371,6 @@ export {
6250
4371
  NotConnectedError,
6251
4372
  OwneyError,
6252
4373
  OwneySDK,
6253
- YieldseekerAgent,
6254
4374
  createOwneySIWX,
6255
4375
  setOwneyDebug
6256
4376
  };