@owney/sdk 0.7.25-beta.8 → 0.7.25

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,23 +1,3 @@
1
- // src/lib/deposit-batch-callback.ts
2
- var batchCallbacks = /* @__PURE__ */ new WeakMap();
3
- var getDepositBatchTransfer = (callback) => callback ? batchCallbacks.get(callback) : void 0;
4
- function toBatchTransfer(to, amount, verification) {
5
- return {
6
- to,
7
- amount,
8
- ...verification ? {
9
- yieldseeker: {
10
- signature: verification.signature,
11
- userId: verification.userId,
12
- agentId: verification.yieldseekerAgentId
13
- }
14
- } : {}
15
- };
16
- }
17
- function registerDepositBatch(callback, transfer) {
18
- batchCallbacks.set(callback, transfer);
19
- }
20
-
21
1
  // src/errors.ts
22
2
  var OwneyError = class extends Error {
23
3
  code;
@@ -125,34 +105,6 @@ function rateLimitDelay(error, now = Date.now()) {
125
105
  }
126
106
 
127
107
  // src/lib/agent-reads.ts
128
- function rateLimitDiagnostics(error) {
129
- const seen = /* @__PURE__ */ new Set();
130
- let details = {};
131
- function visit(value, depth = 0) {
132
- if (depth > 6 || !value || typeof value !== "object" || seen.has(value))
133
- return;
134
- seen.add(value);
135
- const record = value;
136
- for (const key2 of [
137
- "rpcSource",
138
- "chainId",
139
- "rpcMethod",
140
- "providerRequestId",
141
- "statusCode"
142
- ]) {
143
- const candidate = record[key2];
144
- if (candidate !== void 0 && details[key2] === void 0)
145
- details = { ...details, [key2]: candidate };
146
- }
147
- for (const key2 of ["details", "cause", "response", "fields", "error"])
148
- visit(record[key2], depth + 1);
149
- }
150
- visit(error);
151
- return {
152
- rpcSource: details.rpcSource ?? "agent-api",
153
- ...details
154
- };
155
- }
156
108
  var AgentReads = class {
157
109
  inFlight = /* @__PURE__ */ new Map();
158
110
  cooldowns = /* @__PURE__ */ new Map();
@@ -160,15 +112,14 @@ var AgentReads = class {
160
112
  clearInFlight() {
161
113
  this.inFlight.clear();
162
114
  }
163
- limited(agentId, until, diagnostics) {
115
+ limited(agentId, until) {
164
116
  return new OwneyError(
165
117
  "AGENT_RATE_LIMITED",
166
118
  "Too many requests. Please wait before trying again.",
167
119
  {
168
120
  statusCode: 429,
169
121
  retryAt: until,
170
- retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3)),
171
- ...diagnostics
122
+ retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3))
172
123
  },
173
124
  agentId
174
125
  );
@@ -176,9 +127,7 @@ var AgentReads = class {
176
127
  run(agentId, key2, fetch2) {
177
128
  const cooldown = this.cooldowns.get(agentId);
178
129
  if (cooldown && cooldown.until > Date.now()) {
179
- return Promise.reject(
180
- this.limited(agentId, cooldown.until, cooldown.diagnostics)
181
- );
130
+ return Promise.reject(this.limited(agentId, cooldown.until));
182
131
  }
183
132
  const requestKey = JSON.stringify([agentId, key2]);
184
133
  const existing = this.inFlight.get(requestKey);
@@ -199,9 +148,8 @@ var AgentReads = class {
199
148
  Math.min(3e4 * 2 ** (failures - 1), 3e5)
200
149
  );
201
150
  const until = Math.max(previous?.until ?? 0, Date.now() + delay);
202
- const diagnostics = rateLimitDiagnostics(error);
203
- this.cooldowns.set(agentId, { until, failures, diagnostics });
204
- throw this.limited(agentId, until, diagnostics);
151
+ this.cooldowns.set(agentId, { until, failures });
152
+ throw this.limited(agentId, until);
205
153
  }
206
154
  ).finally(() => {
207
155
  if (this.inFlight.get(requestKey) === promise)
@@ -214,7 +162,7 @@ var AgentReads = class {
214
162
 
215
163
  // src/agents/zyfai/zyfai.agent.ts
216
164
  import { SMART_SESSIONS_VALIDATOR, ZyfaiSDK } from "@zyfai/sdk";
217
- import { parseAbi } from "viem";
165
+ import { createPublicClient, http, parseAbi } from "viem";
218
166
  import { base, arbitrum, mainnet } from "viem/chains";
219
167
 
220
168
  // src/types/config.ts
@@ -329,18 +277,18 @@ function tokenDecimals(symbol, explicit) {
329
277
  return explicit;
330
278
  return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
331
279
  }
332
- function mapDeposit(raw2) {
280
+ function mapDeposit(raw) {
333
281
  return {
334
- txHash: raw2.txHash,
335
- smartWallet: raw2.smartWallet,
336
- amount: raw2.amount
282
+ txHash: raw.txHash,
283
+ smartWallet: raw.smartWallet,
284
+ amount: raw.amount
337
285
  };
338
286
  }
339
- function mapWithdraw(raw2) {
287
+ function mapWithdraw(raw) {
340
288
  return {
341
- txHash: raw2.txHash,
342
- type: raw2.type,
343
- amount: raw2.amount
289
+ txHash: raw.txHash,
290
+ type: raw.type,
291
+ amount: raw.amount
344
292
  };
345
293
  }
346
294
  var CHAIN_ID_TO_NAME = {
@@ -359,10 +307,10 @@ function resolveChainId(chain) {
359
307
  if (Number.isFinite(asNum) && asNum > 0) return asNum;
360
308
  return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
361
309
  }
362
- function mapPendingAllocations(raw2) {
363
- if (!Array.isArray(raw2)) return void 0;
310
+ function mapPendingAllocations(raw) {
311
+ if (!Array.isArray(raw)) return void 0;
364
312
  const pending = [];
365
- for (const entry of raw2) {
313
+ for (const entry of raw) {
366
314
  if (typeof entry !== "object" || entry === null) continue;
367
315
  const e = entry;
368
316
  if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
@@ -385,8 +333,8 @@ function mapPendingAllocations(raw2) {
385
333
  }
386
334
  return pending.length > 0 ? pending : void 0;
387
335
  }
388
- function mapBalances(raw2, _chainId, smartWallet) {
389
- const portfolio = raw2.portfolio;
336
+ function mapBalances(raw, _chainId, smartWallet) {
337
+ const portfolio = raw.portfolio;
390
338
  const portfolioByChain = portfolio.portfolioByChain ?? {};
391
339
  let totalBalance = 0;
392
340
  const tokens = [];
@@ -455,8 +403,8 @@ function sumTokenValues(tokens) {
455
403
  function sumTokenEarnings(tokens) {
456
404
  return Object.values(tokens).reduce((sum, val) => sum + Number(val), 0);
457
405
  }
458
- function mapEarnings(raw2, smartWallet) {
459
- const totalEarningsByChain = raw2.data.totalEarningsByChainWithFee ?? raw2.data.totalEarningsByChain ?? {};
406
+ function mapEarnings(raw, smartWallet) {
407
+ const totalEarningsByChain = raw.data.totalEarningsByChainWithFee ?? raw.data.totalEarningsByChain ?? {};
460
408
  const tokens = [];
461
409
  for (const [chainIdKey, tokensBySymbol] of Object.entries(
462
410
  totalEarningsByChain
@@ -475,15 +423,15 @@ function mapEarnings(raw2, smartWallet) {
475
423
  return {
476
424
  smartWallet,
477
425
  lifetimeEarnings: sumTokenEarnings(
478
- raw2.data.totalEarningsByTokenWithFee ?? raw2.data.totalEarningsByToken
426
+ raw.data.totalEarningsByTokenWithFee ?? raw.data.totalEarningsByToken
479
427
  ),
480
428
  tokens
481
429
  };
482
430
  }
483
- function mapWeightedApyByChain(raw2) {
484
- if (!raw2) return void 0;
431
+ function mapWeightedApyByChain(raw) {
432
+ if (!raw) return void 0;
485
433
  const out = {};
486
- for (const [chainKey, tokenApy] of Object.entries(raw2)) {
434
+ for (const [chainKey, tokenApy] of Object.entries(raw)) {
487
435
  const chainId = Number(chainKey);
488
436
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
489
437
  const perAsset = {};
@@ -523,8 +471,8 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
523
471
  }
524
472
  return totalBalance > 0 ? weightedSum / totalBalance : null;
525
473
  }
526
- function mapApyHistory(raw2, chainId, tokenSymbol) {
527
- const history = Object.entries(raw2.history ?? {}).map(([date, entry]) => ({
474
+ function mapApyHistory(raw, chainId, tokenSymbol) {
475
+ const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
528
476
  date,
529
477
  apy: rawPoolApyForChain(entry, chainId, tokenSymbol),
530
478
  // Provider position balances are treated as decimal amounts of the
@@ -540,9 +488,9 @@ function mapApyHistory(raw2, chainId, tokenSymbol) {
540
488
  } : {}
541
489
  })).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
542
490
  return {
543
- walletAddress: raw2.walletAddress,
544
- weightedApyAfterFee: raw2.weightedApyAfterFee ? sumTokenValues(raw2.weightedApyAfterFee) : void 0,
545
- apyByChainAndAsset: mapWeightedApyByChain(raw2.weightedApyAfterFeeByChain),
491
+ walletAddress: raw.walletAddress,
492
+ weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
493
+ apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain),
546
494
  history
547
495
  };
548
496
  }
@@ -638,23 +586,23 @@ function mapEntries(rawEntries, chainId) {
638
586
  };
639
587
  });
640
588
  }
641
- function mapUserProfile(raw2, userAddress) {
589
+ function mapUserProfile(raw, userAddress) {
642
590
  return {
643
591
  address: userAddress,
644
- smartWallet: raw2.smartWallet || "",
645
- chains: raw2.chains || [],
646
- strategy: raw2.strategy,
647
- hasActiveSessionKey: raw2.hasActiveSessionKey || false,
648
- protocols: raw2.protocols || [],
649
- splitting: raw2.splitting,
650
- minSplits: raw2.minSplits
592
+ smartWallet: raw.smartWallet || "",
593
+ chains: raw.chains || [],
594
+ strategy: raw.strategy,
595
+ hasActiveSessionKey: raw.hasActiveSessionKey || false,
596
+ protocols: raw.protocols || [],
597
+ splitting: raw.splitting,
598
+ minSplits: raw.minSplits
651
599
  };
652
600
  }
653
- function mapApyByStrategy(raw2) {
601
+ function mapApyByStrategy(raw) {
654
602
  const apyPerAsset = {};
655
603
  let apySum = 0;
656
604
  let apyCount = 0;
657
- for (const entry of raw2.data) {
605
+ for (const entry of raw.data) {
658
606
  const supported = SupportedAssets.find(
659
607
  (asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
660
608
  );
@@ -766,9 +714,9 @@ function netDeltaForSnapshot(entry, chainId, asset) {
766
714
  debugLog("zyfai:earnings", "gross fallback for daily earnings", { gross });
767
715
  return gross;
768
716
  }
769
- function mapDailyEarnings(raw2, chainId, tokenSymbol) {
717
+ function mapDailyEarnings(raw, chainId, tokenSymbol) {
770
718
  const wanted = tokenSymbol?.toUpperCase();
771
- const snapshots = [...raw2.data ?? []].sort(
719
+ const snapshots = [...raw.data ?? []].sort(
772
720
  (a, b) => a.snapshot_date.localeCompare(b.snapshot_date)
773
721
  );
774
722
  const byAsset = /* @__PURE__ */ new Map();
@@ -783,7 +731,7 @@ function mapDailyEarnings(raw2, chainId, tokenSymbol) {
783
731
  }
784
732
  }
785
733
  const assets = [...byAsset.entries()].map(([asset, series]) => ({ asset, points: series.points })).sort((a, b) => a.asset.localeCompare(b.asset));
786
- return { walletAddress: raw2.walletAddress, chainId, assets };
734
+ return { walletAddress: raw.walletAddress, chainId, assets };
787
735
  }
788
736
 
789
737
  // src/agents/zyfai/zyfai.withdraw-amount.ts
@@ -894,15 +842,15 @@ var readSession = (address, _chainId) => {
894
842
  if (typeof window === "undefined") return null;
895
843
  const key2 = buildKey(address);
896
844
  const store = storage();
897
- let raw2 = null;
845
+ let raw = null;
898
846
  try {
899
- raw2 = store?.getItem(key2) ?? null;
847
+ raw = store?.getItem(key2) ?? null;
900
848
  } catch {
901
- raw2 = null;
849
+ raw = null;
902
850
  }
903
- if (raw2) {
851
+ if (raw) {
904
852
  try {
905
- const parsed = JSON.parse(raw2);
853
+ const parsed = JSON.parse(raw);
906
854
  if (isFreshSession(parsed)) return parsed;
907
855
  } catch {
908
856
  }
@@ -1070,8 +1018,8 @@ function buildChainsByProtocol(protocols, dashboardChainIds) {
1070
1018
  }
1071
1019
  return result;
1072
1020
  }
1073
- function flattenAvailablePools(raw2) {
1074
- const byChain = raw2 ?? {};
1021
+ function flattenAvailablePools(raw) {
1022
+ const byChain = raw ?? {};
1075
1023
  const names = [];
1076
1024
  for (const byToken of Object.values(byChain ?? {})) {
1077
1025
  for (const entry of Object.values(byToken ?? {})) {
@@ -1095,148 +1043,15 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
1095
1043
  return !protocolListsEqual(current.protocols, desiredProtocols);
1096
1044
  }
1097
1045
 
1098
- // src/lib/paid-rpc.ts
1099
- import {
1100
- createPublicClient,
1101
- http
1102
- } from "viem";
1103
- var PAID_RPC_RETRY_COUNT = 3;
1104
- var PAID_RPC_RETRY_DELAY_MS = 1e3;
1105
- function configuredRpcProxyBaseUrl(baseUrl) {
1106
- const configured = (baseUrl ?? "")?.trim();
1107
- if (!configured) {
1108
- throw new Error(
1109
- "OWNEY_ROUTING_API_BASE_URL is required for RPC proxy requests unless routingApiBaseUrl or all rpcUrls are configured."
1110
- );
1111
- }
1112
- return configured;
1113
- }
1114
- function rpcProxyUrl(chainId, apiKey, baseUrl) {
1115
- const url = new URL(
1116
- `${configuredRpcProxyBaseUrl(baseUrl).replace(/\/$/, "")}/api/v1/rpc/${chainId}`
1117
- );
1118
- if (apiKey) url.searchParams.set("apiKey", apiKey);
1119
- return url.toString();
1120
- }
1121
- function resolveRpcUrl(rpcUrls, chainId, apiKey = "", baseUrl) {
1122
- const url = rpcUrls?.[chainId]?.trim();
1123
- if (url) return url;
1124
- return rpcProxyUrl(chainId, apiKey, baseUrl);
1125
- }
1126
- function resolveRpcUrls(rpcUrls, apiKey = "", baseUrl) {
1127
- return {
1128
- 1: resolveRpcUrl(rpcUrls, 1, apiKey, baseUrl),
1129
- 8453: resolveRpcUrl(rpcUrls, 8453, apiKey, baseUrl),
1130
- 42161: resolveRpcUrl(rpcUrls, 42161, apiKey, baseUrl)
1131
- };
1132
- }
1133
- function createPaidRpcClient(chain, rpcUrls) {
1134
- const url = resolveRpcUrl(
1135
- rpcUrls,
1136
- chain.id
1137
- );
1138
- return createPublicClient({
1139
- chain,
1140
- transport: http(url, {
1141
- retryCount: PAID_RPC_RETRY_COUNT,
1142
- retryDelay: PAID_RPC_RETRY_DELAY_MS
1143
- })
1144
- });
1145
- }
1146
- function headerValue(error, name) {
1147
- const seen = /* @__PURE__ */ new Set();
1148
- let value;
1149
- function visit(candidate, depth = 0) {
1150
- if (value || depth > 6 || !candidate || typeof candidate !== "object")
1151
- return;
1152
- if (seen.has(candidate)) return;
1153
- seen.add(candidate);
1154
- const record = candidate;
1155
- const headers = record.headers;
1156
- let found;
1157
- if (typeof headers?.get === "function") {
1158
- found = headers.get(name);
1159
- } else {
1160
- const headerRecord = headers;
1161
- found = headerRecord?.[name] ?? headerRecord?.[name.toLowerCase()];
1162
- }
1163
- if (typeof found === "string" && found) {
1164
- value = found;
1165
- return;
1166
- }
1167
- for (const key2 of ["cause", "details", "response", "error"])
1168
- visit(record[key2], depth + 1);
1169
- }
1170
- visit(error);
1171
- return value;
1172
- }
1173
- function statusCode(error) {
1174
- const seen = /* @__PURE__ */ new Set();
1175
- let status;
1176
- function visit(candidate, depth = 0) {
1177
- if (status || depth > 6 || !candidate || typeof candidate !== "object")
1178
- return;
1179
- if (seen.has(candidate)) return;
1180
- seen.add(candidate);
1181
- const record = candidate;
1182
- for (const key2 of ["status", "statusCode"]) {
1183
- const parsed = Number(record[key2]);
1184
- if (Number.isInteger(parsed) && parsed >= 100 && parsed <= 599) {
1185
- status = parsed;
1186
- return;
1187
- }
1188
- }
1189
- for (const key2 of ["cause", "details", "response", "error"])
1190
- visit(record[key2], depth + 1);
1191
- }
1192
- visit(error);
1193
- return status;
1194
- }
1195
- function paidRpcError(error, chainId, rpcMethod, agentId) {
1196
- const delay = rateLimitDelay(error);
1197
- const providerRequestId = headerValue(error, "x-alchemy-request-id") ?? headerValue(error, "x-request-id");
1198
- if (delay === void 0) {
1199
- return new OwneyError(
1200
- "AGENT_API_ERROR",
1201
- "The blockchain RPC request failed.",
1202
- {
1203
- rpcSource: "paid-rpc",
1204
- chainId,
1205
- rpcMethod,
1206
- ...statusCode(error) ? { statusCode: statusCode(error) } : {},
1207
- ...providerRequestId ? { providerRequestId } : {}
1208
- },
1209
- agentId
1210
- );
1211
- }
1212
- const retryAt = Date.now() + delay;
1213
- return new OwneyError(
1214
- "AGENT_RATE_LIMITED",
1215
- "The blockchain RPC is rate limited. Please wait before trying again.",
1216
- {
1217
- rpcSource: "paid-rpc",
1218
- chainId,
1219
- rpcMethod,
1220
- statusCode: 429,
1221
- retryAt,
1222
- retryAfterSeconds: Math.max(0, Math.ceil(delay / 1e3)),
1223
- ...providerRequestId ? { providerRequestId } : {}
1224
- },
1225
- agentId
1226
- );
1227
- }
1228
- async function withPaidRpcDiagnostics(operation, chainId, rpcMethod, agentId) {
1229
- try {
1230
- return await operation();
1231
- } catch (error) {
1232
- throw paidRpcError(error, chainId, rpcMethod, agentId);
1233
- }
1234
- }
1235
-
1236
1046
  // src/agents/zyfai/zyfai.agent.ts
1237
1047
  var ERC7579_IS_MODULE_INSTALLED_ABI = parseAbi([
1238
1048
  "function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
1239
1049
  ]);
1050
+ var DEFAULT_ZYFAI_RPC_URLS = {
1051
+ 8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
1052
+ 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
1053
+ 1: "https://eth-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
1054
+ };
1240
1055
  var WETH_ADDRESS_BY_CHAIN = {
1241
1056
  8453: "0x4200000000000000000000000000000000000006",
1242
1057
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
@@ -1302,7 +1117,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1302
1117
  earningsSnapshot = null;
1303
1118
  earningsGeneration = 0;
1304
1119
  constructor(apiKey, rpcUrls, referralSource) {
1305
- this.rpcUrls = resolveRpcUrls(rpcUrls);
1120
+ this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
1306
1121
  this.sdk = new ZyfaiSDK({
1307
1122
  apiKey,
1308
1123
  rpcUrls: this.rpcUrls,
@@ -1316,10 +1131,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
1316
1131
  getPublicClient(chainId) {
1317
1132
  const cached = this.publicClients.get(chainId);
1318
1133
  if (cached) return cached;
1319
- const client = createPaidRpcClient(
1320
- VIEM_CHAIN[chainId],
1321
- this.rpcUrls
1322
- );
1134
+ const client = createPublicClient({
1135
+ chain: VIEM_CHAIN[chainId],
1136
+ transport: http(this.rpcUrls[chainId])
1137
+ });
1323
1138
  this.publicClients.set(chainId, client);
1324
1139
  return client;
1325
1140
  }
@@ -1489,7 +1304,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1489
1304
  * chain/account switch fires the provider's `accountsChanged` →
1490
1305
  * `disconnectAccount` (nulls walletClient + authenticatedUserId) while our
1491
1306
  * own `connectAuth` guard still believes this chain is connected and
1492
- * early-returns. Without this, authenticated calls (depositFunds,
1307
+ * early-returns. Without this, authenticated calls (sendDeposit,
1493
1308
  * withdrawFunds) fail with "No account connected".
1494
1309
  */
1495
1310
  async ensureConnected(state, chainId) {
@@ -1707,8 +1522,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
1707
1522
  const poolResults = await Promise.all(
1708
1523
  universe.map(async (protocol) => {
1709
1524
  try {
1710
- const raw2 = await this.sdk.getAvailablePools(protocol.id, strategy);
1711
- return [protocol.id, flattenAvailablePools(raw2)];
1525
+ const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
1526
+ return [protocol.id, flattenAvailablePools(raw)];
1712
1527
  } catch (error) {
1713
1528
  console.warn(
1714
1529
  `[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
@@ -1774,14 +1589,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
1774
1589
  async readWalletState(ownerAddress) {
1775
1590
  try {
1776
1591
  const { portfolio } = await this.sdk.getPositions(ownerAddress);
1777
- const raw2 = portfolio;
1592
+ const raw = portfolio;
1778
1593
  debugLog("zyfai:onboard", "wallet state from getPositions", {
1779
- predeployed: raw2?.predeployed,
1780
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1594
+ predeployed: raw?.predeployed,
1595
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1781
1596
  });
1782
1597
  return {
1783
- predeployed: raw2?.predeployed,
1784
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1598
+ predeployed: raw?.predeployed,
1599
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1785
1600
  };
1786
1601
  } catch (error) {
1787
1602
  console.warn(
@@ -2067,14 +1882,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
2067
1882
  return { txHash, smartWallet, amount };
2068
1883
  }
2069
1884
  await this.ensureWalletDeployed(this.getAddress(), validChainId);
2070
- const raw2 = await this.sdk.depositFunds(
1885
+ const raw = await this.sdk.sendDeposit(
2071
1886
  this.getAddress(),
2072
1887
  validChainId,
2073
1888
  amount,
2074
1889
  asset,
2075
1890
  "aggressive"
2076
1891
  );
2077
- return mapDeposit(raw2);
1892
+ return mapDeposit(raw);
2078
1893
  } catch (error) {
2079
1894
  throw error;
2080
1895
  }
@@ -2083,27 +1898,27 @@ var ZyfaiAgent = class _ZyfaiAgent {
2083
1898
  async withdraw(state, chainId, token, amount) {
2084
1899
  const validChainId = isValidChainId(chainId);
2085
1900
  await this.ensureConnected(state, validChainId);
2086
- const raw2 = await this.sdk.withdrawFunds(
1901
+ const raw = await this.sdk.withdrawFunds(
2087
1902
  this.getAddress(),
2088
1903
  validChainId,
2089
1904
  amount,
2090
1905
  token
2091
1906
  );
2092
- if (!raw2.success) {
1907
+ if (!raw.success) {
2093
1908
  throw new OwneyError(
2094
1909
  "WITHDRAW_FAILED",
2095
- raw2.message || "Zyfai withdraw failed.",
2096
- { chainId: validChainId, token, amount, response: raw2 },
1910
+ raw.message || "Zyfai withdraw failed.",
1911
+ { chainId: validChainId, token, amount, response: raw },
2097
1912
  this.id
2098
1913
  );
2099
1914
  }
2100
- return mapWithdraw(raw2);
1915
+ return mapWithdraw(raw);
2101
1916
  }
2102
1917
  // --- IAgent: Portfolio reads ---
2103
1918
  async getBalances(state, chainId) {
2104
1919
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
2105
- const raw2 = await this.sdk.getPortfolio(this.getAddress());
2106
- return mapBalances(raw2, validChainId, smartWallet);
1920
+ const raw = await this.sdk.getPortfolio(this.getAddress());
1921
+ return mapBalances(raw, validChainId, smartWallet);
2107
1922
  }
2108
1923
  earningsKey(state, chainId, smartWallet) {
2109
1924
  return JSON.stringify([
@@ -2116,11 +1931,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
2116
1931
  const existing = this.earningsReads.get(key2);
2117
1932
  if (existing) return existing;
2118
1933
  const generation = this.earningsGeneration;
2119
- const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw2) => {
1934
+ const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw) => {
2120
1935
  if (generation === this.earningsGeneration) {
2121
- this.earningsSnapshot = { key: key2, raw: raw2, at: Date.now() };
1936
+ this.earningsSnapshot = { key: key2, raw, at: Date.now() };
2122
1937
  }
2123
- return raw2;
1938
+ return raw;
2124
1939
  }).finally(() => {
2125
1940
  if (this.earningsReads.get(key2) === pending)
2126
1941
  this.earningsReads.delete(key2);
@@ -2130,11 +1945,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
2130
1945
  }
2131
1946
  async getEarnings(state, chainId) {
2132
1947
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
2133
- const raw2 = await this.readEarnings(
1948
+ const raw = await this.readEarnings(
2134
1949
  this.earningsKey(state, chainId, smartWallet),
2135
1950
  smartWallet
2136
1951
  );
2137
- return mapEarnings(raw2, smartWallet);
1952
+ return mapEarnings(raw, smartWallet);
2138
1953
  }
2139
1954
  async refreshEarnings(state, chainId) {
2140
1955
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
@@ -2161,17 +1976,17 @@ var ZyfaiAgent = class _ZyfaiAgent {
2161
1976
  }
2162
1977
  async getAccountApy(state, chainId, days, tokenSymbol) {
2163
1978
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
2164
- const raw2 = await this.sdk.getDailyApyHistory(smartWallet, days);
2165
- return mapApyHistory(raw2, chainId, tokenSymbol);
1979
+ const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
1980
+ return mapApyHistory(raw, chainId, tokenSymbol);
2166
1981
  }
2167
1982
  async getDailyEarnings(state, chainId, days, tokenSymbol) {
2168
1983
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
2169
1984
  const start = new Date(Date.now() - (DayFilterMapping[days] + 1) * 864e5);
2170
- const raw2 = await this.sdk.getDailyEarnings(
1985
+ const raw = await this.sdk.getDailyEarnings(
2171
1986
  smartWallet,
2172
1987
  start.toISOString().slice(0, 10)
2173
1988
  );
2174
- return mapDailyEarnings(raw2, chainId, tokenSymbol);
1989
+ return mapDailyEarnings(raw, chainId, tokenSymbol);
2175
1990
  }
2176
1991
  /**
2177
1992
  * Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
@@ -2206,7 +2021,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2206
2021
  const matched = [];
2207
2022
  let backendExhausted = false;
2208
2023
  for (let i = 0; i < MAX_BACKEND_CALLS && matched.length < limit; i++) {
2209
- const raw2 = await this.sdk.getHistory(smartWallet, validChainId, {
2024
+ const raw = await this.sdk.getHistory(smartWallet, validChainId, {
2210
2025
  limit: backendPageSize,
2211
2026
  offset,
2212
2027
  fromDate: options?.fromDate,
@@ -2217,13 +2032,13 @@ var ZyfaiAgent = class _ZyfaiAgent {
2217
2032
  // asset's rows and handing back a page that filters to nothing.
2218
2033
  assetType
2219
2034
  });
2220
- raw2.data.forEach((entry, idx) => {
2035
+ raw.data.forEach((entry, idx) => {
2221
2036
  if (entry.chainId === validChainId) {
2222
2037
  matched.push({ entry, rawIdx: offset + idx });
2223
2038
  }
2224
2039
  });
2225
- offset += raw2.data.length;
2226
- if (raw2.data.length < backendPageSize) {
2040
+ offset += raw.data.length;
2041
+ if (raw.data.length < backendPageSize) {
2227
2042
  backendExhausted = true;
2228
2043
  break;
2229
2044
  }
@@ -2245,18 +2060,18 @@ var ZyfaiAgent = class _ZyfaiAgent {
2245
2060
  }
2246
2061
  async getUserProfile(state, chainId) {
2247
2062
  await this.connectAuth(state, chainId);
2248
- const raw2 = await this.sdk.getUserDetails();
2063
+ const raw = await this.sdk.getUserDetails();
2249
2064
  debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
2250
2065
  asset: "USDC (default \u2014 no asset passed)",
2251
- splitting: raw2.splitting,
2252
- minSplits: raw2.minSplits,
2253
- strategy: raw2.strategy,
2254
- chains: raw2.chains,
2255
- protocolCount: raw2.protocols?.length,
2256
- hasActiveSessionKey: raw2.hasActiveSessionKey,
2257
- smartWallet: raw2.smartWallet
2066
+ splitting: raw.splitting,
2067
+ minSplits: raw.minSplits,
2068
+ strategy: raw.strategy,
2069
+ chains: raw.chains,
2070
+ protocolCount: raw.protocols?.length,
2071
+ hasActiveSessionKey: raw.hasActiveSessionKey,
2072
+ smartWallet: raw.smartWallet
2258
2073
  });
2259
- return mapUserProfile(raw2, this.connectedAddress);
2074
+ return mapUserProfile(raw, this.connectedAddress);
2260
2075
  }
2261
2076
  async ensureAutoSelectProtocols(state, chainId, asset) {
2262
2077
  await this.connectAuth(state, chainId);
@@ -2275,2241 +2090,111 @@ var ZyfaiAgent = class _ZyfaiAgent {
2275
2090
  }
2276
2091
  // --- IAgent: Discovery (no wallet required) ---
2277
2092
  async getAgentApy(days, options) {
2278
- const raw2 = await this.sdk.getAPYPerStrategy(
2093
+ const raw = await this.sdk.getAPYPerStrategy(
2279
2094
  false,
2280
2095
  DayFilterMapping[days],
2281
2096
  "aggressive",
2282
2097
  options?.chainId,
2283
2098
  options?.tokenSymbol
2284
2099
  );
2285
- return mapApyByStrategy(raw2);
2100
+ return mapApyByStrategy(raw);
2286
2101
  }
2287
2102
  };
2288
2103
 
2289
- // src/agents/yieldseeker/yieldseeker.agent.ts
2290
- import {
2291
- createPublicClient as createPublicClient3,
2292
- createWalletClient as createWalletClient2,
2293
- custom as custom2,
2294
- encodeFunctionData,
2295
- erc20Abi,
2296
- getAddress as getAddress2,
2297
- isAddress as isAddress2
2298
- } from "viem";
2299
- import { base as base3 } from "viem/chains";
2300
-
2301
- // src/lib/chain-guard.ts
2302
- var CHAIN_NAMES = {
2303
- 1: "Ethereum",
2304
- 8453: "Base",
2305
- 42161: "Arbitrum"
2306
- };
2307
- function chainName(chainId) {
2308
- return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
2309
- }
2310
- async function ensureWalletOnChain(pub, wallet, expected) {
2311
- const actual = await pub.getChainId();
2312
- if (actual === expected) return;
2104
+ // src/lib/routing-api.ts
2105
+ var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2106
+ async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
2107
+ const url = `${baseUrl}/api/v1/agent/org-config`;
2313
2108
  try {
2314
- await wallet.switchChain({ id: expected });
2109
+ const res = await fetch(url, {
2110
+ method: "GET",
2111
+ headers: {
2112
+ "Content-Type": "application/json",
2113
+ "x-owney-api-key": `${apiKey}`
2114
+ }
2115
+ });
2116
+ if (!res.ok) {
2117
+ if (res.status !== 404) {
2118
+ console.warn(
2119
+ `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
2120
+ );
2121
+ }
2122
+ return null;
2123
+ }
2124
+ const json = await res.json();
2125
+ const policy = json.success ? json.data ?? null : null;
2126
+ debugLog(
2127
+ "owney-sdk",
2128
+ policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
2129
+ policy ?? void 0
2130
+ );
2131
+ return policy;
2315
2132
  } catch (error) {
2133
+ console.warn(
2134
+ "[owney-sdk] Could not read org agent config (non-fatal):",
2135
+ error instanceof Error ? error.message : String(error)
2136
+ );
2137
+ return null;
2138
+ }
2139
+ }
2140
+ async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
2141
+ const url = `${baseUrl}/api/v1/agent/keys`;
2142
+ const res = await fetch(url, {
2143
+ method: "GET",
2144
+ headers: {
2145
+ "Content-Type": "application/json",
2146
+ "x-owney-api-key": `${apiKey}`
2147
+ }
2148
+ });
2149
+ if (!res.ok) {
2150
+ const text = await res.text().catch(() => "");
2316
2151
  throw new OwneyError(
2317
- "CHAIN_MISMATCH",
2318
- `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2319
- {
2320
- expectedChainId: expected,
2321
- actualChainId: actual,
2322
- cause: error instanceof Error ? error.message : String(error)
2323
- }
2152
+ "API_ROUTING_ERROR",
2153
+ `Routing API error ${res.status}: ${text}`,
2154
+ { statusCode: res.status, responseBody: text }
2324
2155
  );
2325
2156
  }
2326
- const after = await pub.getChainId();
2327
- if (after !== expected) {
2157
+ const json = await res.json();
2158
+ if (!json.success) {
2328
2159
  throw new OwneyError(
2329
- "CHAIN_MISMATCH",
2330
- `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2331
- { expectedChainId: expected, actualChainId: after }
2160
+ "API_ROUTING_FAILED",
2161
+ `Routing API request failed: ${json.message}`,
2162
+ { message: json.message }
2332
2163
  );
2333
2164
  }
2165
+ return json.data;
2334
2166
  }
2335
2167
 
2336
- // src/lib/transfer-auth.ts
2337
- import { bytesToHex } from "viem";
2338
-
2339
- // src/lib/sponsor-client.ts
2340
- var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2341
- async function postPaymasterIntent(input) {
2342
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2343
- let res;
2168
+ // src/lib/health-report.ts
2169
+ var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2170
+ async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
2344
2171
  try {
2345
- res = await fetch(`${base5}/api/v1/sponsor/paymaster-intent`, {
2172
+ await fetch(`${baseUrl}/api/v1/agent/health-report`, {
2346
2173
  method: "POST",
2347
2174
  headers: {
2348
- "content-type": "application/json",
2349
- "x-owney-api-key": input.apiKey,
2350
- Authorization: `Signature ${input.yieldseekerSignature}`
2175
+ "Content-Type": "application/json",
2176
+ "x-owney-api-key": apiKey
2351
2177
  },
2352
- body: JSON.stringify(input.body)
2178
+ body: JSON.stringify({
2179
+ agent_type: agentType,
2180
+ error_code: errorCode,
2181
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2182
+ })
2353
2183
  });
2354
- } catch (networkError) {
2355
- throw new OwneyError(
2356
- "SPONSOR_REQUEST_FAILED",
2357
- `Paymaster intent network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2358
- { cause: String(networkError), safeToFallback: true }
2359
- );
2360
- }
2361
- const text = await res.text();
2362
- let parsed = null;
2363
- try {
2364
- parsed = JSON.parse(text);
2365
- } catch {
2366
- }
2367
- if (!res.ok || !parsed?.success || typeof parsed.data?.intent !== "string" || typeof parsed.data.expiresAt !== "number") {
2368
- throw new OwneyError(
2369
- "SPONSOR_REQUEST_FAILED",
2370
- `Paymaster intent API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2371
- {
2372
- statusCode: res.status,
2373
- responseBody: text.slice(0, 500),
2374
- safeToFallback: true
2375
- }
2376
- );
2377
- }
2378
- return parsed.data;
2379
- }
2380
- async function getSponsorRelayerAddress(input) {
2381
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2382
- let res;
2383
- try {
2384
- res = await fetch(
2385
- `${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2386
- {
2387
- headers: { "x-owney-api-key": input.apiKey }
2388
- }
2389
- );
2390
- } catch (networkError) {
2391
- throw new OwneyError(
2392
- "SPONSOR_REQUEST_FAILED",
2393
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2394
- { cause: String(networkError), safeToFallback: true }
2395
- );
2396
- }
2397
- const text = await res.text();
2398
- let parsed = null;
2399
- try {
2400
- parsed = JSON.parse(text);
2401
- } catch {
2402
- }
2403
- if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
2404
- throw new OwneyError(
2405
- "SPONSOR_REQUEST_FAILED",
2406
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2407
- {
2408
- statusCode: res.status,
2409
- responseBody: text.slice(0, 500),
2410
- safeToFallback: true
2411
- }
2184
+ } catch (err) {
2185
+ console.warn(
2186
+ `[owney-sdk] health-report failed for agent "${agentType}":`,
2187
+ err instanceof Error ? err.message : err
2412
2188
  );
2413
2189
  }
2414
- return parsed.data.relayer;
2415
2190
  }
2416
- async function postSponsorBatchTransfer(input) {
2417
- let res;
2191
+ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
2418
2192
  try {
2419
- res = await fetch(
2420
- `${input.baseUrl ?? ROUTING_API_BASE_URL}/api/v1/sponsor/permit2-batch`,
2421
- {
2422
- method: "POST",
2423
- headers: {
2424
- "content-type": "application/json",
2425
- "x-owney-api-key": input.apiKey
2426
- },
2427
- body: JSON.stringify(input.body)
2428
- }
2429
- );
2430
- } catch {
2431
- throw new OwneyError(
2432
- "SPONSOR_REQUEST_FAILED",
2433
- "Deposit status is unknown. Retry the same amount to check it.",
2434
- { safeToFallback: false }
2435
- );
2436
- }
2437
- const parsed = await res.json().catch(() => null);
2438
- if (!res.ok || !parsed?.success || !/^0x[0-9a-fA-F]{64}$/.test(parsed.data?.txHash ?? "")) {
2439
- throw new OwneyError(
2440
- "SPONSOR_REQUEST_FAILED",
2441
- "Deposit could not be confirmed. Retry the same amount to check its status.",
2442
- {
2443
- statusCode: res.status,
2444
- safeToFallback: false,
2445
- notSubmitted: parsed?.notSubmitted === true || parsed?.error?.notSubmitted === true || parsed?.error?.details?.notSubmitted === true
2446
- }
2447
- );
2448
- }
2449
- return parsed.data;
2450
- }
2451
-
2452
- // src/lib/permit2.ts
2453
- import { bytesToHex as bytesToHex2 } from "viem";
2454
- var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2455
- var MAX_UINT256 = 2n ** 256n - 1n;
2456
- function permit2ApprovalAmount(requiredAmount) {
2457
- if (requiredAmount <= 0n) {
2458
- throw new Error("Permit2 approval requires a positive deposit amount");
2459
- }
2460
- return MAX_UINT256;
2461
- }
2462
- var ERC20_ALLOWANCE_ABI = [
2463
- {
2464
- type: "function",
2465
- name: "allowance",
2466
- stateMutability: "view",
2467
- inputs: [
2468
- { name: "owner", type: "address" },
2469
- { name: "spender", type: "address" }
2470
- ],
2471
- outputs: [{ name: "", type: "uint256" }]
2472
- },
2473
- {
2474
- type: "function",
2475
- name: "approve",
2476
- stateMutability: "nonpayable",
2477
- inputs: [
2478
- { name: "spender", type: "address" },
2479
- { name: "amount", type: "uint256" }
2480
- ],
2481
- outputs: [{ name: "", type: "bool" }]
2482
- },
2483
- {
2484
- type: "function",
2485
- name: "balanceOf",
2486
- stateMutability: "view",
2487
- inputs: [{ name: "account", type: "address" }],
2488
- outputs: [{ name: "", type: "uint256" }]
2489
- }
2490
- ];
2491
- function randomPermit2Nonce() {
2492
- const bytes = new Uint8Array(32);
2493
- globalThis.crypto.getRandomValues(bytes);
2494
- return BigInt(bytesToHex2(bytes));
2495
- }
2496
- async function readPermit2Allowance(publicClient, token, owner, blockNumber) {
2497
- return publicClient.readContract({
2498
- address: token,
2499
- abi: ERC20_ALLOWANCE_ABI,
2500
- functionName: "allowance",
2501
- args: [owner, PERMIT2_ADDRESS],
2502
- ...blockNumber === void 0 ? {} : { blockNumber }
2503
- });
2504
- }
2505
- async function readErc20Balance(publicClient, token, owner) {
2506
- return publicClient.readContract({
2507
- address: token,
2508
- abi: ERC20_ALLOWANCE_ABI,
2509
- functionName: "balanceOf",
2510
- args: [owner]
2511
- });
2512
- }
2513
-
2514
- // src/lib/sponsored-deposit.ts
2515
- var AUTH_WINDOW_SECONDS = 15 * 60;
2516
- var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
2517
- function provideDepositVerificationContext(callback, context) {
2518
- callback[verificationSetter]?.(context);
2519
- }
2520
- function makeVerificationAwareDepositCallback(implementation) {
2521
- let nextVerification;
2522
- const callback = async (smartWallet, chainId, amount) => {
2523
- const verification = nextVerification;
2524
- nextVerification = void 0;
2525
- return implementation(smartWallet, chainId, amount, verification);
2526
- };
2527
- Object.defineProperty(callback, verificationSetter, {
2528
- value: (context) => {
2529
- nextVerification = context;
2530
- }
2531
- });
2532
- return callback;
2533
- }
2534
-
2535
- // src/agents/yieldseeker/yieldseeker.auth.ts
2536
- import { SiweMessage, generateNonce } from "siwe";
2537
- import {
2538
- createPublicClient as createPublicClient2,
2539
- createWalletClient,
2540
- custom,
2541
- getAddress
2542
- } from "viem";
2543
- import { base as base2 } from "viem/chains";
2544
-
2545
- // src/agents/yieldseeker/yieldseeker.auth-cache.ts
2546
- var KEY_PREFIX2 = "owney.yieldseeker.session.v5";
2547
- var INVALIDATED_KEY_PREFIXES = [
2548
- "owney.yieldseeker.session",
2549
- "owney.yieldseeker.session.v3",
2550
- "owney.yieldseeker.session.v4"
2551
- ];
2552
- var storage2 = () => {
2553
- if (typeof window === "undefined") return null;
2554
- try {
2555
- return window.localStorage;
2556
- } catch {
2557
- return null;
2558
- }
2559
- };
2560
- var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2561
- var invalidatedKeys = (address, chainId) => INVALIDATED_KEY_PREFIXES.map(
2562
- (prefix) => `${prefix}:${address.toLowerCase()}:${chainId}`
2563
- );
2564
- var clearInvalidatedSessions = (store, address, chainId) => {
2565
- for (const key2 of invalidatedKeys(address, chainId)) {
2566
- memorySessions2.delete(key2);
2567
- try {
2568
- store?.removeItem(key2);
2569
- } catch {
2570
- }
2571
- }
2572
- };
2573
- var memorySessions2 = /* @__PURE__ */ new Map();
2574
- var isValidSession = (session) => {
2575
- if (!session?.token) return false;
2576
- try {
2577
- const parsed = JSON.parse(atob(session.token));
2578
- return typeof parsed.message === "string" && typeof parsed.signature === "string" && parsed.signature.startsWith("0x");
2579
- } catch {
2580
- return false;
2581
- }
2582
- };
2583
- var readYieldseekerSession = (address, chainId) => {
2584
- if (typeof window === "undefined") return null;
2585
- const key2 = buildKey2(address, chainId);
2586
- const store = storage2();
2587
- clearInvalidatedSessions(store, address, chainId);
2588
- let raw2 = null;
2589
- try {
2590
- raw2 = store?.getItem(key2) ?? null;
2591
- } catch {
2592
- raw2 = null;
2593
- }
2594
- if (raw2) {
2595
- try {
2596
- const parsed = JSON.parse(raw2);
2597
- if (isValidSession(parsed)) return parsed.token;
2598
- } catch {
2599
- }
2600
- memorySessions2.delete(key2);
2601
- try {
2602
- store?.removeItem(key2);
2603
- } catch {
2604
- }
2605
- return null;
2606
- }
2607
- const cached = memorySessions2.get(key2);
2608
- if (isValidSession(cached)) return cached.token;
2609
- if (cached) memorySessions2.delete(key2);
2610
- return null;
2611
- };
2612
- var writeYieldseekerSession = (address, chainId, token) => {
2613
- if (typeof window === "undefined") return;
2614
- const session = { token };
2615
- if (!isValidSession(session)) return;
2616
- const key2 = buildKey2(address, chainId);
2617
- memorySessions2.set(key2, session);
2618
- const store = storage2();
2619
- try {
2620
- store?.setItem(key2, JSON.stringify(session));
2621
- } catch {
2622
- }
2623
- };
2624
- var clearYieldseekerSession = (address, chainId) => {
2625
- const key2 = buildKey2(address, chainId);
2626
- memorySessions2.delete(key2);
2627
- const store = storage2();
2628
- clearInvalidatedSessions(store, address, chainId);
2629
- try {
2630
- store?.removeItem(key2);
2631
- } catch {
2632
- }
2633
- };
2634
-
2635
- // src/agents/yieldseeker/yieldseeker.auth.ts
2636
- function resolveSiweOrigin(override) {
2637
- const origin = override?.trim() || (typeof window !== "undefined" ? window.location?.origin : void 0);
2638
- if (!origin || origin === "null") {
2639
- throw new Error("Yieldseeker sign-in requires the requesting app's browser origin.");
2640
- }
2641
- const url = new URL(origin);
2642
- if (url.protocol !== "https:" && url.protocol !== "http:") {
2643
- throw new Error("Yieldseeker sign-in requires an HTTP or HTTPS app origin.");
2644
- }
2645
- if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
2646
- throw new Error("Yieldseeker SIWE override must be an origin without credentials, path, query, or fragment.");
2647
- }
2648
- return url;
2649
- }
2650
- function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
2651
- const url = resolveSiweOrigin(dependencies.origin);
2652
- return new SiweMessage({
2653
- scheme: url.protocol.slice(0, -1),
2654
- domain: url.host,
2655
- address: getAddress(address),
2656
- uri: url.origin,
2657
- version: "1",
2658
- chainId,
2659
- nonce: (dependencies.nonce ?? generateNonce)(),
2660
- issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
2661
- }).prepareMessage();
2662
- }
2663
- function encodeYieldseekerAuthToken(token) {
2664
- const bytes = new TextEncoder().encode(JSON.stringify(token));
2665
- let binary = "";
2666
- for (const byte of bytes) binary += String.fromCharCode(byte);
2667
- return btoa(binary);
2668
- }
2669
- var YieldseekerAuth = class {
2670
- constructor(dependencies = {}) {
2671
- this.dependencies = dependencies;
2672
- }
2673
- dependencies;
2674
- tokens = /* @__PURE__ */ new Map();
2675
- pending = /* @__PURE__ */ new Map();
2676
- scopes = /* @__PURE__ */ new Map();
2677
- key(state, chainId) {
2678
- return `${state.walletAddress.toLowerCase()}:${chainId}:${resolveSiweOrigin(this.dependencies.origin).origin}`;
2679
- }
2680
- async getToken(state, chainId) {
2681
- const key2 = this.key(state, chainId);
2682
- const scope = { address: state.walletAddress, chainId };
2683
- this.scopes.set(key2, scope);
2684
- const cached = this.tokens.get(key2);
2685
- if (cached) return cached;
2686
- const persisted = readYieldseekerSession(scope.address, scope.chainId);
2687
- if (persisted && this.matchesOrigin(persisted)) {
2688
- this.tokens.set(key2, persisted);
2689
- return persisted;
2690
- }
2691
- if (persisted) clearYieldseekerSession(scope.address, scope.chainId);
2692
- const inFlight = this.pending.get(key2);
2693
- if (inFlight) return inFlight;
2694
- const request = this.sign(state, chainId).then((token) => {
2695
- if (this.pending.get(key2) !== request) throw new Error("Wallet sign-in session changed. Please try again.");
2696
- this.tokens.set(key2, token);
2697
- writeYieldseekerSession(scope.address, scope.chainId, token);
2698
- return token;
2699
- });
2700
- this.pending.set(key2, request);
2701
- try {
2702
- return await request;
2703
- } finally {
2704
- if (this.pending.get(key2) === request) this.pending.delete(key2);
2705
- }
2706
- }
2707
- async refreshToken(state, chainId, rejectedToken) {
2708
- const key2 = this.key(state, chainId);
2709
- if (this.tokens.get(key2) === rejectedToken) {
2710
- this.tokens.delete(key2);
2711
- clearYieldseekerSession(state.walletAddress, chainId);
2712
- }
2713
- return this.getToken(state, chainId);
2714
- }
2715
- matchesOrigin(token) {
2716
- try {
2717
- const message = new SiweMessage(JSON.parse(atob(token)).message);
2718
- const url = resolveSiweOrigin(this.dependencies.origin);
2719
- return message.domain === url.host && message.uri === url.origin && message.scheme === url.protocol.slice(0, -1);
2720
- } catch {
2721
- return false;
2722
- }
2723
- }
2724
- clear(state, chainId) {
2725
- if (!state || chainId === void 0) {
2726
- for (const scope of this.scopes.values()) {
2727
- clearYieldseekerSession(scope.address, scope.chainId);
2728
- }
2729
- this.tokens.clear();
2730
- this.pending.clear();
2731
- this.scopes.clear();
2732
- return;
2733
- }
2734
- const key2 = this.key(state, chainId);
2735
- this.tokens.delete(key2);
2736
- this.pending.delete(key2);
2737
- this.scopes.delete(key2);
2738
- clearYieldseekerSession(state.walletAddress, chainId);
2739
- }
2740
- async sign(state, chainId) {
2741
- const account = getAddress(state.walletAddress);
2742
- const publicClient = createPublicClient2({
2743
- chain: base2,
2744
- transport: custom(state.provider)
2745
- });
2746
- const walletClient = createWalletClient({
2747
- account,
2748
- chain: base2,
2749
- transport: custom(state.provider)
2750
- });
2751
- await ensureWalletOnChain(
2752
- publicClient,
2753
- walletClient,
2754
- 8453
2755
- );
2756
- const message = createYieldseekerSiweMessage(
2757
- account,
2758
- chainId,
2759
- this.dependencies
2760
- );
2761
- const signature = await walletClient.signMessage({ account, message });
2762
- return encodeYieldseekerAuthToken({ message, signature });
2763
- }
2764
- };
2765
-
2766
- // src/agents/yieldseeker/yieldseeker.identity-cache.ts
2767
- var KEY_PREFIX3 = "owney.yieldseeker.identity.v1";
2768
- var YIELDSEEKER_IDENTITY_TTL_MS = 24 * 60 * 60 * 1e3;
2769
- var memoryIdentities = /* @__PURE__ */ new Map();
2770
- var storage3 = () => {
2771
- if (typeof window === "undefined") return null;
2772
- try {
2773
- return window.localStorage;
2774
- } catch {
2775
- return null;
2776
- }
2777
- };
2778
- var keyFor = (walletAddress, chainId) => `${KEY_PREFIX3}:${walletAddress.toLowerCase()}:${chainId}`;
2779
- function valid(value, walletAddress, chainId, now) {
2780
- return Boolean(
2781
- 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
2782
- );
2783
- }
2784
- function readYieldseekerIdentity(walletAddress, chainId, now = Date.now()) {
2785
- if (typeof window === "undefined") return null;
2786
- const key2 = keyFor(walletAddress, chainId);
2787
- const store = storage3();
2788
- let parsed = null;
2789
- try {
2790
- const raw2 = store?.getItem(key2);
2791
- parsed = raw2 ? JSON.parse(raw2) : null;
2792
- } catch {
2793
- parsed = null;
2794
- }
2795
- const candidate = parsed ?? memoryIdentities.get(key2);
2796
- if (valid(candidate, walletAddress, chainId, now)) {
2797
- memoryIdentities.set(key2, candidate);
2798
- return { userId: candidate.userId };
2799
- }
2800
- memoryIdentities.delete(key2);
2801
- try {
2802
- store?.removeItem(key2);
2803
- } catch {
2804
- }
2805
- return null;
2806
- }
2807
- function writeYieldseekerIdentity(walletAddress, chainId, userId, now = Date.now()) {
2808
- if (typeof window === "undefined") return;
2809
- const identity = {
2810
- userId,
2811
- walletAddress,
2812
- chainId,
2813
- expiresAt: now + YIELDSEEKER_IDENTITY_TTL_MS
2814
- };
2815
- if (!valid(identity, walletAddress, chainId, now)) return;
2816
- const key2 = keyFor(walletAddress, chainId);
2817
- memoryIdentities.set(key2, identity);
2818
- try {
2819
- storage3()?.setItem(key2, JSON.stringify(identity));
2820
- } catch {
2821
- }
2822
- }
2823
- function clearYieldseekerIdentity(walletAddress, chainId) {
2824
- const key2 = keyFor(walletAddress, chainId);
2825
- memoryIdentities.delete(key2);
2826
- try {
2827
- storage3()?.removeItem(key2);
2828
- } catch {
2829
- }
2830
- }
2831
-
2832
- // src/agents/yieldseeker/yieldseeker.client.ts
2833
- var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2834
- function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
2835
- return `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/agent/yieldseeker`;
2836
- }
2837
- var YIELDSEEKER_API_BASE_URL = getYieldseekerProxyBaseUrl();
2838
- var YieldseekerApiError = class extends Error {
2839
- constructor(status, providerCode, responseFields) {
2840
- super(`Yieldseeker request failed (${status}): ${providerCode}`);
2841
- this.status = status;
2842
- this.providerCode = providerCode;
2843
- this.responseFields = responseFields;
2844
- this.name = "YieldseekerApiError";
2845
- }
2846
- status;
2847
- providerCode;
2848
- responseFields;
2849
- get isAuthenticationError() {
2850
- return this.status === 401 || this.status === 403;
2851
- }
2852
- };
2853
- function providerError(body, fallback) {
2854
- if (!body || typeof body !== "object") return { code: fallback };
2855
- const record = body;
2856
- return {
2857
- code: typeof record.message === "string" ? record.message : fallback,
2858
- fields: record.fields && typeof record.fields === "object" ? record.fields : void 0
2859
- };
2860
- }
2861
- var YieldseekerApiClient = class {
2862
- constructor(owneyApiKey, baseUrl = YIELDSEEKER_API_BASE_URL, fetchFn = fetch.bind(globalThis)) {
2863
- this.owneyApiKey = owneyApiKey;
2864
- this.baseUrl = baseUrl;
2865
- this.fetchFn = fetchFn;
2866
- }
2867
- owneyApiKey;
2868
- baseUrl;
2869
- fetchFn;
2870
- async request(path, options = {}) {
2871
- const controller = new AbortController();
2872
- const timer = setTimeout(
2873
- () => controller.abort(),
2874
- options.timeoutMs ?? 15e3
2875
- );
2876
- try {
2877
- const response = await this.fetchFn(`${this.baseUrl}${path}`, {
2878
- method: options.method ?? "GET",
2879
- headers: {
2880
- "Content-Type": "application/json",
2881
- "x-owney-api-key": this.owneyApiKey,
2882
- ...options.signature ? { Authorization: `Signature ${options.signature}` } : {}
2883
- },
2884
- body: options.body ? JSON.stringify(options.body) : void 0,
2885
- signal: controller.signal
2886
- });
2887
- const payload = await response.json().catch(() => null);
2888
- if (!response.ok) {
2889
- const error = providerError(payload, `HTTP_${response.status}`);
2890
- const retryAfter = response.headers.get("Retry-After");
2891
- throw new YieldseekerApiError(
2892
- response.status,
2893
- error.code,
2894
- retryAfter ? { ...error.fields, headers: { "Retry-After": retryAfter } } : error.fields
2895
- );
2896
- }
2897
- if (payload && typeof payload === "object" && payload.success === true && "data" in payload) {
2898
- return payload.data;
2899
- }
2900
- return payload;
2901
- } catch (error) {
2902
- if (error instanceof YieldseekerApiError) throw error;
2903
- if (error instanceof DOMException && error.name === "AbortError") {
2904
- throw new YieldseekerApiError(408, "REQUEST_TIMEOUT");
2905
- }
2906
- throw new YieldseekerApiError(0, "NETWORK_ERROR", {
2907
- cause: error instanceof Error ? error.message : String(error)
2908
- });
2909
- } finally {
2910
- clearTimeout(timer);
2911
- }
2912
- }
2913
- };
2914
-
2915
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2916
- import { formatUnits, isAddress } from "viem";
2917
-
2918
- // src/lib/helpers/snapshot-apy.ts
2919
- var DAY_MS = 864e5;
2920
- function snapshotTime(date) {
2921
- if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return void 0;
2922
- const time = Date.parse(date);
2923
- return Number.isFinite(time) && new Date(time).toISOString().slice(0, 10) === date ? time : void 0;
2924
- }
2925
- function returnFactor(value) {
2926
- if (typeof value !== "number" && typeof value !== "string") return void 0;
2927
- if (typeof value === "string" && value.trim() === "") return void 0;
2928
- const factor = Number(value);
2929
- return Number.isFinite(factor) && factor >= 0 ? factor : void 0;
2930
- }
2931
- function calculateSnapshotApy(snapshots, lookbackDays, now = Date.now()) {
2932
- if (!Number.isFinite(lookbackDays) || lookbackDays <= 0 || !Number.isFinite(now)) {
2933
- return void 0;
2934
- }
2935
- const points = snapshots.flatMap((snapshot) => {
2936
- const time = snapshotTime(snapshot.date);
2937
- return time !== void 0 && time <= now ? [{ snapshot, time }] : [];
2938
- }).sort((a, b) => a.time - b.time);
2939
- const end = points.at(-1);
2940
- if (!end) return void 0;
2941
- const cutoff = end.time - lookbackDays * DAY_MS;
2942
- const start = points.find((point) => point.time >= cutoff);
2943
- const actualDays = (end.time - start.time) / DAY_MS;
2944
- if (actualDays <= 0) return void 0;
2945
- const startFactor = returnFactor(start.snapshot.cumulativeReturnFactor);
2946
- const endFactor = returnFactor(end.snapshot.cumulativeReturnFactor);
2947
- if (startFactor === void 0 || startFactor === 0 || endFactor === void 0) {
2948
- return void 0;
2949
- }
2950
- const periodReturn = endFactor / startFactor - 1;
2951
- const apy = Math.pow(1 + periodReturn, 365 / actualDays) - 1;
2952
- return Number.isFinite(apy) ? apy : void 0;
2953
- }
2954
-
2955
- // src/agents/yieldseeker/yieldseeker.types.ts
2956
- var YIELDSEEKER_ASSET_METADATA = {
2957
- USDC: {
2958
- address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
2959
- decimals: 6
2960
- },
2961
- WETH: {
2962
- address: "0x4200000000000000000000000000000000000006",
2963
- decimals: 18
2964
- }
2965
- };
2966
-
2967
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2968
- function invalid(endpoint, detail) {
2969
- throw new OwneyError(
2970
- "AGENT_INVALID_RESPONSE",
2971
- `Yieldseeker returned an invalid ${endpoint} response: ${detail}.`,
2972
- { endpoint, detail },
2973
- "yieldseeker"
2974
- );
2975
- }
2976
- function raw(value, endpoint) {
2977
- if (typeof value !== "string" || !/^-?[0-9]+$/.test(value)) {
2978
- return invalid(endpoint, "expected a base-10 integer string");
2979
- }
2980
- return BigInt(value);
2981
- }
2982
- function decimal(value, decimals, endpoint) {
2983
- return formatUnits(raw(value, endpoint), decimals);
2984
- }
2985
- function usd(rawAmount, decimals, price) {
2986
- return Number(formatUnits(rawAmount, decimals)) * price;
2987
- }
2988
- function percent(value) {
2989
- const result = Number(value);
2990
- return Number.isFinite(result) ? result * 100 : 0;
2991
- }
2992
- var YIELDSEEKER_POSITIVE_YIELD_FEE_RATE = 0.1;
2993
- function publicApyAfterYieldseekerFee(value) {
2994
- const grossPercent = percent(value);
2995
- if (grossPercent <= 0) return grossPercent;
2996
- const netPercent = grossPercent * (1 - YIELDSEEKER_POSITIVE_YIELD_FEE_RATE);
2997
- return Math.round(netPercent * 1e12) / 1e12;
2998
- }
2999
- function riskAdjustedApyForDays(option, days) {
3000
- if (days === "7D") return option.riskAdjustedApy7dAverage;
3001
- if (days === "30D") return option.riskAdjustedApy30dAverage;
3002
- return (option.riskAdjustedApy7dAverage + option.riskAdjustedApy30dAverage) / 2;
3003
- }
3004
- function assetAddressValue(record, address) {
3005
- const entry = Object.entries(record).find(
3006
- ([key2]) => key2.toLowerCase() === address.toLowerCase()
3007
- );
3008
- return entry?.[1] ?? "0";
3009
- }
3010
- function position(value, asset, baseAssetDecimals) {
3011
- const option = value?.yieldOption;
3012
- if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !isAddress(option.address)) {
3013
- return invalid("yield positions", "missing vault metadata");
3014
- }
3015
- return {
3016
- chain: "BASE",
3017
- protocol: option.provider,
3018
- protocolId: option.address,
3019
- pool: option.name,
3020
- asset,
3021
- // `assetsRaw` is the ERC-4626 vault-share quantity, whose decimals can
3022
- // differ from the underlying asset. Yieldseeker already converts it to
3023
- // underlying base-asset units in `assetsBase`; pair that value with the
3024
- // snapshot's corresponding `baseAssetDecimals` for display. Keep the raw
3025
- // share quantity separate from the withdrawable underlying asset amount.
3026
- amount: decimal(
3027
- value.assetsBase,
3028
- baseAssetDecimals,
3029
- "yield positions"
3030
- ),
3031
- amountRaw: String(value.assetsRaw),
3032
- withdrawableAmountRaw: String(value.withdrawableAssetsRaw),
3033
- apy: percent(option.riskAdjustedApy),
3034
- tvl: Number(option.totalDepositsUsd),
3035
- liquidity: Number(option.withdrawableDepositsUsd)
3036
- };
3037
- }
3038
- function mapYieldseekerBalances(contexts) {
3039
- const tokens = [];
3040
- const assetBalances = [];
3041
- const positions = [];
3042
- let totalUsd = 0;
3043
- for (const context of contexts) {
3044
- const metadata = YIELDSEEKER_ASSET_METADATA[context.asset];
3045
- assetBalances.push({
3046
- chain: "BASE",
3047
- chainId: 8453,
3048
- asset: context.asset,
3049
- amount: decimal(context.snapshot.totalValueBase, context.snapshot.baseAssetDecimals, "snapshot")
3050
- });
3051
- const idle = assetAddressValue(
3052
- context.snapshot.tokenBalances,
3053
- metadata.address
3054
- );
3055
- tokens.push({
3056
- chain: "BASE",
3057
- chainId: 8453,
3058
- asset: context.asset,
3059
- amount: decimal(idle, metadata.decimals, "snapshot")
3060
- });
3061
- positions.push(
3062
- ...context.positions.map(
3063
- (entry) => position(
3064
- entry,
3065
- context.asset,
3066
- context.snapshot.baseAssetDecimals
3067
- )
3068
- )
3069
- );
3070
- totalUsd += usd(
3071
- raw(context.snapshot.totalValueBase, "snapshot"),
3072
- context.snapshot.baseAssetDecimals,
3073
- context.snapshot.baseAssetPriceUsd
3074
- );
3075
- }
3076
- return {
3077
- ...contexts.length === 1 ? { smartWallet: contexts[0].wallet.walletAddress } : {},
3078
- totalBalance: String(totalUsd),
3079
- totalBalanceAsset: "usdc",
3080
- assetBalances,
3081
- tokens,
3082
- positions
3083
- };
3084
- }
3085
- function mapYieldseekerEarnings(contexts) {
3086
- const tokens = [];
3087
- let lifetimeEarnings = 0;
3088
- for (const context of contexts) {
3089
- const amount = raw(context.snapshot.cumulativeYieldBase, "snapshot");
3090
- tokens.push({
3091
- chain: "BASE",
3092
- chainId: 8453,
3093
- asset: context.asset,
3094
- amount: formatUnits(amount, context.snapshot.baseAssetDecimals)
3095
- });
3096
- lifetimeEarnings += usd(
3097
- amount,
3098
- context.snapshot.baseAssetDecimals,
3099
- context.snapshot.baseAssetPriceUsd
3100
- );
3101
- }
3102
- return {
3103
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
3104
- lifetimeEarnings,
3105
- tokens
3106
- };
3107
- }
3108
- function apyForDays(context, days, now) {
3109
- if (days === "7D") return percent(context.snapshot.apy7d);
3110
- if (days === "30D") return percent(context.snapshot.apy30d);
3111
- const apy = calculateSnapshotApy(context.historic?.dailyYieldSnapshots ?? [], 14, now);
3112
- const apyPercent = apy === void 0 ? void 0 : apy * 100;
3113
- return apyPercent !== void 0 && Number.isFinite(apyPercent) ? apyPercent : void 0;
3114
- }
3115
- function dailyApy(point) {
3116
- const total = raw(point.totalValueBase, "historic position");
3117
- const earned = raw(point.dailyYieldBase, "historic position");
3118
- const principal = total - earned;
3119
- if (principal <= 0n || earned === 0n) return 0;
3120
- return Number(earned) / Number(principal) * 365 * 100;
3121
- }
3122
- function aggregateHistory(contexts, dayCount, now) {
3123
- const today = new Date(now).toISOString().slice(0, 10);
3124
- const cutoff = new Date(Date.parse(today) - (dayCount - 1) * 864e5).toISOString().slice(0, 10);
3125
- const assets = new Set(contexts.map((context) => context.asset.toUpperCase()));
3126
- const unit = assets.size === 1 ? [...assets][0] : "USD";
3127
- const byDate = /* @__PURE__ */ new Map();
3128
- for (const context of contexts) {
3129
- const points = context.historic?.dailyYieldSnapshots ?? [];
3130
- for (const point of points) {
3131
- if (!/^\d{4}-\d{2}-\d{2}$/.test(point.date) || !Number.isFinite(Date.parse(point.date)) || point.date < cutoff || point.date > today) continue;
3132
- const tokens = Number(decimal(point.totalValueBase, point.baseAssetDecimals, "historic position"));
3133
- const amount = assets.size === 1 ? tokens : tokens * point.baseAssetPriceUsd;
3134
- if (!Number.isFinite(amount) || amount < 0) {
3135
- invalid("historic position", "expected a finite non-negative balance");
3136
- }
3137
- const current = byDate.get(point.date) ?? { weighted: 0, amount: 0 };
3138
- current.weighted += dailyApy(point) * amount;
3139
- current.amount += amount;
3140
- byDate.set(point.date, current);
3141
- }
3142
- }
3143
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
3144
- date,
3145
- apy: value.amount > 0 ? value.weighted / value.amount : 0,
3146
- historicalBalance: { amount: value.amount, unit }
3147
- }));
3148
- }
3149
- function mapYieldseekerApy(walletAddress, contexts, days, now = Date.now()) {
3150
- let weighted = 0;
3151
- let totalUsd = 0;
3152
- const byAsset = {};
3153
- for (const context of contexts) {
3154
- const valueUsd = usd(
3155
- raw(context.snapshot.totalValueBase, "snapshot"),
3156
- context.snapshot.baseAssetDecimals,
3157
- context.snapshot.baseAssetPriceUsd
3158
- );
3159
- const apy = apyForDays(context, days, now);
3160
- if (apy === void 0) continue;
3161
- weighted += apy * valueUsd;
3162
- totalUsd += valueUsd;
3163
- byAsset[context.asset] = apy;
3164
- }
3165
- const dayCount = Number(days.slice(0, -1));
3166
- return {
3167
- walletAddress,
3168
- ...days !== "14D" || Object.keys(byAsset).length > 0 ? { weightedApyAfterFee: totalUsd > 0 ? weighted / totalUsd : 0 } : {},
3169
- apyByChainAndAsset: { 8453: byAsset },
3170
- history: aggregateHistory(contexts, dayCount, now)
3171
- };
3172
- }
3173
- function actionType(value) {
3174
- const normalized = value.toLowerCase();
3175
- if (normalized.includes("deposit")) return "Deposit";
3176
- if (normalized.includes("withdraw")) return "Withdraw";
3177
- if (normalized.includes("yield") || normalized.includes("earn"))
3178
- return "Earned";
3179
- return "Rebalance";
3180
- }
3181
- function transactionHashes(details) {
3182
- if (!details) return [];
3183
- const values = [
3184
- details.transactionHash,
3185
- details.txHash,
3186
- ...Array.isArray(details.transactionHashes) ? details.transactionHashes : [],
3187
- ...Array.isArray(details.txHashes) ? details.txHashes : []
3188
- ];
3189
- return values.filter(
3190
- (value) => typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value)
3191
- ).filter((value, index, all) => all.indexOf(value) === index);
3192
- }
3193
- function actionEntry(action) {
3194
- if (action.actionType.toLowerCase().includes("withdraw")) return void 0;
3195
- return {
3196
- agent: "yieldseeker",
3197
- action: actionType(action.actionType),
3198
- date: action.createdDate,
3199
- oldApy: null,
3200
- newApy: null,
3201
- transactions: [
3202
- {
3203
- txHashes: transactionHashes(action.details),
3204
- chainId: 8453
3205
- }
3206
- ],
3207
- rebalanceLog: []
3208
- };
3209
- }
3210
- function depositDestination(context, movement) {
3211
- const to = movement.toAddress.toLowerCase();
3212
- const option = context.positions.find(({ yieldOption }) => yieldOption.chainId === movement.chainId && yieldOption.assetAddress.toLowerCase() === context.agent.assetAddress.toLowerCase() && yieldOption.address.toLowerCase() === to)?.yieldOption;
3213
- if (option) return { protocol: option.provider || "Vault", pool: option.name, tokenSymbol: context.asset };
3214
- const receipt = context.historic?.assets.find((asset) => asset.chainId === movement.chainId && !asset.isSpam && asset.address.toLowerCase() === to && asset.address.toLowerCase() !== context.agent.assetAddress.toLowerCase());
3215
- 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);
3216
- if (receipt && minted) return { protocol: "Vault", pool: receipt.name || receipt.symbol, tokenSymbol: context.asset };
3217
- return void 0;
3218
- }
3219
- function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddresses, destination) {
3220
- const from = movement.fromAddress.toLowerCase();
3221
- const to = movement.toAddress.toLowerCase();
3222
- const owner = ownerAddress.toLowerCase();
3223
- const agentWallet = wallet.walletAddress.toLowerCase();
3224
- const baseAsset = agent.assetAddress.toLowerCase();
3225
- if (movement.chainId !== agent.chainId || movement.assetAddress.toLowerCase() !== baseAsset) {
3226
- return void 0;
3227
- }
3228
- let action;
3229
- if (to === agentWallet && !vaultAddresses.has(from)) {
3230
- action = "Top up";
3231
- } else if (from === agentWallet && to === owner) {
3232
- action = "Withdraw";
3233
- } else if (from === agentWallet && destination) {
3234
- action = "Deposit";
3235
- }
3236
- if (!action) return void 0;
3237
- return {
3238
- agent: "yieldseeker",
3239
- action,
3240
- ...action === "Deposit" && destination ? { positions: [{
3241
- ...destination,
3242
- amount: decimal(movement.assetAmount, YIELDSEEKER_ASSET_METADATA[asset].decimals, "historic position")
3243
- }] } : {},
3244
- date: movement.blockDate,
3245
- oldApy: null,
3246
- newApy: null,
3247
- transactions: [
3248
- {
3249
- txHashes: [movement.transactionHash],
3250
- chainId: agent.chainId,
3251
- tokenSymbol: asset,
3252
- amount: decimal(
3253
- movement.assetAmount,
3254
- YIELDSEEKER_ASSET_METADATA[asset].decimals,
3255
- "historic position"
3256
- )
3257
- }
3258
- ],
3259
- rebalanceLog: []
3260
- };
3261
- }
3262
- function mapYieldseekerHistory(contexts, options) {
3263
- const entries = contexts.flatMap((context) => {
3264
- const seenMovements = /* @__PURE__ */ new Set();
3265
- const movements = (context.historic?.movements ?? []).filter((movement) => {
3266
- const key2 = `${movement.chainId}:${movement.transactionHash.toLowerCase()}:${movement.logIndex}`;
3267
- if (seenMovements.has(key2)) return false;
3268
- seenMovements.add(key2);
3269
- return true;
3270
- });
3271
- return [
3272
- ...movements.map(
3273
- (movement) => movementEntry(
3274
- movement,
3275
- context.wallet,
3276
- context.agent,
3277
- context.asset,
3278
- options.ownerAddress,
3279
- options.vaultAddresses,
3280
- depositDestination(context, movement)
3281
- )
3282
- ),
3283
- ...(context.actions ?? []).map(actionEntry)
3284
- ].filter((entry) => entry !== void 0);
3285
- });
3286
- const grouped = /* @__PURE__ */ new Map();
3287
- const ungrouped = [];
3288
- for (const entry of entries) {
3289
- const tx = entry.transactions[0];
3290
- const hash = tx?.txHashes[0];
3291
- if (!hash) {
3292
- ungrouped.push(entry);
3293
- continue;
3294
- }
3295
- const key2 = `${entry.agent}:${entry.action}:${tx.chainId}:${hash.toLowerCase()}`;
3296
- const previous = grouped.get(key2);
3297
- if (!previous) {
3298
- grouped.set(key2, entry);
3299
- continue;
3300
- }
3301
- if (entry.action === "Deposit" && entry.positions?.length) {
3302
- if (!previous.positions?.length) {
3303
- grouped.set(key2, entry);
3304
- continue;
3305
- }
3306
- previous.positions.push(...entry.positions);
3307
- previous.transactions.push(...entry.transactions);
3308
- }
3309
- }
3310
- 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));
3311
- return {
3312
- data: filtered.slice(0, options.limit),
3313
- // v1 returns the whole action/movement collection and defines no cursor.
3314
- // Report a terminal page so callers never loop over the same prefix.
3315
- hasMore: false
3316
- };
3317
- }
3318
- function mapYieldseekerProfile(address, contexts) {
3319
- const protocols = /* @__PURE__ */ new Set();
3320
- for (const context of contexts) {
3321
- for (const current of context.positions) {
3322
- if (current.yieldOption?.provider) {
3323
- protocols.add(String(current.yieldOption.provider));
3324
- }
3325
- }
3326
- }
3327
- return {
3328
- address,
3329
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
3330
- chains: contexts.length > 0 ? [8453] : [],
3331
- hasActiveSessionKey: contexts.some(
3332
- (context) => context.wallet.initializedDate != null
3333
- ),
3334
- protocols: [...protocols]
3335
- };
3336
- }
3337
- function mapYieldseekerAgentApy(options, days) {
3338
- const perAsset = {};
3339
- const all = [];
3340
- for (const entry of options) {
3341
- const apys = entry.yieldOptions.map(
3342
- (option) => publicApyAfterYieldseekerFee(riskAdjustedApyForDays(option, days))
3343
- ).filter(Number.isFinite);
3344
- if (apys.length === 0) continue;
3345
- const average = apys.reduce((sum, value) => sum + value, 0) / apys.length;
3346
- perAsset[entry.asset] = average;
3347
- all.push(average);
3348
- }
3349
- return {
3350
- averageApy: all.length > 0 ? all.reduce((sum, value) => sum + value, 0) / all.length : 0,
3351
- detailedApys: { apyPerAsset: { 8453: perAsset } }
3352
- };
3353
- }
3354
-
3355
- // src/agents/yieldseeker/yieldseeker.agent.ts
3356
- var OWNEY_AGENT_NAME = "owney";
3357
- var YIELDSEEKER_USERNAME_PREFIX = "owney_";
3358
- var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
3359
- var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
3360
- var YIELDSEEKER_YIELD_OPTIONS_CACHE_MS = 6e4;
3361
- var YIELDSEEKER_AGENT_LIST_CACHE_MS = 12e4;
3362
- var YIELDSEEKER_PORTFOLIO_CACHE_MS = 12e4;
3363
- var YIELDSEEKER_SETTLEMENT_CACHE_MS = 5e3;
3364
- var YIELDSEEKER_SETTLEMENT_ACTIVITY_CACHE_MS = 15e3;
3365
- var YIELDSEEKER_READ_FAILURE_COOLDOWN_MS = 6e4;
3366
- var YIELDSEEKER_SETTLEMENT_WINDOW_MS = 5 * 6e4;
3367
- var YIELDSEEKER_ACTIVITY_CACHE_MS = 6e4;
3368
- function generateYieldseekerUsername() {
3369
- const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
3370
- return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
3371
- }
3372
- function isUsernameConflict(error) {
3373
- if (!(error instanceof YieldseekerApiError)) return false;
3374
- const code = error.providerCode.toUpperCase();
3375
- return code.includes("USERNAME") && (code.includes("TAKEN") || code.includes("EXIST") || code.includes("UNAVAILABLE") || code.includes("IN_USE"));
3376
- }
3377
- var YIELDSEEKER_AGENT_WALLET_ABI = [
3378
- {
3379
- type: "function",
3380
- name: "withdrawAssetToUser",
3381
- stateMutability: "nonpayable",
3382
- inputs: [
3383
- { name: "recipient", type: "address" },
3384
- { name: "asset", type: "address" },
3385
- { name: "amount", type: "uint256" }
3386
- ],
3387
- outputs: []
3388
- },
3389
- {
3390
- type: "function",
3391
- name: "withdrawAllAssetToUser",
3392
- stateMutability: "nonpayable",
3393
- inputs: [
3394
- { name: "recipient", type: "address" },
3395
- { name: "asset", type: "address" }
3396
- ],
3397
- outputs: []
3398
- }
3399
- ];
3400
- function query(params) {
3401
- const search = new URLSearchParams();
3402
- for (const [key2, value] of Object.entries(params)) {
3403
- if (value !== void 0) search.set(key2, String(value));
3404
- }
3405
- const encoded = search.toString();
3406
- return encoded ? `?${encoded}` : "";
3407
- }
3408
- var YieldseekerAgent = class {
3409
- id = "yieldseeker";
3410
- balanceComposition = "tokens-plus-positions";
3411
- withdrawalRequiresWalletApproval = true;
3412
- supportedChainIds = [8453];
3413
- supportedAssets = [
3414
- {
3415
- chainId: 8453,
3416
- chain: "BASE",
3417
- assets: [
3418
- { symbol: "USDC", minDepositAmount: "10000000" },
3419
- { symbol: "WETH", minDepositAmount: "1" }
3420
- ]
3421
- }
3422
- ];
3423
- api;
3424
- auth;
3425
- rpcUrls;
3426
- receiptClient;
3427
- transactionExecutor;
3428
- unwindReceiptWaiter;
3429
- agentContexts = /* @__PURE__ */ new Map();
3430
- users = /* @__PURE__ */ new Map();
3431
- pendingAgents = /* @__PURE__ */ new Map();
3432
- pendingWalletContexts = /* @__PURE__ */ new Map();
3433
- readCache = /* @__PURE__ */ new Map();
3434
- pendingReads = /* @__PURE__ */ new Map();
3435
- readGeneration = 0;
3436
- portfolioVersions = /* @__PURE__ */ new Map();
3437
- snapshotFailures = /* @__PURE__ */ new Map();
3438
- standardReadFailures = /* @__PURE__ */ new Map();
3439
- reconcileUntil = /* @__PURE__ */ new Map();
3440
- activityRefreshUntil = /* @__PURE__ */ new Map();
3441
- // null means a confirmed movement has no reliable baseline. Do not guess
3442
- // settlement; keep slow reconciliation after the fast window expires.
3443
- snapshotMovements = /* @__PURE__ */ new Map();
3444
- movementEpochs = /* @__PURE__ */ new Map();
3445
- yieldOptions = /* @__PURE__ */ new Map();
3446
- pendingYieldOptions = /* @__PURE__ */ new Map();
3447
- constructor(owneyApiKey, options = {}) {
3448
- this.api = new YieldseekerApiClient(
3449
- owneyApiKey,
3450
- options.baseUrl ?? getYieldseekerProxyBaseUrl(),
3451
- options.fetchFn
3452
- );
3453
- this.auth = new YieldseekerAuth(options.auth);
3454
- this.rpcUrls = options.rpcUrls;
3455
- this.transactionExecutor = options.transactionExecutor;
3456
- this.unwindReceiptWaiter = options.unwindReceiptWaiter;
3457
- }
3458
- getReceiptClient() {
3459
- this.receiptClient ??= createPaidRpcClient(base3, this.rpcUrls);
3460
- return this.receiptClient;
3461
- }
3462
- async disconnect() {
3463
- this.readGeneration += 1;
3464
- this.auth.clear();
3465
- for (const key2 of this.users.keys()) {
3466
- const [walletAddress, chainId] = key2.split(":");
3467
- clearYieldseekerIdentity(walletAddress, Number(chainId));
3468
- }
3469
- this.users.clear();
3470
- this.agentContexts.clear();
3471
- this.pendingAgents.clear();
3472
- this.pendingWalletContexts.clear();
3473
- this.readCache.clear();
3474
- this.pendingReads.clear();
3475
- this.portfolioVersions.clear();
3476
- this.snapshotFailures.clear();
3477
- this.standardReadFailures.clear();
3478
- this.reconcileUntil.clear();
3479
- this.activityRefreshUntil.clear();
3480
- this.snapshotMovements.clear();
3481
- this.movementEpochs.clear();
3482
- }
3483
- async activateAgent(state, chainId, asset) {
3484
- this.assertChain(chainId);
3485
- const targetAsset = asset ?? "USDC";
3486
- this.assertAsset(targetAsset);
3487
- await this.ensureAgent(state, chainId, targetAsset);
3488
- }
3489
- async deposit(state, chainId, amount, asset, depositCallback) {
3490
- this.assertChain(chainId);
3491
- this.assertAsset(asset);
3492
- if (BigInt(amount) <= 0n) {
3493
- throw new OwneyError(
3494
- "DEPOSIT_AMOUNT_BELOW_MINIMUM",
3495
- "Yieldseeker deposits must be greater than zero.",
3496
- { amount, minDepositAmount: "1" },
3497
- this.id
3498
- );
3499
- }
3500
- const context = await this.ensureAgent(state, chainId, asset);
3501
- const generation = this.readGeneration;
3502
- const movement = this.snapshotMovement(state, chainId, context, BigInt(amount));
3503
- let txHash;
3504
- if (depositCallback) {
3505
- provideDepositVerificationContext(depositCallback, {
3506
- agentId: "yieldseeker",
3507
- signature: await this.auth.getToken(state, chainId),
3508
- userId: context.user.userId,
3509
- yieldseekerAgentId: context.agent.agentId
3510
- });
3511
- txHash = await depositCallback(
3512
- context.wallet.walletAddress,
3513
- chainId,
3514
- amount
3515
- );
3516
- await this.waitForReceipt(state, chainId, txHash);
3517
- } else {
3518
- txHash = await this.submitTransaction(state, chainId, {
3519
- from: getAddress2(state.walletAddress),
3520
- to: YIELDSEEKER_ASSET_METADATA[asset].address,
3521
- data: encodeFunctionData({
3522
- abi: erc20Abi,
3523
- functionName: "transfer",
3524
- args: [getAddress2(context.wallet.walletAddress), BigInt(amount)]
3525
- }),
3526
- value: "0",
3527
- chainId
3528
- });
3529
- }
3530
- if (this.readGeneration === generation) {
3531
- await this.refreshSnapshotAfterMovement(state, chainId, context, "deposit", movement);
3532
- }
3533
- return {
3534
- txHash,
3535
- smartWallet: context.wallet.walletAddress,
3536
- amount
3537
- };
3538
- }
3539
- async withdraw(state, chainId, asset, amount) {
3540
- this.assertChain(chainId);
3541
- this.assertAsset(asset);
3542
- if (amount !== void 0 && BigInt(amount) <= 0n) {
3543
- throw new OwneyError(
3544
- "WITHDRAW_FAILED",
3545
- "Yieldseeker withdrawals must be greater than zero.",
3546
- { amount },
3547
- this.id
3548
- );
3549
- }
3550
- const context = await this.findAgent(state, chainId, asset);
3551
- if (!context) {
3552
- throw new OwneyError(
3553
- "WITHDRAW_INSUFFICIENT_BALANCE",
3554
- `No Yieldseeker ${asset} agent exists for this wallet.`,
3555
- { asset, available: "0" },
3556
- this.id
3557
- );
3558
- }
3559
- const generation = this.readGeneration;
3560
- let confirmedMovement = false;
3561
- let settlement = null;
3562
- try {
3563
- const portfolio = await this.loadPortfolioContext(
3564
- state,
3565
- chainId,
3566
- context
3567
- );
3568
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3569
- const idleEntry = Object.entries(portfolio.snapshot.tokenBalances).find(
3570
- ([address]) => address.toLowerCase() === metadata.address.toLowerCase()
3571
- );
3572
- const idle = BigInt(idleEntry?.[1] ?? "0");
3573
- const deployed = portfolio.positions.reduce(
3574
- (total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
3575
- 0n
3576
- );
3577
- const totalAvailable = idle + deployed;
3578
- const requested = amount === void 0 ? totalAvailable : BigInt(amount);
3579
- const plannedMovement = this.snapshotMovement(state, chainId, context, -requested);
3580
- if (requested > totalAvailable) {
3581
- throw new OwneyError(
3582
- "WITHDRAW_INSUFFICIENT_BALANCE",
3583
- `Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
3584
- {
3585
- asset,
3586
- requested: requested.toString(),
3587
- available: totalAvailable.toString()
3588
- },
3589
- this.id
3590
- );
3591
- }
3592
- let remaining = requested > idle ? requested - idle : 0n;
3593
- for (const position2 of portfolio.positions) {
3594
- if (remaining === 0n) break;
3595
- const available = BigInt(position2.withdrawableAssetsRaw);
3596
- if (available <= 0n) continue;
3597
- const assetsRaw = available < remaining ? available : remaining;
3598
- const response = await this.walletRequest(
3599
- state,
3600
- chainId,
3601
- this.agentPath(context, "withdraw-from-position"),
3602
- {
3603
- method: "POST",
3604
- body: {
3605
- chainId,
3606
- vaultAddress: position2.yieldOption.address,
3607
- assetsRaw: assetsRaw.toString()
3608
- }
3609
- }
3610
- );
3611
- if (!this.isTransactionHash(response?.transactionHash)) {
3612
- throw this.invalidResponse("position withdrawal");
3613
- }
3614
- await this.waitForReceipt(state, chainId, response.transactionHash);
3615
- confirmedMovement = true;
3616
- remaining -= assetsRaw;
3617
- }
3618
- if (remaining > 0n) {
3619
- throw this.invalidResponse("yield positions", {
3620
- reason: "Withdrawable positions could not cover the request.",
3621
- remaining: remaining.toString()
3622
- });
3623
- }
3624
- const account = getAddress2(state.walletAddress);
3625
- const txHash = await this.submitTransaction(state, chainId, {
3626
- from: account,
3627
- to: getAddress2(context.wallet.walletAddress),
3628
- data: amount === void 0 ? encodeFunctionData({
3629
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3630
- functionName: "withdrawAllAssetToUser",
3631
- args: [account, metadata.address]
3632
- }) : encodeFunctionData({
3633
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3634
- functionName: "withdrawAssetToUser",
3635
- args: [account, metadata.address, requested]
3636
- }),
3637
- value: "0",
3638
- chainId
3639
- });
3640
- confirmedMovement = true;
3641
- settlement = plannedMovement;
3642
- return {
3643
- txHash,
3644
- type: amount === void 0 ? "full" : "partial",
3645
- amount: requested.toString()
3646
- };
3647
- } finally {
3648
- if (confirmedMovement && this.readGeneration === generation) {
3649
- await this.refreshSnapshotAfterMovement(
3650
- state,
3651
- chainId,
3652
- context,
3653
- "withdrawal",
3654
- settlement
3655
- );
3656
- }
3657
- }
3658
- }
3659
- async getBalances(state, chainId) {
3660
- this.assertChain(chainId);
3661
- return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, {}));
3662
- }
3663
- async getEarnings(state, chainId) {
3664
- this.assertChain(chainId);
3665
- return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
3666
- }
3667
- async getAccountApy(state, chainId, days, tokenSymbol) {
3668
- this.assertChain(chainId);
3669
- const asset = tokenSymbol?.toUpperCase();
3670
- if (asset !== void 0) this.assertAsset(asset);
3671
- const contexts = await this.loadPortfolio(state, chainId, {
3672
- ...asset ? { asset } : {},
3673
- historic: true
3674
- });
3675
- return mapYieldseekerApy(state.walletAddress, contexts, days);
3676
- }
3677
- async getHistory(state, chainId, options) {
3678
- this.assertChain(chainId);
3679
- const asset = options?.tokenSymbol?.toUpperCase();
3680
- if (asset !== void 0) this.assertAsset(asset);
3681
- const contexts = await this.loadPortfolio(state, chainId, {
3682
- ...asset ? { asset } : {},
3683
- historic: true,
3684
- actions: true
3685
- });
3686
- const catalog = await Promise.all(
3687
- [...new Set(contexts.map((context) => context.asset))].map(
3688
- (contextAsset) => this.loadYieldOptions(contextAsset)
3689
- )
3690
- );
3691
- const vaultAddresses = new Set(
3692
- catalog.flat().filter(
3693
- (yieldOption) => yieldOption.chainId === chainId && isAddress2(yieldOption.address)
3694
- ).map((yieldOption) => yieldOption.address.toLowerCase())
3695
- );
3696
- return mapYieldseekerHistory(contexts, {
3697
- limit: options?.limit ?? 10,
3698
- ownerAddress: state.walletAddress,
3699
- vaultAddresses,
3700
- ...options?.fromDate ? { fromDate: options.fromDate } : {},
3701
- ...options?.toDate ? { toDate: options.toDate } : {}
3702
- });
3703
- }
3704
- async getUserProfile(state, chainId) {
3705
- this.assertChain(chainId);
3706
- return mapYieldseekerProfile(
3707
- state.walletAddress,
3708
- await this.loadPortfolio(state, chainId, {})
3709
- );
3710
- }
3711
- async getAgentApy(days, options) {
3712
- this.assertOptionalChain(options?.chainId);
3713
- const requested = options?.tokenSymbol?.toUpperCase();
3714
- if (requested !== void 0) this.assertAsset(requested);
3715
- const assets = requested ? [requested] : ["USDC", "WETH"];
3716
- const values = await Promise.all(
3717
- assets.map(async (asset) => {
3718
- return { asset, yieldOptions: await this.loadYieldOptions(asset) };
3719
- })
3720
- );
3721
- return mapYieldseekerAgentApy(values, days);
3722
- }
3723
- async loadYieldOptions(asset) {
3724
- const cached = this.yieldOptions.get(asset);
3725
- if (cached && cached.expiresAt > Date.now()) return cached.value;
3726
- const pending = this.pendingYieldOptions.get(asset);
3727
- if (pending) return pending;
3728
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3729
- const request = this.api.request(
3730
- `/chains/8453/assets/${metadata.address}/yield-options`
3731
- ).then((response) => {
3732
- if (!Array.isArray(response?.yieldOptions)) {
3733
- throw this.invalidResponse("yield options");
3734
- }
3735
- this.yieldOptions.set(asset, {
3736
- expiresAt: Date.now() + YIELDSEEKER_YIELD_OPTIONS_CACHE_MS,
3737
- value: response.yieldOptions
3738
- });
3739
- return response.yieldOptions;
3740
- }).finally(() => this.pendingYieldOptions.delete(asset));
3741
- this.pendingYieldOptions.set(asset, request);
3742
- return request;
3743
- }
3744
- userKey(state, chainId) {
3745
- return `${state.walletAddress.toLowerCase()}:${chainId}`;
3746
- }
3747
- contextKey(state, chainId, asset) {
3748
- return `${this.userKey(state, chainId)}:${asset}`;
3749
- }
3750
- assertSession(generation, chainId, asset) {
3751
- if (this.readGeneration !== generation) {
3752
- throw new OwneyError(
3753
- "NOT_CONNECTED",
3754
- "Wallet session changed during the Yieldseeker request.",
3755
- { rpcSource: "agent-api", chainId, ...asset ? { asset } : {} },
3756
- this.id
3757
- );
3758
- }
3759
- }
3760
- cachedRead(key2, ttlMs, read2) {
3761
- const cached = this.readCache.get(key2);
3762
- if (cached && cached.expiresAt > Date.now()) {
3763
- return Promise.resolve(cached.value);
3764
- }
3765
- const pending = this.pendingReads.get(key2);
3766
- if (pending) return pending;
3767
- const generation = this.readGeneration;
3768
- const request = Promise.resolve().then(read2).then((value) => {
3769
- if (this.readGeneration === generation && this.pendingReads.get(key2) === request) {
3770
- this.readCache.set(key2, {
3771
- expiresAt: Date.now() + ttlMs,
3772
- value
3773
- });
3774
- }
3775
- return value;
3776
- }).finally(() => {
3777
- if (this.pendingReads.get(key2) === request) {
3778
- this.pendingReads.delete(key2);
3779
- }
3780
- });
3781
- this.pendingReads.set(key2, request);
3782
- return request;
3783
- }
3784
- agentListKey(state, chainId) {
3785
- return `agents:${this.userKey(state, chainId)}`;
3786
- }
3787
- async listAgents(state, chainId, user) {
3788
- const response = await this.cachedRead(
3789
- this.agentListKey(state, chainId),
3790
- YIELDSEEKER_AGENT_LIST_CACHE_MS,
3791
- async () => {
3792
- const response2 = await this.walletRequest(
3793
- state,
3794
- chainId,
3795
- `/users/${user.userId}/agents`
3796
- );
3797
- if (!Array.isArray(response2?.agents)) {
3798
- throw this.invalidResponse("agent list");
3799
- }
3800
- return response2;
3801
- }
3802
- );
3803
- return response.agents;
3804
- }
3805
- async contextForAgent(state, chainId, user, agent, asset) {
3806
- const key2 = this.contextKey(state, chainId, asset);
3807
- const cached = this.agentContexts.get(key2);
3808
- if (cached?.agent.agentId === agent.agentId) return cached;
3809
- const pending = this.pendingWalletContexts.get(key2);
3810
- if (pending) return pending;
3811
- const generation = this.readGeneration;
3812
- const request = this.walletRequest(
3813
- state,
3814
- chainId,
3815
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3816
- ).then((walletResponse) => {
3817
- this.assertSession(generation, chainId, asset);
3818
- if (!walletResponse?.agentWallet || !isAddress2(walletResponse.agentWallet.walletAddress)) {
3819
- throw this.invalidResponse("agent wallet");
3820
- }
3821
- const context = {
3822
- user,
3823
- agent,
3824
- wallet: walletResponse.agentWallet,
3825
- asset
3826
- };
3827
- this.agentContexts.set(key2, context);
3828
- return context;
3829
- });
3830
- this.pendingWalletContexts.set(key2, request);
3831
- try {
3832
- return await request;
3833
- } finally {
3834
- if (this.pendingWalletContexts.get(key2) === request) {
3835
- this.pendingWalletContexts.delete(key2);
3836
- }
3837
- }
3838
- }
3839
- async resolveUser(state, chainId) {
3840
- const key2 = this.userKey(state, chainId);
3841
- const inMemory = this.users.get(key2);
3842
- if (inMemory) return inMemory;
3843
- const persisted = readYieldseekerIdentity(state.walletAddress, chainId);
3844
- if (persisted) {
3845
- this.users.set(key2, persisted);
3846
- return persisted;
3847
- }
3848
- const walletAddress = getAddress2(state.walletAddress);
3849
- const generation = this.readGeneration;
3850
- let user = null;
3851
- try {
3852
- const login = await this.providerRequest(
3853
- state,
3854
- chainId,
3855
- "/users/login-with-wallet",
3856
- { method: "POST", body: { walletAddress } }
3857
- );
3858
- user = login?.user ?? null;
3859
- if (!user) {
3860
- throw this.invalidResponse("wallet login", {
3861
- reason: "A successful login returned no user."
3862
- });
3863
- }
3864
- } catch (error) {
3865
- if (!(error instanceof YieldseekerApiError) || error.providerCode !== "NO_USER") {
3866
- if (error instanceof OwneyError) throw error;
3867
- throw this.mapApiError(error);
3868
- }
3869
- let created;
3870
- for (let attempt = 0; attempt < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS; attempt += 1) {
3871
- try {
3872
- created = await this.providerRequest(
3873
- state,
3874
- chainId,
3875
- "/users",
3876
- {
3877
- method: "POST",
3878
- body: {
3879
- walletAddress,
3880
- username: generateYieldseekerUsername()
3881
- }
3882
- }
3883
- );
3884
- break;
3885
- } catch (createError) {
3886
- const canRetry = isUsernameConflict(createError) && attempt + 1 < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS;
3887
- if (canRetry) continue;
3888
- throw this.mapApiError(createError);
3889
- }
3890
- }
3891
- user = created?.user ?? null;
3892
- }
3893
- if (!user || !/^[a-zA-Z0-9_-]{1,128}$/.test(user.userId)) {
3894
- throw this.invalidResponse("wallet identity");
3895
- }
3896
- this.assertSession(generation, chainId);
3897
- const resolved = { userId: user.userId };
3898
- this.users.set(key2, resolved);
3899
- writeYieldseekerIdentity(state.walletAddress, chainId, resolved.userId);
3900
- return resolved;
3901
- }
3902
- forgetUser(state, chainId) {
3903
- this.users.delete(this.userKey(state, chainId));
3904
- clearYieldseekerIdentity(state.walletAddress, chainId);
3905
- }
3906
- async ensureAgent(state, chainId, asset) {
3907
- const key2 = this.contextKey(state, chainId, asset);
3908
- const cached = this.agentContexts.get(key2);
3909
- if (cached) return cached;
3910
- const pending = this.pendingAgents.get(key2);
3911
- if (pending) return pending;
3912
- const generation = this.readGeneration;
3913
- const request = this.resolveAgent(state, chainId, asset, true).then(
3914
- async (context) => {
3915
- this.assertSession(generation, chainId, asset);
3916
- if (!context) throw this.invalidResponse("agent creation");
3917
- await this.deployAgent(state, chainId, context);
3918
- this.assertSession(generation, chainId, asset);
3919
- this.agentContexts.set(key2, context);
3920
- return context;
3921
- }
3922
- );
3923
- this.pendingAgents.set(key2, request);
3924
- try {
3925
- return await request;
3926
- } finally {
3927
- if (this.pendingAgents.get(key2) === request) this.pendingAgents.delete(key2);
3928
- }
3929
- }
3930
- async findAgent(state, chainId, asset) {
3931
- const key2 = this.contextKey(state, chainId, asset);
3932
- const cached = this.agentContexts.get(key2);
3933
- if (cached) return cached;
3934
- const generation = this.readGeneration;
3935
- const context = await this.resolveAgent(state, chainId, asset, false);
3936
- this.assertSession(generation, chainId, asset);
3937
- if (context) this.agentContexts.set(key2, context);
3938
- return context;
3939
- }
3940
- async resolveAgent(state, chainId, asset, createIfMissing) {
3941
- const generation = this.readGeneration;
3942
- const user = await this.resolveUser(state, chainId);
3943
- this.assertSession(generation, chainId, asset);
3944
- const agents = await this.listAgents(state, chainId, user);
3945
- this.assertSession(generation, chainId, asset);
3946
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3947
- let agent = agents.find(
3948
- (candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
3949
- );
3950
- if (!agent && createIfMissing) {
3951
- const created = await this.walletRequest(
3952
- state,
3953
- chainId,
3954
- `/users/${user.userId}/agents`,
3955
- {
3956
- method: "POST",
3957
- body: {
3958
- name: OWNEY_AGENT_NAME,
3959
- emoji: "\u{1F989}",
3960
- chainId,
3961
- assetAddress: metadata.address,
3962
- type: "vault",
3963
- rulePreset: null
3964
- }
3965
- }
3966
- );
3967
- this.assertSession(generation, chainId, asset);
3968
- agent = created?.agent;
3969
- if (agent) {
3970
- this.readCache.set(this.agentListKey(state, chainId), {
3971
- expiresAt: Date.now() + YIELDSEEKER_AGENT_LIST_CACHE_MS,
3972
- value: {
3973
- agents: [...agents, agent]
3974
- }
3975
- });
3976
- }
3977
- }
3978
- if (!agent) return null;
3979
- this.assertAgent(agent);
3980
- return this.contextForAgent(state, chainId, user, agent, asset);
3981
- }
3982
- async loadPortfolio(state, chainId, options) {
3983
- const generation = this.readGeneration;
3984
- const user = await this.resolveUser(state, chainId);
3985
- this.assertSession(generation, chainId);
3986
- const agents = await this.listAgents(state, chainId, user);
3987
- this.assertSession(generation, chainId);
3988
- const contexts = [];
3989
- for (const agent of agents) {
3990
- const asset = this.assetForAgent(agent);
3991
- if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
3992
- continue;
3993
- }
3994
- this.assertAgent(agent);
3995
- contexts.push(this.contextForAgent(state, chainId, user, agent, asset));
3996
- }
3997
- const resolvedContexts = await Promise.all(contexts);
3998
- this.assertSession(generation, chainId);
3999
- return Promise.all(
4000
- resolvedContexts.map(
4001
- (context) => this.loadPortfolioContext(state, chainId, context, options)
4002
- )
4003
- );
4004
- }
4005
- portfolioVersion(contextKey) {
4006
- return this.portfolioVersions.get(contextKey) ?? 0;
4007
- }
4008
- portfolioCacheMs(contextKey) {
4009
- return (this.reconcileUntil.get(contextKey) ?? 0) > Date.now() ? YIELDSEEKER_SETTLEMENT_CACHE_MS : YIELDSEEKER_PORTFOLIO_CACHE_MS;
4010
- }
4011
- snapshotMovement(state, chainId, context, delta) {
4012
- const key2 = this.contextKey(state, chainId, context.asset);
4013
- const previous = this.snapshotMovements.get(key2);
4014
- if (this.snapshotMovements.has(key2)) {
4015
- if (!previous || previous.delta > 0n !== delta > 0n) return null;
4016
- return {
4017
- ...previous,
4018
- epoch: this.movementEpochs.get(key2) ?? 0,
4019
- delta: previous.delta + delta,
4020
- expectedBalance: previous.expectedBalance + delta,
4021
- expectedNetDeposits: previous.expectedNetDeposits + delta
4022
- };
4023
- }
4024
- const cached = this.readCache.get(`snapshot:${key2}`);
4025
- if (!cached || cached.expiresAt <= Date.now()) return null;
4026
- const snapshot = cached.value.agentSnapshot;
4027
- if (snapshot.baseAssetDecimals !== YIELDSEEKER_ASSET_METADATA[context.asset].decimals) return null;
4028
- if (!/^-?\d+$/.test(snapshot.netDepositsBase) || !/^\d+$/.test(snapshot.totalValueBase)) return null;
4029
- return {
4030
- epoch: this.movementEpochs.get(key2) ?? 0,
4031
- delta,
4032
- decimals: snapshot.baseAssetDecimals,
4033
- expectedBalance: BigInt(snapshot.totalValueBase) + delta,
4034
- expectedNetDeposits: BigInt(snapshot.netDepositsBase) + delta
4035
- };
4036
- }
4037
- advancePortfolioVersion(contextKey) {
4038
- const version = this.portfolioVersion(contextKey) + 1;
4039
- this.portfolioVersions.set(contextKey, version);
4040
- this.snapshotFailures.delete(contextKey);
4041
- for (const kind of ["snapshot", "positions", "historic", "actions"]) {
4042
- const key2 = `${kind}:${contextKey}`;
4043
- this.readCache.delete(key2);
4044
- this.pendingReads.delete(key2);
4045
- }
4046
- return version;
4047
- }
4048
- requestPortfolioSnapshot(state, chainId, context, contextKey, version, generation, forceRefresh = false) {
4049
- return this.walletRequest(
4050
- state,
4051
- chainId,
4052
- `${this.agentPath(context, "snapshot")}${query(forceRefresh ? { shouldForceRefresh: true } : { shouldOnlyUseRecentValue: true, shouldAllowStaleOnError: true })}`
4053
- ).then((response) => {
4054
- if (!response?.agentSnapshot) {
4055
- throw this.invalidResponse("agent snapshot");
4056
- }
4057
- if (this.readGeneration === generation && this.portfolioVersion(contextKey) === version) {
4058
- this.snapshotFailures.delete(contextKey);
4059
- const movement = this.snapshotMovements.get(contextKey);
4060
- const snapshot = response.agentSnapshot;
4061
- if (movement && snapshot.baseAssetDecimals === movement.decimals && /^-?\d+$/.test(snapshot.netDepositsBase) && /^\d+$/.test(snapshot.totalValueBase)) {
4062
- const balance = BigInt(snapshot.totalValueBase);
4063
- const netDeposits = BigInt(snapshot.netDepositsBase);
4064
- const reconciled = movement.delta > 0n ? balance >= movement.expectedBalance && netDeposits >= movement.expectedNetDeposits : balance <= movement.expectedBalance && netDeposits <= movement.expectedNetDeposits;
4065
- if (reconciled) {
4066
- this.snapshotMovements.delete(contextKey);
4067
- this.reconcileUntil.delete(contextKey);
4068
- }
4069
- }
4070
- }
4071
- return response;
4072
- }).catch((error) => {
4073
- if (this.readGeneration === generation && this.portfolioVersion(contextKey) === version) {
4074
- this.snapshotFailures.set(contextKey, {
4075
- retryAt: Date.now() + Math.max(YIELDSEEKER_READ_FAILURE_COOLDOWN_MS, rateLimitDelay(error) ?? 0),
4076
- error
4077
- });
4078
- }
4079
- throw error;
4080
- });
4081
- }
4082
- portfolioSnapshot(state, chainId, context, contextKey) {
4083
- const key2 = `snapshot:${contextKey}`;
4084
- const cached = this.readCache.get(key2);
4085
- if ((!cached || cached.expiresAt <= Date.now()) && !this.pendingReads.has(key2)) {
4086
- const failure = this.snapshotFailures.get(contextKey);
4087
- if (failure && failure.retryAt > Date.now()) throw failure.error;
4088
- this.advancePortfolioVersion(contextKey);
4089
- }
4090
- const version = this.portfolioVersion(contextKey);
4091
- const generation = this.readGeneration;
4092
- return {
4093
- version,
4094
- read: this.cachedRead(key2, this.portfolioCacheMs(contextKey), () => (
4095
- // Only event-driven reconciliation forces refreshes. Routine reads
4096
- // remain non-forced; the cache and shared cooldown still bound calls.
4097
- this.requestPortfolioSnapshot(
4098
- state,
4099
- chainId,
4100
- context,
4101
- contextKey,
4102
- version,
4103
- generation,
4104
- this.snapshotMovements.has(contextKey)
4105
- )
4106
- ))
4107
- };
4108
- }
4109
- async loadPortfolioContext(state, chainId, context, options = {}) {
4110
- const contextKey = this.contextKey(state, chainId, context.asset);
4111
- const generation = this.readGeneration;
4112
- const assertSession = () => this.assertSession(generation, chainId, context.asset);
4113
- for (let attempt = 0; attempt < 2; attempt++) {
4114
- const { version, read: read2 } = this.portfolioSnapshot(state, chainId, context, contextKey);
4115
- try {
4116
- const snapshot = await read2;
4117
- assertSession();
4118
- if (this.portfolioVersion(contextKey) !== version) continue;
4119
- const [positions, historic, actions] = await Promise.all([
4120
- this.cachedRead(
4121
- `positions:${contextKey}`,
4122
- this.portfolioCacheMs(contextKey),
4123
- async () => {
4124
- const response = await this.walletRequest(
4125
- state,
4126
- chainId,
4127
- this.agentPath(context, "yield-positions")
4128
- );
4129
- if (!Array.isArray(response?.yieldPositions)) {
4130
- throw this.invalidResponse("yield positions");
4131
- }
4132
- return response;
4133
- }
4134
- ),
4135
- options.historic ? this.cachedRead(
4136
- `historic:${contextKey}`,
4137
- (this.activityRefreshUntil.get(contextKey) ?? 0) > Date.now() ? YIELDSEEKER_SETTLEMENT_ACTIVITY_CACHE_MS : YIELDSEEKER_ACTIVITY_CACHE_MS,
4138
- () => this.walletRequest(
4139
- state,
4140
- chainId,
4141
- this.agentPath(context, "wallet/historic-position")
4142
- )
4143
- ) : Promise.resolve(void 0),
4144
- options.actions ? this.cachedRead(
4145
- `actions:${contextKey}`,
4146
- (this.activityRefreshUntil.get(contextKey) ?? 0) > Date.now() ? YIELDSEEKER_SETTLEMENT_ACTIVITY_CACHE_MS : YIELDSEEKER_ACTIVITY_CACHE_MS,
4147
- () => this.walletRequest(
4148
- state,
4149
- chainId,
4150
- this.agentPath(context, "actions")
4151
- )
4152
- ) : Promise.resolve(void 0)
4153
- ]);
4154
- assertSession();
4155
- if (this.portfolioVersion(contextKey) !== version) continue;
4156
- if (!Array.isArray(positions?.yieldPositions)) {
4157
- throw this.invalidResponse("yield positions");
4158
- }
4159
- return {
4160
- ...context,
4161
- snapshot: snapshot.agentSnapshot,
4162
- positions: positions.yieldPositions,
4163
- ...historic?.position ? { historic: historic.position } : {},
4164
- ...actions?.actions ? { actions: actions.actions } : {}
4165
- };
4166
- } catch (error) {
4167
- assertSession();
4168
- if (this.portfolioVersion(contextKey) !== version) continue;
4169
- throw error;
4170
- }
4171
- }
4172
- throw new OwneyError(
4173
- "AGENT_API_ERROR",
4174
- "Yieldseeker portfolio changed during the read. Please retry.",
4175
- { rpcSource: "agent-api", chainId, asset: context.asset },
4176
- this.id
4177
- );
4178
- }
4179
- async deployAgent(state, chainId, context) {
4180
- if (context.wallet.initializedDate != null) return;
4181
- const walletAddress = context.wallet.walletAddress.toLowerCase();
4182
- const deployed = await this.walletRequest(
4183
- state,
4184
- chainId,
4185
- this.agentPath(context, "deploy"),
4186
- { method: "POST", body: {} }
4187
- );
4188
- if (!deployed?.agentWallet || !isAddress2(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
4189
- throw this.invalidResponse("agent deployment", {
4190
- reason: "Deploy did not return the expected Agent Wallet."
4191
- });
4192
- }
4193
- context.wallet = deployed.agentWallet;
4194
- }
4195
- async refreshSnapshotAfterMovement(state, chainId, context, movement, settlement) {
4196
- const contextKey = this.contextKey(state, chainId, context.asset);
4197
- this.reconcileUntil.set(contextKey, Date.now() + YIELDSEEKER_SETTLEMENT_WINDOW_MS);
4198
- this.activityRefreshUntil.set(contextKey, Date.now() + YIELDSEEKER_SETTLEMENT_WINDOW_MS);
4199
- const epoch = this.movementEpochs.get(contextKey) ?? 0;
4200
- this.snapshotMovements.set(contextKey, settlement?.epoch === epoch ? settlement : null);
4201
- this.movementEpochs.set(contextKey, epoch + 1);
4202
- const version = this.advancePortfolioVersion(contextKey);
4203
- const generation = this.readGeneration;
4204
- try {
4205
- await this.cachedRead(
4206
- `snapshot:${contextKey}`,
4207
- YIELDSEEKER_SETTLEMENT_CACHE_MS,
4208
- () => this.requestPortfolioSnapshot(state, chainId, context, contextKey, version, generation, true)
4209
- );
4210
- } catch (error) {
4211
- console.warn(
4212
- `[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
4213
- error
4214
- );
4215
- }
4216
- }
4217
- agentPath(context, suffix) {
4218
- return `/users/${context.user.userId}/agents/${context.agent.agentId}/${suffix}`;
4219
- }
4220
- async walletRequest(state, chainId, path, options = {}) {
4221
- const read2 = (options.method ?? "GET") === "GET";
4222
- const userKey = this.userKey(state, chainId);
4223
- if (read2) {
4224
- const failure = this.standardReadFailures.get(userKey);
4225
- if (failure && failure.retryAt > Date.now()) throw failure.error;
4226
- if (failure) this.standardReadFailures.delete(userKey);
4227
- }
4228
- const generation = this.readGeneration;
4229
- try {
4230
- return await this.providerRequest(state, chainId, path, options);
4231
- } catch (error) {
4232
- const mapped = this.mapApiError(error);
4233
- const delay = read2 ? rateLimitDelay(mapped) : void 0;
4234
- if (delay !== void 0 && this.readGeneration === generation) {
4235
- this.standardReadFailures.set(userKey, {
4236
- retryAt: Date.now() + Math.max(YIELDSEEKER_READ_FAILURE_COOLDOWN_MS, delay),
4237
- error: mapped
4238
- });
4239
- }
4240
- throw mapped;
4241
- }
4242
- }
4243
- async providerRequest(state, chainId, path, options = {}) {
4244
- this.assertChain(chainId);
4245
- const request = (signature2) => this.api.request(path, {
4246
- ...options,
4247
- signature: signature2
4248
- });
4249
- let signature = await this.auth.getToken(state, chainId);
4250
- try {
4251
- return await request(signature);
4252
- } catch (error) {
4253
- if (!(error instanceof YieldseekerApiError)) throw error;
4254
- if (error.providerCode === "NO_USER") throw error;
4255
- if (!error.isAuthenticationError) throw error;
4256
- signature = await this.auth.refreshToken(state, chainId, signature);
4257
- try {
4258
- return await request(signature);
4259
- } catch (retryError) {
4260
- if (retryError instanceof YieldseekerApiError && retryError.isAuthenticationError) {
4261
- this.forgetUser(state, chainId);
4262
- }
4263
- throw retryError;
4264
- }
4265
- }
4266
- }
4267
- mapApiError(error) {
4268
- if (!(error instanceof YieldseekerApiError)) {
4269
- return new OwneyError(
4270
- "AGENT_API_ERROR",
4271
- "Yieldseeker request failed.",
4272
- { cause: error instanceof Error ? error.message : String(error) },
4273
- this.id
4274
- );
4275
- }
4276
- const code = error.isAuthenticationError ? "AGENT_AUTH_FAILED" : error.providerCode === "REQUEST_TIMEOUT" ? "AGENT_TIMEOUT" : "AGENT_API_ERROR";
4277
- return new OwneyError(
4278
- code,
4279
- `Yieldseeker request failed: ${error.providerCode}.`,
4280
- {
4281
- rpcSource: "agent-api",
4282
- statusCode: error.status,
4283
- providerCode: error.providerCode,
4284
- ...error.responseFields ? { fields: error.responseFields } : {}
4285
- },
4286
- this.id
4287
- );
4288
- }
4289
- async submitTransaction(state, chainId, transaction) {
4290
- if (this.transactionExecutor) {
4291
- return this.transactionExecutor(state, chainId, transaction);
4292
- }
4293
- this.assertTransaction(transaction, state, chainId);
4294
- const account = getAddress2(state.walletAddress);
4295
- const walletClient = createWalletClient2({
4296
- account,
4297
- chain: base3,
4298
- transport: custom2(state.provider)
4299
- });
4300
- const walletChainClient = createPublicClient3({
4301
- chain: base3,
4302
- transport: custom2(state.provider)
4303
- });
4304
- await ensureWalletOnChain(
4305
- walletChainClient,
4306
- walletClient,
4307
- 8453
4308
- );
4309
- const hash = await walletClient.sendTransaction({
4310
- account,
4311
- chain: base3,
4312
- to: getAddress2(transaction.to),
4313
- data: transaction.data,
4314
- value: BigInt(transaction.value)
4315
- });
4316
- const receipt = await withPaidRpcDiagnostics(
4317
- () => this.getReceiptClient().waitForTransactionReceipt({
4318
- hash,
4319
- confirmations: 1
4320
- }),
4321
- 8453,
4322
- "eth_getTransactionReceipt",
4323
- this.id
4324
- );
4325
- if (receipt.status !== "success") {
4326
- throw new OwneyError(
4327
- "AGENT_TRANSACTION_REVERTED",
4328
- `Yieldseeker transaction reverted (${hash}).`,
4329
- { transactionHash: hash },
4330
- this.id
4331
- );
4332
- }
4333
- return hash;
4334
- }
4335
- async waitForReceipt(state, chainId, transactionHash) {
4336
- if (this.unwindReceiptWaiter) {
4337
- await this.unwindReceiptWaiter(state, chainId, transactionHash);
4338
- return;
4339
- }
4340
- const receipt = await withPaidRpcDiagnostics(
4341
- () => this.getReceiptClient().waitForTransactionReceipt({
4342
- hash: transactionHash,
4343
- confirmations: 1
4344
- }),
4345
- 8453,
4346
- "eth_getTransactionReceipt",
4347
- this.id
4348
- );
4349
- if (receipt.status !== "success") {
4350
- throw new OwneyError(
4351
- "AGENT_TRANSACTION_REVERTED",
4352
- `Yieldseeker transaction reverted (${transactionHash}).`,
4353
- { transactionHash },
4354
- this.id
4355
- );
4356
- }
4357
- }
4358
- assertTransaction(transaction, state, chainId) {
4359
- 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)) {
4360
- throw this.invalidResponse("transaction");
4361
- }
4362
- }
4363
- assertAgent(agent) {
4364
- if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !isAddress2(agent.assetAddress) || agent.chainId !== 8453) {
4365
- throw this.invalidResponse("agent");
4366
- }
4367
- }
4368
- isOwneyAgent(agent) {
4369
- return typeof agent.name === "string" && agent.name.trim().toLowerCase() === OWNEY_AGENT_NAME;
4370
- }
4371
- assetForAgent(agent) {
4372
- for (const asset of ["USDC", "WETH"]) {
4373
- if (agent.assetAddress.toLowerCase() === YIELDSEEKER_ASSET_METADATA[asset].address.toLowerCase()) {
4374
- return asset;
4375
- }
4376
- }
4377
- return null;
4378
- }
4379
- isTransactionHash(value) {
4380
- return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
4381
- }
4382
- assertChain(chainId) {
4383
- if (chainId !== 8453) {
4384
- throw new OwneyError(
4385
- "CHAIN_UNSUPPORTED",
4386
- `Yieldseeker does not support chain ${chainId}.`,
4387
- { chainId, supportedChainIds: [8453] },
4388
- this.id
4389
- );
4390
- }
4391
- }
4392
- assertOptionalChain(chainId) {
4393
- if (chainId !== void 0) this.assertChain(chainId);
4394
- }
4395
- assertAsset(asset) {
4396
- if (asset !== "USDC" && asset !== "WETH") {
4397
- throw new OwneyError(
4398
- "ASSET_UNSUPPORTED",
4399
- `Yieldseeker does not support asset ${asset} in the Owney rollout.`,
4400
- {
4401
- asset,
4402
- supportedAssets: ["USDC", "WETH"],
4403
- providerAlsoAdvertises: ["cbBTC"]
4404
- },
4405
- this.id
4406
- );
4407
- }
4408
- }
4409
- invalidResponse(operation, details = {}) {
4410
- return new OwneyError(
4411
- "AGENT_INVALID_RESPONSE",
4412
- `Yieldseeker returned an invalid ${operation} response.`,
4413
- details,
4414
- this.id
4415
- );
4416
- }
4417
- };
4418
-
4419
- // src/lib/routing-api.ts
4420
- var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
4421
- async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
4422
- const url = `${baseUrl}/api/v1/agent/org-config`;
4423
- try {
4424
- const res = await fetch(url, {
4425
- method: "GET",
4426
- headers: {
4427
- "Content-Type": "application/json",
4428
- "x-owney-api-key": `${apiKey}`
4429
- }
4430
- });
4431
- if (!res.ok) {
4432
- if (res.status !== 404) {
4433
- console.warn(
4434
- `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
4435
- );
4436
- }
4437
- return null;
4438
- }
4439
- const json = await res.json();
4440
- const policy = json.success ? json.data ?? null : null;
4441
- debugLog(
4442
- "owney-sdk",
4443
- policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
4444
- policy ?? void 0
4445
- );
4446
- return policy;
4447
- } catch (error) {
4448
- console.warn(
4449
- "[owney-sdk] Could not read org agent config (non-fatal):",
4450
- error instanceof Error ? error.message : String(error)
4451
- );
4452
- return null;
4453
- }
4454
- }
4455
- async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
4456
- const url = `${baseUrl}/api/v1/agent/keys`;
4457
- const res = await fetch(url, {
4458
- method: "GET",
4459
- headers: {
4460
- "Content-Type": "application/json",
4461
- "x-owney-api-key": `${apiKey}`
4462
- }
4463
- });
4464
- if (!res.ok) {
4465
- const text = await res.text().catch(() => "");
4466
- throw new OwneyError(
4467
- "API_ROUTING_ERROR",
4468
- `Routing API error ${res.status}: ${text}`,
4469
- { statusCode: res.status, responseBody: text }
4470
- );
4471
- }
4472
- const json = await res.json();
4473
- if (!json.success) {
4474
- throw new OwneyError(
4475
- "API_ROUTING_FAILED",
4476
- `Routing API request failed: ${json.message}`,
4477
- { message: json.message }
4478
- );
4479
- }
4480
- return json.data;
4481
- }
4482
-
4483
- // src/lib/health-report.ts
4484
- var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
4485
- async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL3) {
4486
- try {
4487
- await fetch(`${baseUrl}/api/v1/agent/health-report`, {
4488
- method: "POST",
4489
- headers: {
4490
- "Content-Type": "application/json",
4491
- "x-owney-api-key": apiKey
4492
- },
4493
- body: JSON.stringify({
4494
- agent_type: agentType,
4495
- error_code: errorCode,
4496
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
4497
- })
4498
- });
4499
- } catch (err) {
4500
- console.warn(
4501
- `[owney-sdk] health-report failed for agent "${agentType}":`,
4502
- err instanceof Error ? err.message : err
4503
- );
4504
- }
4505
- }
4506
- async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
4507
- try {
4508
- return await fn();
4509
- } catch (err) {
4510
- const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
4511
- void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
4512
- throw err;
2193
+ return await fn();
2194
+ } catch (err) {
2195
+ const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
2196
+ void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
2197
+ throw err;
4513
2198
  }
4514
2199
  }
4515
2200
 
@@ -4522,29 +2207,8 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
4522
2207
  const tokenBalance = agentBalance?.tokens.find(
4523
2208
  (t) => t.chainId === chainId && t.asset.toUpperCase() === target
4524
2209
  );
4525
- let balance = tokenBalance ? parseUnits(tokenBalance.amount, decimals) : 0n;
4526
- if (agent.balanceComposition === "tokens-plus-positions") {
4527
- const chainNameById = {
4528
- 1: "ETHEREUM",
4529
- 8453: "BASE",
4530
- 42161: "ARBITRUM"
4531
- };
4532
- const targetChain = chainNameById[chainId];
4533
- for (const position2 of agentBalance?.positions ?? []) {
4534
- const positionChain = position2.chain.trim().toUpperCase();
4535
- const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
4536
- if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
4537
- balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : parseUnits(position2.amount, decimals);
4538
- }
4539
- }
4540
- const assetTotal = agentBalance?.assetBalances?.find(
4541
- (t) => t.chainId === chainId && t.asset.toUpperCase() === target
4542
- );
4543
- if (assetTotal) {
4544
- const total = parseUnits(assetTotal.amount, decimals);
4545
- if (total < balance) balance = total > 0n ? total : 0n;
4546
- }
4547
- return { agent, balance };
2210
+ if (!tokenBalance) return { agent, balance: 0n };
2211
+ return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
4548
2212
  });
4549
2213
  }
4550
2214
  function planProportionalShares(balances, requested, totalAvailable) {
@@ -4570,9 +2234,7 @@ function planProportionalShares(balances, requested, totalAvailable) {
4570
2234
  return plans;
4571
2235
  }
4572
2236
  function planDisabledDrain(disabled, requested) {
4573
- const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
4574
- (a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
4575
- );
2237
+ const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
4576
2238
  const plans = [];
4577
2239
  let remaining = requested;
4578
2240
  for (const { agent, balance } of sorted) {
@@ -4623,13 +2285,6 @@ function balanceForApyScope(balance, chainId, tokenSymbol) {
4623
2285
  return Number.isFinite(total) && total > 0 ? total : 0;
4624
2286
  }
4625
2287
  const normalizedToken = tokenSymbol.toUpperCase();
4626
- const snapshots = balance.assetBalances?.filter(
4627
- (token) => Number(token.chainId) === chainId && String(token.asset).toUpperCase() === normalizedToken
4628
- );
4629
- if (snapshots?.length) {
4630
- const amount = snapshots.reduce((sum, token) => sum + Number(token.amount), 0);
4631
- if (Number.isFinite(amount)) return Math.max(0, amount);
4632
- }
4633
2288
  return balance.tokens.reduce((total, token) => {
4634
2289
  if (Number(token.chainId) !== chainId || String(token.asset).toUpperCase() !== normalizedToken) {
4635
2290
  return total;
@@ -4701,386 +2356,441 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
4701
2356
 
4702
2357
  // src/client.ts
4703
2358
  import {
4704
- createPublicClient as createPublicClient4,
4705
- createWalletClient as createWalletClient3,
4706
- custom as custom3
4707
- } from "viem";
4708
- import { base as base4, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
4709
-
4710
- // src/lib/sponsored-token-batch.ts
4711
- import {
4712
- isAddressEqual,
4713
- keccak256,
4714
- toBytes
2359
+ createPublicClient as createPublicClient2,
2360
+ createWalletClient,
2361
+ custom
4715
2362
  } from "viem";
2363
+ import { base as base2, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
4716
2364
 
4717
- // src/lib/permit2-batch.ts
4718
- import { parseAbi as parseAbi2, hashStruct } from "viem";
4719
- var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
4720
- var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
4721
- var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
4722
- var ERC2612_PERMIT_TYPES = {
4723
- Permit: [
4724
- { name: "owner", type: "address" },
4725
- { name: "spender", type: "address" },
4726
- { name: "value", type: "uint256" },
4727
- { name: "nonce", type: "uint256" },
4728
- { name: "deadline", type: "uint256" }
4729
- ]
4730
- };
4731
- var ERC2612_READ_ABI = parseAbi2([
4732
- "function name() view returns (string)",
4733
- "function version() view returns (string)",
4734
- "function nonces(address owner) view returns (uint256)"
4735
- ]);
4736
- function erc2612TypedData(input) {
2365
+ // src/lib/transfer-auth.ts
2366
+ import { bytesToHex } from "viem";
2367
+ var ERC20_META_ABI = [
2368
+ { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
2369
+ { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
2370
+ ];
2371
+ function buildTransferWithAuthorizationTypedData(input) {
4737
2372
  return {
4738
- domain: {
4739
- name: input.permit.tokenName,
4740
- version: input.permit.tokenVersion,
4741
- chainId: input.chainId,
4742
- verifyingContract: input.token
2373
+ domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
2374
+ types: {
2375
+ TransferWithAuthorization: [
2376
+ { name: "from", type: "address" },
2377
+ { name: "to", type: "address" },
2378
+ { name: "value", type: "uint256" },
2379
+ { name: "validAfter", type: "uint256" },
2380
+ { name: "validBefore", type: "uint256" },
2381
+ { name: "nonce", type: "bytes32" }
2382
+ ]
4743
2383
  },
4744
- types: ERC2612_PERMIT_TYPES,
4745
- primaryType: "Permit",
4746
- message: {
4747
- owner: input.owner,
4748
- spender: BATCH_PERMIT2_ADDRESS,
4749
- value: BigInt(input.permit.value),
4750
- nonce: BigInt(input.permit.nonce),
4751
- deadline: BigInt(input.permit.deadline)
4752
- }
2384
+ primaryType: "TransferWithAuthorization",
2385
+ message: input.message
4753
2386
  };
4754
2387
  }
4755
- var PERMIT_BATCH_TYPES = {
4756
- PermitBatchWitnessTransferFrom: [
4757
- { name: "permitted", type: "TokenPermissions[]" },
4758
- { name: "spender", type: "address" },
4759
- { name: "nonce", type: "uint256" },
4760
- { name: "deadline", type: "uint256" },
4761
- { name: "witness", type: "Deposit" }
4762
- ],
4763
- Deposit: [{ name: "recipients", type: "address[]" }],
4764
- TokenPermissions: [
4765
- { name: "token", type: "address" },
4766
- { name: "amount", type: "uint256" }
4767
- ]
4768
- };
4769
- var PERMIT2_BATCH_ABI = parseAbi2([
4770
- "struct TokenPermissions { address token; uint256 amount; }",
4771
- "struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
4772
- "struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
4773
- "function permitWitnessTransferFrom(PermitBatchTransferFrom permit,SignatureTransferDetails[] transferDetails,address owner,bytes32 witness,string witnessTypeString,bytes signature)",
4774
- "function nonceBitmap(address owner,uint256 wordPos) view returns (uint256)"
4775
- ]);
4776
- function batchPermit(b) {
4777
- return {
4778
- permitted: b.transfers.map((t) => ({
4779
- token: b.token,
4780
- amount: BigInt(t.amount)
4781
- })),
4782
- nonce: BigInt(b.nonce),
4783
- deadline: BigInt(b.deadline)
4784
- };
2388
+ async function readTokenMeta(publicClient, token) {
2389
+ const [tokenName, tokenVersion] = await Promise.all([
2390
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
2391
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
2392
+ ]);
2393
+ return { tokenName, tokenVersion };
2394
+ }
2395
+ function randomAuthNonce() {
2396
+ const bytes = new Uint8Array(32);
2397
+ globalThis.crypto.getRandomValues(bytes);
2398
+ return bytesToHex(bytes);
2399
+ }
2400
+
2401
+ // src/lib/sponsor-client.ts
2402
+ var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2403
+ async function postSponsorTransferAuth(input) {
2404
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2405
+ let res;
2406
+ try {
2407
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2408
+ method: "POST",
2409
+ headers: {
2410
+ "content-type": "application/json",
2411
+ "x-owney-api-key": input.apiKey
2412
+ },
2413
+ body: JSON.stringify(input.body)
2414
+ });
2415
+ } catch (networkError) {
2416
+ throw new OwneyError(
2417
+ "SPONSOR_REQUEST_FAILED",
2418
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2419
+ { cause: String(networkError) }
2420
+ );
2421
+ }
2422
+ const text = await res.text();
2423
+ let parsed = null;
2424
+ try {
2425
+ parsed = JSON.parse(text);
2426
+ } catch {
2427
+ }
2428
+ if (!res.ok || !parsed?.success || !parsed.data) {
2429
+ throw new OwneyError(
2430
+ "SPONSOR_REQUEST_FAILED",
2431
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2432
+ {
2433
+ statusCode: res.status,
2434
+ responseBody: text.slice(0, 500),
2435
+ // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2436
+ // before broadcast, so it is safe to fall back to a user-paid deposit.
2437
+ safeToFallback: res.status === 503
2438
+ }
2439
+ );
2440
+ }
2441
+ return parsed.data;
2442
+ }
2443
+ async function postSponsorPermit2Transfer(input) {
2444
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2445
+ let res;
2446
+ try {
2447
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2448
+ method: "POST",
2449
+ headers: {
2450
+ "content-type": "application/json",
2451
+ "x-owney-api-key": input.apiKey
2452
+ },
2453
+ body: JSON.stringify(input.body)
2454
+ });
2455
+ } catch (networkError) {
2456
+ throw new OwneyError(
2457
+ "SPONSOR_REQUEST_FAILED",
2458
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2459
+ { cause: String(networkError), safeToFallback: false }
2460
+ );
2461
+ }
2462
+ const text = await res.text();
2463
+ let parsed = null;
2464
+ try {
2465
+ parsed = JSON.parse(text);
2466
+ } catch {
2467
+ }
2468
+ if (!res.ok || !parsed?.success || !parsed.data) {
2469
+ throw new OwneyError(
2470
+ "SPONSOR_REQUEST_FAILED",
2471
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2472
+ {
2473
+ statusCode: res.status,
2474
+ responseBody: text.slice(0, 500),
2475
+ safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
2476
+ }
2477
+ );
2478
+ }
2479
+ return parsed.data;
2480
+ }
2481
+ async function getSponsorRelayerAddress(input) {
2482
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2483
+ let res;
2484
+ try {
2485
+ res = await fetch(
2486
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2487
+ {
2488
+ headers: { "x-owney-api-key": input.apiKey }
2489
+ }
2490
+ );
2491
+ } catch (networkError) {
2492
+ throw new OwneyError(
2493
+ "SPONSOR_REQUEST_FAILED",
2494
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2495
+ { cause: String(networkError), safeToFallback: true }
2496
+ );
2497
+ }
2498
+ const text = await res.text();
2499
+ let parsed = null;
2500
+ try {
2501
+ parsed = JSON.parse(text);
2502
+ } catch {
2503
+ }
2504
+ if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
2505
+ throw new OwneyError(
2506
+ "SPONSOR_REQUEST_FAILED",
2507
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2508
+ {
2509
+ statusCode: res.status,
2510
+ responseBody: text.slice(0, 500),
2511
+ safeToFallback: true
2512
+ }
2513
+ );
2514
+ }
2515
+ return parsed.data.relayer;
4785
2516
  }
4786
- function batchTypedData(b, spender) {
2517
+
2518
+ // src/lib/permit2.ts
2519
+ import { bytesToHex as bytesToHex2 } from "viem";
2520
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2521
+ var MAX_UINT256 = 2n ** 256n - 1n;
2522
+ var ERC20_ALLOWANCE_ABI = [
2523
+ {
2524
+ type: "function",
2525
+ name: "allowance",
2526
+ stateMutability: "view",
2527
+ inputs: [
2528
+ { name: "owner", type: "address" },
2529
+ { name: "spender", type: "address" }
2530
+ ],
2531
+ outputs: [{ name: "", type: "uint256" }]
2532
+ },
2533
+ {
2534
+ type: "function",
2535
+ name: "approve",
2536
+ stateMutability: "nonpayable",
2537
+ inputs: [
2538
+ { name: "spender", type: "address" },
2539
+ { name: "amount", type: "uint256" }
2540
+ ],
2541
+ outputs: [{ name: "", type: "bool" }]
2542
+ },
2543
+ {
2544
+ type: "function",
2545
+ name: "balanceOf",
2546
+ stateMutability: "view",
2547
+ inputs: [{ name: "account", type: "address" }],
2548
+ outputs: [{ name: "", type: "uint256" }]
2549
+ }
2550
+ ];
2551
+ function buildPermitTransferFromTypedData(input) {
4787
2552
  return {
4788
2553
  domain: {
4789
2554
  name: "Permit2",
4790
- chainId: b.chainId,
4791
- verifyingContract: BATCH_PERMIT2_ADDRESS
2555
+ chainId: input.chainId,
2556
+ verifyingContract: PERMIT2_ADDRESS
4792
2557
  },
4793
- types: PERMIT_BATCH_TYPES,
4794
- primaryType: "PermitBatchWitnessTransferFrom",
4795
- message: {
4796
- ...batchPermit(b),
4797
- spender,
4798
- witness: { recipients: b.transfers.map((t) => t.to) }
4799
- }
2558
+ types: {
2559
+ PermitTransferFrom: [
2560
+ { name: "permitted", type: "TokenPermissions" },
2561
+ { name: "spender", type: "address" },
2562
+ { name: "nonce", type: "uint256" },
2563
+ { name: "deadline", type: "uint256" }
2564
+ ],
2565
+ TokenPermissions: [
2566
+ { name: "token", type: "address" },
2567
+ { name: "amount", type: "uint256" }
2568
+ ]
2569
+ },
2570
+ primaryType: "PermitTransferFrom",
2571
+ message: input.message
4800
2572
  };
4801
2573
  }
4802
-
4803
- // src/lib/sponsored-token-batch.ts
4804
- var memory = /* @__PURE__ */ new Map();
4805
- var inflight = /* @__PURE__ */ new Map();
4806
- var planOf = (transfers) => JSON.stringify(
4807
- transfers.map((t) => ({
4808
- to: t.to.toLowerCase(),
4809
- amount: BigInt(t.amount).toString()
4810
- }))
4811
- );
4812
- function read(key2) {
4813
- return typeof window === "undefined" ? memory.get(key2) : window.localStorage.getItem(key2);
2574
+ function randomPermit2Nonce() {
2575
+ const bytes = new Uint8Array(32);
2576
+ globalThis.crypto.getRandomValues(bytes);
2577
+ return BigInt(bytesToHex2(bytes));
4814
2578
  }
4815
- function save(key2, body) {
4816
- const value = JSON.stringify({
4817
- ...body,
4818
- transfers: body.transfers.map(({ to, amount }) => ({ to, amount }))
2579
+ async function readPermit2Allowance(publicClient, token, owner) {
2580
+ return publicClient.readContract({
2581
+ address: token,
2582
+ abi: ERC20_ALLOWANCE_ABI,
2583
+ functionName: "allowance",
2584
+ args: [owner, PERMIT2_ADDRESS]
4819
2585
  });
4820
- if (typeof window === "undefined") memory.set(key2, value);
4821
- else window.localStorage.setItem(key2, value);
4822
2586
  }
4823
- function clear(key2) {
4824
- if (typeof window === "undefined") memory.delete(key2);
4825
- else window.localStorage.removeItem(key2);
2587
+ async function readErc20Balance(publicClient, token, owner) {
2588
+ return publicClient.readContract({
2589
+ address: token,
2590
+ abi: ERC20_ALLOWANCE_ABI,
2591
+ functionName: "balanceOf",
2592
+ args: [owner]
2593
+ });
4826
2594
  }
4827
- function sponsorTokenBatch(i) {
4828
- const key2 = `owney.token-batch.v1:${keccak256(toBytes(i.apiKey))}:${i.baseUrl ?? "default"}:${i.chainId}:${i.owner.toLowerCase()}:${i.token.toLowerCase()}`;
4829
- const plan = planOf(i.transfers);
4830
- const active = inflight.get(key2);
4831
- if (active) {
4832
- if (active.plan !== plan)
4833
- return Promise.reject(
4834
- new Error(
4835
- "A token deposit is already in progress. Wait for its result before depositing again."
4836
- )
4837
- );
4838
- return active.promise;
4839
- }
4840
- const promise = execute(i, key2, plan).finally(() => inflight.delete(key2));
4841
- inflight.set(key2, { plan, promise });
4842
- return promise;
2595
+
2596
+ // src/lib/chain-guard.ts
2597
+ var CHAIN_NAMES = {
2598
+ 1: "Ethereum",
2599
+ 8453: "Base",
2600
+ 42161: "Arbitrum"
2601
+ };
2602
+ function chainName(chainId) {
2603
+ return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
4843
2604
  }
4844
- async function execute(i, key2, plan) {
4845
- if (!i.transfers.length || i.transfers.length > 16 || i.transfers.some(
4846
- (t) => BigInt(t.amount) <= 0n || BigInt(t.amount) >= 1n << 256n
4847
- ) || new Set(i.transfers.map((t) => t.to.toLowerCase())).size !== i.transfers.length)
4848
- throw new Error("Invalid token deposit shares.");
4849
- const send = async (initial) => {
4850
- let body = initial;
4851
- save(key2, body);
4852
- try {
4853
- if (!body.serializedTransaction) {
4854
- const prepared = await postSponsorBatchTransfer({
4855
- apiKey: i.apiKey,
4856
- baseUrl: i.baseUrl,
4857
- body
4858
- });
4859
- if (!prepared.serializedTransaction || keccak256(prepared.serializedTransaction) !== prepared.txHash)
4860
- throw new Error(
4861
- "Sponsorship API did not return a valid prepared transaction."
4862
- );
4863
- body = {
4864
- ...body,
4865
- serializedTransaction: prepared.serializedTransaction
4866
- };
4867
- save(key2, body);
4868
- }
4869
- const result = await postSponsorBatchTransfer({
4870
- apiKey: i.apiKey,
4871
- baseUrl: i.baseUrl,
4872
- body
4873
- });
4874
- if (result.txHash !== keccak256(body.serializedTransaction))
4875
- throw new Error(
4876
- "Sponsorship receipt does not match the pending transaction."
4877
- );
4878
- clear(key2);
4879
- return result.txHash;
4880
- } catch (error) {
4881
- if (!body.serializedTransaction || error instanceof OwneyError && error.details?.notSubmitted === true)
4882
- clear(key2);
4883
- throw error;
4884
- }
4885
- };
4886
- const saved = read(key2);
4887
- if (saved) {
4888
- const previous = JSON.parse(saved);
4889
- if (previous.chainId !== i.chainId || !isAddressEqual(previous.from, i.owner) || !isAddressEqual(previous.token, i.token) || planOf(previous.transfers) !== plan)
4890
- throw new Error(
4891
- "Retry the previous token deposit and agent split first to reconcile its status."
4892
- );
4893
- i.onApproved?.();
4894
- return send({ ...previous, transfers: i.transfers });
4895
- }
4896
- const total = i.transfers.reduce((sum, t) => sum + BigInt(t.amount), 0n);
4897
- const [balance, allowance] = await Promise.all([
4898
- readErc20Balance(i.pub, i.token, i.owner),
4899
- readPermit2Allowance(i.pub, i.token, i.owner)
4900
- ]);
4901
- if (balance < total)
2605
+ async function ensureWalletOnChain(pub, wallet, expected) {
2606
+ const actual = await pub.getChainId();
2607
+ if (actual === expected) return;
2608
+ try {
2609
+ await wallet.switchChain({ id: expected });
2610
+ } catch (error) {
4902
2611
  throw new OwneyError(
4903
- "DEPOSIT_INSUFFICIENT_BALANCE",
4904
- "Insufficient token balance for this deposit."
2612
+ "CHAIN_MISMATCH",
2613
+ `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2614
+ {
2615
+ expectedChainId: expected,
2616
+ actualChainId: actual,
2617
+ cause: error instanceof Error ? error.message : String(error)
2618
+ }
4905
2619
  );
4906
- if (allowance < total && (i.chainId !== 8453 || !isAddressEqual(i.token, BASE_USDC_ADDRESS)))
2620
+ }
2621
+ const after = await pub.getChainId();
2622
+ if (after !== expected) {
4907
2623
  throw new OwneyError(
4908
- "PERMIT2_APPROVAL_REQUIRED",
4909
- "token deposits need a one-time Permit2 approval."
2624
+ "CHAIN_MISMATCH",
2625
+ `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2626
+ { expectedChainId: expected, actualChainId: after }
4910
2627
  );
4911
- const now = (await i.pub.getBlock()).timestamp;
4912
- let erc2612Permit;
4913
- if (allowance < total) {
4914
- const [tokenName, tokenVersion, permitNonce] = await Promise.all([
4915
- i.pub.readContract({
4916
- address: i.token,
4917
- abi: ERC2612_READ_ABI,
4918
- functionName: "name"
4919
- }),
4920
- i.pub.readContract({
4921
- address: i.token,
4922
- abi: ERC2612_READ_ABI,
4923
- functionName: "version"
4924
- }),
4925
- i.pub.readContract({
4926
- address: i.token,
4927
- abi: ERC2612_READ_ABI,
4928
- functionName: "nonces",
4929
- args: [i.owner]
4930
- })
4931
- ]);
4932
- const unsignedPermit = {
4933
- value: MAX_UINT256.toString(),
4934
- nonce: permitNonce.toString(),
4935
- deadline: (now + 900n).toString(),
4936
- tokenName,
4937
- tokenVersion
4938
- };
4939
- const signature2 = await i.wallet.signTypedData({
4940
- account: i.owner,
4941
- ...erc2612TypedData({
4942
- chainId: 8453,
4943
- token: i.token,
4944
- owner: i.owner,
4945
- permit: unsignedPermit
4946
- })
4947
- });
4948
- erc2612Permit = { ...unsignedPermit, signature: signature2 };
4949
2628
  }
4950
- const spender = erc2612Permit ? MULTICALL3_ADDRESS : await getSponsorRelayerAddress({
4951
- apiKey: i.apiKey,
4952
- baseUrl: i.baseUrl,
4953
- chainId: i.chainId
4954
- });
4955
- const unsigned = {
4956
- chainId: i.chainId,
4957
- token: i.token,
4958
- from: i.owner,
4959
- transfers: i.transfers,
4960
- nonce: randomPermit2Nonce().toString(),
4961
- deadline: (now + 900n).toString(),
4962
- ...erc2612Permit ? { erc2612Permit } : {}
4963
- };
4964
- const signature = await i.wallet.signTypedData({
4965
- account: i.owner,
4966
- ...batchTypedData(unsigned, spender)
4967
- });
4968
- i.onApproved?.();
4969
- return send({ ...unsigned, signature });
4970
2629
  }
4971
2630
 
4972
- // src/lib/sponsored-token-deposit.ts
4973
- function makeSponsoredTokenCallback(deps) {
4974
- const batch = async (chainId, transfers) => {
4975
- if (chainId !== 8453 && chainId !== 42161 && chainId !== 1)
2631
+ // src/lib/sponsored-deposit.ts
2632
+ var AUTH_WINDOW_SECONDS = 15 * 60;
2633
+ function makeSponsoredDepositCallback(deps) {
2634
+ const post = deps.httpPost ?? postSponsorTransferAuth;
2635
+ return async (smartWallet, chainId, amount) => {
2636
+ const cid = chainId;
2637
+ const token = deps.tokenAddressByChain[cid];
2638
+ if (!token) {
4976
2639
  throw new OwneyError(
4977
2640
  "CHAIN_UNSUPPORTED",
4978
2641
  `No sponsored token configured for chain ${chainId}`
4979
2642
  );
4980
- const token = deps.tokenAddressByChain[chainId];
4981
- if (!token)
4982
- throw new OwneyError(
4983
- "CHAIN_UNSUPPORTED",
4984
- `No sponsored token configured for chain ${chainId}`
2643
+ }
2644
+ const pub = deps.getPublicClient(cid);
2645
+ const wallet = deps.getWalletClient(cid);
2646
+ await ensureWalletOnChain(pub, wallet, cid);
2647
+ try {
2648
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2649
+ if (balance < BigInt(amount)) {
2650
+ throw new OwneyError(
2651
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2652
+ "Insufficient balance for this deposit.",
2653
+ { token, chainId: cid, balance: balance.toString(), amount }
2654
+ );
2655
+ }
2656
+ } catch (err) {
2657
+ if (err instanceof OwneyError) throw err;
2658
+ console.warn(
2659
+ "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2660
+ err instanceof Error ? err.message : String(err)
4985
2661
  );
4986
- const pub = deps.getPublicClient(chainId), walletChain = deps.getWalletChainClient?.(chainId) ?? pub, wallet = deps.getWalletClient(chainId);
4987
- await ensureWalletOnChain(walletChain, wallet, chainId);
4988
- return sponsorTokenBatch({
4989
- apiKey: deps.apiKey,
4990
- baseUrl: deps.baseUrl,
4991
- owner: deps.ownerAddress,
2662
+ }
2663
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2664
+ const validAfter = 0n;
2665
+ const validBefore = BigInt(
2666
+ Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2667
+ );
2668
+ const nonce = randomAuthNonce();
2669
+ const typedData = buildTransferWithAuthorizationTypedData({
4992
2670
  token,
4993
- chainId,
4994
- transfers,
4995
- pub,
4996
- wallet,
4997
- onApproved: deps.onApproved
2671
+ chainId: cid,
2672
+ tokenName,
2673
+ tokenVersion,
2674
+ message: {
2675
+ from: deps.ownerAddress,
2676
+ to: smartWallet,
2677
+ value: BigInt(amount),
2678
+ validAfter,
2679
+ validBefore,
2680
+ nonce
2681
+ }
2682
+ });
2683
+ const authSignature = await wallet.signTypedData({
2684
+ account: deps.ownerAddress,
2685
+ ...typedData
2686
+ });
2687
+ deps.onApproved?.();
2688
+ const result = await post({
2689
+ baseUrl: deps.baseUrl,
2690
+ apiKey: deps.apiKey,
2691
+ body: {
2692
+ chainId: cid,
2693
+ token,
2694
+ from: deps.ownerAddress,
2695
+ to: smartWallet,
2696
+ value: amount,
2697
+ validAfter: validAfter.toString(),
2698
+ validBefore: validBefore.toString(),
2699
+ nonce,
2700
+ authSignature,
2701
+ tokenName,
2702
+ tokenVersion
2703
+ }
4998
2704
  });
2705
+ return result.txHash;
4999
2706
  };
5000
- const callback = makeVerificationAwareDepositCallback(
5001
- (to, chainId, amount, verification) => batch(chainId, [toBatchTransfer(to, amount, verification)])
5002
- );
5003
- registerDepositBatch(callback, batch);
5004
- return callback;
5005
2707
  }
5006
2708
 
5007
- // src/lib/agent-deposit-batch.ts
5008
- function deferred() {
5009
- let resolve, reject;
5010
- const promise = new Promise((yes, no) => {
5011
- resolve = yes;
5012
- reject = no;
5013
- });
5014
- void promise.catch(() => {
5015
- });
5016
- return { promise, resolve, reject };
5017
- }
5018
- async function runAgentDepositBatch(chainId, legs, transfer) {
5019
- const funding = deferred();
5020
- const tasks = [];
5021
- const transfers = [];
5022
- try {
5023
- for (const leg of legs) {
5024
- const ready = deferred();
5025
- let entered = false;
5026
- const callback = makeVerificationAwareDepositCallback(
5027
- (to, cid, amount, verification) => {
5028
- if (entered || cid !== chainId || BigInt(amount) !== BigInt(leg.amount)) {
5029
- const error = new Error(
5030
- "Agent changed its prepared deposit share."
5031
- );
5032
- ready.reject(error);
5033
- throw error;
5034
- }
5035
- entered = true;
5036
- ready.resolve(toBatchTransfer(to, amount, verification));
5037
- return funding.promise;
5038
- }
5039
- );
5040
- const task = Promise.resolve().then(() => leg.run(callback));
5041
- tasks.push(task);
5042
- void task.then(
5043
- () => {
5044
- if (!entered)
5045
- ready.reject(
5046
- new Error("Agent did not prepare a deposit transfer.")
5047
- );
5048
- },
5049
- (error) => ready.reject(error)
2709
+ // src/lib/sponsored-weth-deposit.ts
2710
+ var PERMIT_WINDOW_SECONDS = 15 * 60;
2711
+ function makeSponsoredWethCallback(deps) {
2712
+ const get = deps.httpGet ?? getSponsorRelayerAddress;
2713
+ const post = deps.httpPost ?? postSponsorPermit2Transfer;
2714
+ return async (smartWallet, chainId, amount) => {
2715
+ const cid = chainId;
2716
+ const token = deps.tokenAddressByChain[cid];
2717
+ if (!token) {
2718
+ throw new OwneyError(
2719
+ "CHAIN_UNSUPPORTED",
2720
+ `No sponsored WETH configured for chain ${chainId}`
5050
2721
  );
5051
- transfers.push(await ready.promise);
5052
2722
  }
5053
- const txHash = await transfer(chainId, transfers);
5054
- funding.resolve(txHash);
5055
- const settled = await Promise.allSettled(tasks);
5056
- const agentResults = {};
5057
- const failures = [];
5058
- for (const [index, result] of settled.entries()) {
5059
- if (result.status === "fulfilled")
5060
- agentResults[legs[index].id] = result.value;
5061
- else failures.push(legs[index].id);
2723
+ const amountWei = BigInt(amount);
2724
+ const pub = deps.getPublicClient(cid);
2725
+ const wallet = deps.getWalletClient(cid);
2726
+ await ensureWalletOnChain(pub, wallet, cid);
2727
+ try {
2728
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2729
+ if (balance < amountWei) {
2730
+ throw new OwneyError(
2731
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2732
+ "Insufficient WETH balance for this deposit.",
2733
+ { token, chainId: cid, balance: balance.toString(), amount }
2734
+ );
2735
+ }
2736
+ } catch (err) {
2737
+ if (err instanceof OwneyError) throw err;
2738
+ console.warn(
2739
+ "[owney-sdk] WETH balance pre-check failed (non-fatal):",
2740
+ err instanceof Error ? err.message : String(err)
2741
+ );
5062
2742
  }
5063
- if (failures.length)
2743
+ const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
2744
+ if (allowance < amountWei) {
5064
2745
  throw new OwneyError(
5065
- "DEPOSIT_PARTIAL_FAILURE",
5066
- "The deposit was sent to all agents, but some agent updates could not be confirmed. Check activity before depositing again.",
5067
- {
5068
- txHash,
5069
- fundsSubmitted: true,
5070
- agentResults,
5071
- failedAgentIds: failures
5072
- }
2746
+ "PERMIT2_APPROVAL_REQUIRED",
2747
+ "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
2748
+ { token, chainId: cid, allowance: allowance.toString(), amount }
5073
2749
  );
5074
- return { agentResults };
5075
- } catch (error) {
5076
- funding.reject(error);
5077
- await Promise.allSettled(tasks);
5078
- throw error;
5079
- }
2750
+ }
2751
+ const relayer = await get({
2752
+ baseUrl: deps.baseUrl,
2753
+ apiKey: deps.apiKey,
2754
+ chainId: cid
2755
+ });
2756
+ const nonce = randomPermit2Nonce();
2757
+ const deadline = BigInt(
2758
+ Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2759
+ );
2760
+ const typedData = buildPermitTransferFromTypedData({
2761
+ chainId: cid,
2762
+ message: {
2763
+ permitted: { token, amount: amountWei },
2764
+ spender: relayer,
2765
+ nonce,
2766
+ deadline
2767
+ }
2768
+ });
2769
+ const signature = await wallet.signTypedData({
2770
+ account: deps.ownerAddress,
2771
+ ...typedData
2772
+ });
2773
+ deps.onApproved?.();
2774
+ const result = await post({
2775
+ baseUrl: deps.baseUrl,
2776
+ apiKey: deps.apiKey,
2777
+ body: {
2778
+ chainId: cid,
2779
+ token,
2780
+ from: deps.ownerAddress,
2781
+ to: smartWallet,
2782
+ amount,
2783
+ nonce: nonce.toString(),
2784
+ deadline: deadline.toString(),
2785
+ signature
2786
+ }
2787
+ });
2788
+ return result.txHash;
2789
+ };
5080
2790
  }
5081
2791
 
5082
2792
  // src/lib/sponsored-calls-deposit.ts
5083
- import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi2, toHex } from "viem";
2793
+ import { encodeFunctionData, erc20Abi, toHex } from "viem";
5084
2794
  var DEFAULT_POLL_INTERVAL_MS = 1500;
5085
2795
  var DEFAULT_MAX_POLLS = 30;
5086
2796
  async function paymasterSupported(provider, owner, chainId) {
@@ -5106,7 +2816,7 @@ function makeSponsoredCallsCallback(deps) {
5106
2816
  }
5107
2817
  return new URL(configured, origin).toString();
5108
2818
  };
5109
- const batch = async (chainId, transfers) => {
2819
+ return async (smartWallet, chainId, amount) => {
5110
2820
  const cid = chainId;
5111
2821
  const token = deps.tokenAddressByChain[cid];
5112
2822
  if (!token) {
@@ -5122,42 +2832,11 @@ function makeSponsoredCallsCallback(deps) {
5122
2832
  { chainId }
5123
2833
  );
5124
2834
  }
5125
- const calls = transfers.map((transfer) => ({
5126
- to: token,
5127
- value: "0x0",
5128
- data: encodeFunctionData2({
5129
- abi: erc20Abi2,
5130
- functionName: "transfer",
5131
- args: [transfer.to, BigInt(transfer.amount)]
5132
- })
5133
- }));
5134
- let paymasterUrl = absolutePaymasterUrl();
5135
- for (const transfer of transfers) {
5136
- const verification = transfer.yieldseeker;
5137
- if (!verification) continue;
5138
- if (chainId !== 8453)
5139
- throw new OwneyError(
5140
- "CHAIN_UNSUPPORTED",
5141
- `Yieldseeker sponsorship is not available on chain ${chainId}.`
5142
- );
5143
- const { intent } = await postPaymasterIntent({
5144
- baseUrl: deps.routingApiBaseUrl,
5145
- apiKey: deps.apiKey,
5146
- yieldseekerSignature: verification.signature,
5147
- body: {
5148
- chainId,
5149
- token,
5150
- from: deps.ownerAddress,
5151
- to: transfer.to,
5152
- amount: transfer.amount,
5153
- yieldseekerUserId: verification.userId,
5154
- yieldseekerAgentId: verification.agentId
5155
- }
5156
- });
5157
- const url = new URL(paymasterUrl);
5158
- url.searchParams.append("owneyIntent", intent);
5159
- paymasterUrl = url.toString();
5160
- }
2835
+ const data = encodeFunctionData({
2836
+ abi: erc20Abi,
2837
+ functionName: "transfer",
2838
+ args: [smartWallet, BigInt(amount)]
2839
+ });
5161
2840
  const sendResult = await deps.provider.request({
5162
2841
  method: "wallet_sendCalls",
5163
2842
  params: [
@@ -5165,10 +2844,10 @@ function makeSponsoredCallsCallback(deps) {
5165
2844
  version: "2.0.0",
5166
2845
  from: deps.ownerAddress,
5167
2846
  chainId: toHex(chainId),
5168
- atomicRequired: transfers.length > 1,
5169
- calls,
2847
+ atomicRequired: false,
2848
+ calls: [{ to: token, value: "0x0", data }],
5170
2849
  capabilities: {
5171
- paymasterService: { url: paymasterUrl }
2850
+ paymasterService: { url: absolutePaymasterUrl() }
5172
2851
  }
5173
2852
  }
5174
2853
  ]
@@ -5188,24 +2867,7 @@ function makeSponsoredCallsCallback(deps) {
5188
2867
  params: [callsId]
5189
2868
  });
5190
2869
  const txHash = status?.receipts?.[0]?.transactionHash;
5191
- if (status?.receipts?.some((receipt) => receipt.status === "0x0") || typeof status?.status === "number" && status.status >= 400) {
5192
- throw new OwneyError(
5193
- "SPONSOR_REQUEST_FAILED",
5194
- "The sponsored deposit did not complete successfully.",
5195
- { chainId, callsId, safeToFallback: false }
5196
- );
5197
- }
5198
- if (txHash && (transfers.length === 1 || status?.status === 200 || status?.status === "CONFIRMED")) {
5199
- if (status?.receipts?.some(
5200
- (receipt) => receipt.transactionHash !== txHash
5201
- ))
5202
- throw new OwneyError(
5203
- "SPONSORED_CALLS_NO_RECEIPT",
5204
- "The wallet returned multiple transactions for an atomic deposit. Check activity before trying again.",
5205
- { chainId, callsId }
5206
- );
5207
- return txHash;
5208
- }
2870
+ if (txHash) return txHash;
5209
2871
  if (pollIntervalMs > 0) {
5210
2872
  await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
5211
2873
  }
@@ -5216,16 +2878,9 @@ function makeSponsoredCallsCallback(deps) {
5216
2878
  { chainId, callsId }
5217
2879
  );
5218
2880
  };
5219
- const callback = makeVerificationAwareDepositCallback(
5220
- (to, chainId, amount, verification) => batch(chainId, [toBatchTransfer(to, amount, verification)])
5221
- );
5222
- registerDepositBatch(callback, batch);
5223
- return callback;
5224
2881
  }
5225
2882
 
5226
2883
  // src/client.ts
5227
- var PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS = 6;
5228
- var PERMIT2_ALLOWANCE_VERIFY_DELAY_MS = 250;
5229
2884
  function encodeMultiAgentCursor(map) {
5230
2885
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
5231
2886
  }
@@ -5252,7 +2907,7 @@ var SPONSORED_USDC_BY_CHAIN = {
5252
2907
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
5253
2908
  };
5254
2909
  var VIEM_CHAIN2 = {
5255
- 8453: base4,
2910
+ 8453: base2,
5256
2911
  42161: arbitrum2,
5257
2912
  1: mainnet2
5258
2913
  };
@@ -5261,11 +2916,6 @@ var SPONSORED_WETH_BY_CHAIN = {
5261
2916
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
5262
2917
  1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
5263
2918
  };
5264
- var SPONSORED_TOKENS_BY_ASSET = { USDC: SPONSORED_USDC_BY_CHAIN, WETH: SPONSORED_WETH_BY_CHAIN };
5265
- function sponsoredTokensFor(asset) {
5266
- if (!Object.prototype.hasOwnProperty.call(SPONSORED_TOKENS_BY_ASSET, asset)) throw new OwneyError("ASSET_UNSUPPORTED", `No sponsored token configured for ${asset}`);
5267
- return SPONSORED_TOKENS_BY_ASSET[asset];
5268
- }
5269
2919
  function shouldFallbackToUserPaid(error, asset, appCallback) {
5270
2920
  return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
5271
2921
  }
@@ -5286,10 +2936,7 @@ var OwneySDK = class {
5286
2936
  // leave every user's agent profile alone.
5287
2937
  orgAgentConfig;
5288
2938
  orgAgentConfigPromise = null;
5289
- rpcUrls;
5290
2939
  zyfaiRpcUrls;
5291
- yieldseekerApiBaseUrl;
5292
- yieldseekerSiweOrigin;
5293
2940
  routingApiBaseUrl;
5294
2941
  referralSource;
5295
2942
  cachedSponsoredCallback = null;
@@ -5311,14 +2958,7 @@ var OwneySDK = class {
5311
2958
  constructor(config) {
5312
2959
  this.apiKey = config.apiKey;
5313
2960
  if (config.debug) setOwneyDebug(true);
5314
- this.rpcUrls = resolveRpcUrls(
5315
- config.rpcUrls,
5316
- config.apiKey,
5317
- config.routingApiBaseUrl
5318
- );
5319
- this.zyfaiRpcUrls = config.rpcUrls ? void 0 : config.zyfaiRpcUrls;
5320
- this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
5321
- this.yieldseekerSiweOrigin = config.yieldseekerSiweOrigin;
2961
+ this.zyfaiRpcUrls = config.zyfaiRpcUrls;
5322
2962
  this.routingApiBaseUrl = config.routingApiBaseUrl;
5323
2963
  this.paymasterServiceUrl = config.paymasterServiceUrl;
5324
2964
  this.referralSource = config.referralSource;
@@ -5352,7 +2992,6 @@ var OwneySDK = class {
5352
2992
  * After calling this, `connect()` must be called again before using agent methods.
5353
2993
  */
5354
2994
  async disconnect() {
5355
- this.state = null;
5356
2995
  for (const agent of this.agents.values()) {
5357
2996
  await agent.disconnect();
5358
2997
  }
@@ -5406,16 +3045,18 @@ var OwneySDK = class {
5406
3045
  }
5407
3046
  return this.state.provider;
5408
3047
  }
5409
- getPaidRpcClient(chainId) {
5410
- return createPaidRpcClient(VIEM_CHAIN2[chainId], this.rpcUrls);
5411
- }
5412
- /** Builds the default USDC batch callback for the connected wallet. */
3048
+ /**
3049
+ * Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
3050
+ * used when the caller omits `depositCallback`. Wraps the connected EIP-1193
3051
+ * provider with viem `custom(provider)` to read token meta and sign the
3052
+ * `TransferWithAuthorization`, then POSTs to the sponsor API.
3053
+ */
5413
3054
  getDefaultSponsoredCallback(onApproved) {
5414
3055
  if (!onApproved && this.cachedSponsoredCallback)
5415
3056
  return this.cachedSponsoredCallback;
5416
3057
  const provider = this.requireConnectedProvider();
5417
3058
  const owner = this.state.walletAddress;
5418
- const callback = makeSponsoredTokenCallback({
3059
+ const callback = makeSponsoredDepositCallback({
5419
3060
  apiKey: this.apiKey,
5420
3061
  baseUrl: this.routingApiBaseUrl,
5421
3062
  ownerAddress: owner,
@@ -5424,33 +3065,35 @@ var OwneySDK = class {
5424
3065
  // Casts work around viem's chain-narrowed Client vs the generic
5425
3066
  // PublicClient/WalletClient param types — structurally identical at
5426
3067
  // runtime, but the two share a name TS treats as unrelated.
5427
- getPublicClient: (cid) => this.getPaidRpcClient(cid),
5428
- getWalletChainClient: (cid) => createPublicClient4({
3068
+ getPublicClient: (cid) => createPublicClient2({
5429
3069
  chain: VIEM_CHAIN2[cid],
5430
- transport: custom3(provider)
3070
+ transport: custom(provider)
5431
3071
  }),
5432
- getWalletClient: (cid) => createWalletClient3({
3072
+ getWalletClient: (cid) => createWalletClient({
5433
3073
  account: owner,
5434
3074
  chain: VIEM_CHAIN2[cid],
5435
- transport: custom3(provider)
3075
+ transport: custom(provider)
5436
3076
  })
5437
3077
  });
5438
3078
  if (!onApproved) this.cachedSponsoredCallback = callback;
5439
3079
  return callback;
5440
3080
  }
5441
- /** Builds the wallet-native sponsored calls callback for compatible paymasters. */
3081
+ /**
3082
+ * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
3083
+ * callback used when the caller omits `depositCallback` for a WETH
3084
+ * deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
3085
+ * `PermitTransferFrom` instead of an EIP-3009 authorization.
3086
+ */
5442
3087
  getDefaultSponsoredCallsCallback(asset, onApproved) {
5443
3088
  const cached = this.cachedSponsoredCallsCallbacks.get(asset);
5444
3089
  if (!onApproved && cached) return cached;
5445
3090
  const provider = this.requireConnectedProvider();
5446
3091
  const callback = makeSponsoredCallsCallback({
5447
- apiKey: this.apiKey,
5448
- routingApiBaseUrl: this.routingApiBaseUrl,
5449
3092
  provider,
5450
3093
  ownerAddress: this.state.walletAddress,
5451
3094
  paymasterServiceUrl: this.paymasterServiceUrl,
5452
3095
  onApproved,
5453
- tokenAddressByChain: sponsoredTokensFor(asset)
3096
+ tokenAddressByChain: asset === "WETH" ? SPONSORED_WETH_BY_CHAIN : SPONSORED_USDC_BY_CHAIN
5454
3097
  });
5455
3098
  if (!onApproved) this.cachedSponsoredCallsCallbacks.set(asset, callback);
5456
3099
  return callback;
@@ -5459,14 +3102,14 @@ var OwneySDK = class {
5459
3102
  * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
5460
3103
  * callback used when the caller omits `depositCallback` for a WETH deposit.
5461
3104
  * Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
5462
- * single-use batch authorization instead of an EIP-3009 authorization.
3105
+ * `PermitTransferFrom` instead of an EIP-3009 authorization.
5463
3106
  */
5464
3107
  getDefaultWethSponsoredCallback(onApproved) {
5465
3108
  if (!onApproved && this.cachedWethSponsoredCallback)
5466
3109
  return this.cachedWethSponsoredCallback;
5467
3110
  const provider = this.requireConnectedProvider();
5468
3111
  const owner = this.state.walletAddress;
5469
- const callback = makeSponsoredTokenCallback({
3112
+ const callback = makeSponsoredWethCallback({
5470
3113
  apiKey: this.apiKey,
5471
3114
  baseUrl: this.routingApiBaseUrl,
5472
3115
  ownerAddress: owner,
@@ -5475,15 +3118,14 @@ var OwneySDK = class {
5475
3118
  // Casts work around viem's chain-narrowed Client vs the generic
5476
3119
  // PublicClient/WalletClient param types — structurally identical at
5477
3120
  // runtime, but the two share a name TS treats as unrelated.
5478
- getPublicClient: (cid) => this.getPaidRpcClient(cid),
5479
- getWalletChainClient: (cid) => createPublicClient4({
3121
+ getPublicClient: (cid) => createPublicClient2({
5480
3122
  chain: VIEM_CHAIN2[cid],
5481
- transport: custom3(provider)
3123
+ transport: custom(provider)
5482
3124
  }),
5483
- getWalletClient: (cid) => createWalletClient3({
3125
+ getWalletClient: (cid) => createWalletClient({
5484
3126
  account: owner,
5485
3127
  chain: VIEM_CHAIN2[cid],
5486
- transport: custom3(provider)
3128
+ transport: custom(provider)
5487
3129
  })
5488
3130
  });
5489
3131
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -5514,10 +3156,12 @@ var OwneySDK = class {
5514
3156
  this.orgAgentConfigPromise = fetchOrgAgentConfig(
5515
3157
  this.apiKey,
5516
3158
  this.routingApiBaseUrl
5517
- ).then((config) => {
5518
- this.orgAgentConfig = config;
5519
- return config;
5520
- });
3159
+ ).then(
3160
+ (config) => {
3161
+ this.orgAgentConfig = config;
3162
+ return config;
3163
+ }
3164
+ );
5521
3165
  }
5522
3166
  return this.orgAgentConfigPromise;
5523
3167
  }
@@ -5557,14 +3201,7 @@ var OwneySDK = class {
5557
3201
  this.routingApiBaseUrl
5558
3202
  );
5559
3203
  this.disabledAgents.clear();
5560
- for (const {
5561
- key: key2,
5562
- agent_type,
5563
- is_enabled,
5564
- is_configured
5565
- } of agentKeys) {
5566
- const configured = is_configured ?? Boolean(key2);
5567
- if (!configured) continue;
3204
+ for (const { key: key2, agent_type, is_enabled } of agentKeys) {
5568
3205
  const agent = this.createAgent(agent_type, key2);
5569
3206
  if (!agent) continue;
5570
3207
  this.agents.set(agent_type, agent);
@@ -5588,23 +3225,7 @@ var OwneySDK = class {
5588
3225
  }
5589
3226
  createAgent(agentId, key2) {
5590
3227
  if (agentId === "zyfai") {
5591
- if (!key2) return null;
5592
- return new ZyfaiAgent(
5593
- key2,
5594
- this.zyfaiRpcUrls ? resolveRpcUrls(
5595
- this.zyfaiRpcUrls,
5596
- this.apiKey,
5597
- this.routingApiBaseUrl
5598
- ) : this.rpcUrls,
5599
- this.referralSource
5600
- );
5601
- }
5602
- if (agentId === "yieldseeker") {
5603
- return new YieldseekerAgent(this.apiKey, {
5604
- auth: { origin: this.yieldseekerSiweOrigin },
5605
- baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl),
5606
- rpcUrls: this.rpcUrls
5607
- });
3228
+ return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
5608
3229
  }
5609
3230
  return null;
5610
3231
  }
@@ -5650,10 +3271,9 @@ var OwneySDK = class {
5650
3271
  * If provided, ALL specified agents must support the chainId or the call
5651
3272
  * throws before activating any agent.
5652
3273
  */
5653
- async activateAgent(chainId, agentId, asset) {
3274
+ async activateAgent(chainId, agentId) {
5654
3275
  const state = this.requireState();
5655
3276
  await this.ensureAgentsInitialized();
5656
- this.assertActivationSession(state);
5657
3277
  if (agentId !== void 0) {
5658
3278
  if (agentId.length === 0) {
5659
3279
  throw new OwneyError(
@@ -5687,7 +3307,7 @@ var OwneySDK = class {
5687
3307
  this.activeAgents.add(id);
5688
3308
  }
5689
3309
  state.chainId = chainId;
5690
- await this.activateAgentsInTurn(agents, state, chainId, asset);
3310
+ await this.activateAgentsInTurn(agents, state, chainId);
5691
3311
  return;
5692
3312
  }
5693
3313
  const compatible = [...this.agents.values()].filter(
@@ -5708,12 +3328,7 @@ var OwneySDK = class {
5708
3328
  const enabledCompatible = compatible.filter(
5709
3329
  (agent) => !this.isAgentDisabled(agent.id)
5710
3330
  );
5711
- await this.activateAgentsInTurn(enabledCompatible, state, chainId, asset);
5712
- }
5713
- assertActivationSession(state) {
5714
- if (this.state !== state) {
5715
- throw new OwneyError("NOT_CONNECTED", "Wallet connection changed. Please try again.");
5716
- }
3331
+ await this.activateAgentsInTurn(enabledCompatible, state, chainId);
5717
3332
  }
5718
3333
  /**
5719
3334
  * Activate agents ONE AT A TIME, each followed by its org policy.
@@ -5728,51 +3343,26 @@ var OwneySDK = class {
5728
3343
  * Serializing costs no real wall-clock: the user can only approve one prompt
5729
3344
  * at a time anyway.
5730
3345
  *
5731
- * Stop at the first failure so a canceled sign-in does not open another
5732
- * agent's wallet prompt. Report any earlier successes for diagnostics; the
5733
- * app discards the session when the complete sign-in does not succeed.
3346
+ * Every agent is attempted even if an earlier one fails, so one declined
3347
+ * signature can't deny the remaining agents their turn. The first failure is
3348
+ * rethrown (matching the previous `Promise.all` rejection) once all agents
3349
+ * have had a chance to activate.
5734
3350
  */
5735
- async activateAgentsInTurn(agents, state, chainId, asset) {
3351
+ async activateAgentsInTurn(agents, state, chainId) {
5736
3352
  let firstError = null;
5737
- const activatedAgentIds = [];
5738
- const failedAgents = [];
5739
3353
  for (const agent of agents) {
5740
- this.assertActivationSession(state);
5741
3354
  try {
5742
- await agent.activateAgent(state, chainId, asset);
5743
- this.assertActivationSession(state);
3355
+ await agent.activateAgent(state, chainId);
5744
3356
  await this.applyOrgPolicyTo(agent, state, chainId);
5745
- this.assertActivationSession(state);
5746
- activatedAgentIds.push(agent.id);
5747
3357
  } catch (error) {
5748
- this.assertActivationSession(state);
5749
- 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.";
5750
- failedAgents.push({
5751
- agentId: agent.id,
5752
- code: error instanceof OwneyError ? error.code : void 0,
5753
- message,
5754
- ...error instanceof OwneyError && error.details ? { details: error.details } : {}
5755
- });
5756
3358
  if (firstError === null) {
5757
3359
  firstError = error;
5758
3360
  } else {
5759
3361
  console.error(`activateAgent(${agent.id}) failed:`, error);
5760
3362
  }
5761
- break;
5762
3363
  }
5763
3364
  }
5764
- if (firstError === null) return;
5765
- if (activatedAgentIds.length === 0) throw firstError;
5766
- const failedAgentIds = failedAgents.map(({ agentId }) => agentId);
5767
- const activeNames = activatedAgentIds.map(this.formatAgentName).join(", ");
5768
- const failureMessages = failedAgents.map(
5769
- ({ agentId, message }) => `${this.formatAgentName(agentId)} activation failed: ${message}`
5770
- ).join(" ");
5771
- throw new OwneyError(
5772
- "AGENT_ACTIVATION_PARTIAL_FAILURE",
5773
- `${activeNames} activated. ${failureMessages}`,
5774
- { activatedAgentIds, failedAgentIds, failures: failedAgents }
5775
- );
3365
+ if (firstError !== null) throw firstError;
5776
3366
  }
5777
3367
  /**
5778
3368
  * Deposit into a specific agent, or distribute across all eligible agents.
@@ -5782,8 +3372,7 @@ var OwneySDK = class {
5782
3372
  * @param options.asset - Asset symbol to deposit (e.g. "USDC")
5783
3373
  * @param options.depositCallback - Callback that performs the token transfer and returns a tx hash.
5784
3374
  * When agentId is omitted, this callback is invoked once per eligible agent with that agent's
5785
- * split amount and smart wallet address. Default sponsored deposits batch
5786
- * all shares into one signature; custom callbacks still run once per agent.
3375
+ * split amount and smart wallet address — expect multiple wallet prompts.
5787
3376
  * @param options.agentId - Optional explicit target. Otherwise split equally,
5788
3377
  * or fund remaining agents when a recovery deposit cannot meet every minimum.
5789
3378
  * @returns {OwneyDepositResult} for a single agent, or {OwneyMultiDepositResult} with per-agent results
@@ -5868,40 +3457,6 @@ var OwneySDK = class {
5868
3457
  }
5869
3458
  );
5870
3459
  }
5871
- const batchTransfer = getDepositBatchTransfer(effectiveCallback);
5872
- if (!depositCallback && batchTransfer) {
5873
- return runAgentDepositBatch(
5874
- chainId,
5875
- agentAmounts.map(({ agent, amount: amount2 }) => ({
5876
- id: agent.id,
5877
- amount: amount2,
5878
- run: (callback) => withFailureReporting(
5879
- this.apiKey,
5880
- agent.id,
5881
- () => agent.deposit(state, chainId, amount2, asset, callback),
5882
- this.routingApiBaseUrl
5883
- )
5884
- })),
5885
- async (cid, transfers) => {
5886
- try {
5887
- return await batchTransfer(cid, transfers);
5888
- } catch (error) {
5889
- if (!(error instanceof OwneyError) || error.code !== "PERMIT2_APPROVAL_REQUIRED")
5890
- throw error;
5891
- const requiredAmount = transfers.reduce(
5892
- (sum, transfer) => sum + BigInt(transfer.amount),
5893
- 0n
5894
- );
5895
- await this.approvePermit2(
5896
- asset,
5897
- requiredAmount,
5898
- cid
5899
- );
5900
- return batchTransfer(cid, transfers);
5901
- }
5902
- }
5903
- );
5904
- }
5905
3460
  const agentResults = {};
5906
3461
  for (const [
5907
3462
  index,
@@ -5939,12 +3494,10 @@ var OwneySDK = class {
5939
3494
  * Invokes `agent.deposit` with the resolved sponsored callback, composing
5940
3495
  * two independent auto-recovery mechanisms:
5941
3496
  *
5942
- * 1. Missing Permit2 allowance outside the atomic Base-USDC path: when the
5943
- * app did not supply its own callback and the attempt fails with
5944
- * `PERMIT2_APPROVAL_REQUIRED`, this is the wallet's first Permit2 deposit
5945
- * for that token. Base USDC bundles a gasless ERC-2612 approval inside
5946
- * its sponsored deposit and never reaches this branch. Other tokens send
5947
- * the one-time user-paid Permit2 approval via `approvePermit2()` and
3497
+ * 1. Missing Permit2 allowance: when the app did not supply its own
3498
+ * callback and the attempt fails with `PERMIT2_APPROVAL_REQUIRED` on a
3499
+ * WETH deposit, this is the wallet's first gasless WETH deposit. We send
3500
+ * the one-time (user-paid) Permit2 approval via `approvePermit2()` and
5948
3501
  * retry the SAME sponsored attempt once. Bounded to one approval attempt
5949
3502
  * per call so a wallet/agent that keeps reporting the allowance as
5950
3503
  * missing can't loop forever. If `approvePermit2()` itself throws (e.g.
@@ -5980,16 +3533,12 @@ var OwneySDK = class {
5980
3533
  try {
5981
3534
  return await attempt(effectiveCallback);
5982
3535
  } catch (error) {
5983
- if (!approvalAttempted && appCallback === void 0 && (asset === "WETH" || asset === "USDC") && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
3536
+ if (!approvalAttempted && appCallback === void 0 && asset === "WETH" && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
5984
3537
  approvalAttempted = true;
5985
3538
  console.warn(
5986
- "[owney-sdk] First token deposit: sending one-time Permit2 approval..."
5987
- );
5988
- await this.approvePermit2(
5989
- asset,
5990
- BigInt(amount),
5991
- chainId
3539
+ "[owney-sdk] First WETH deposit: sending one-time Permit2 approval..."
5992
3540
  );
3541
+ await this.approvePermit2();
5993
3542
  continue;
5994
3543
  }
5995
3544
  if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
@@ -6027,10 +3576,10 @@ var OwneySDK = class {
6027
3576
  agent,
6028
3577
  amount: i === agents.length - 1 ? perAgent + remainder : perAgent
6029
3578
  }));
6030
- const valid2 = splits.filter(
3579
+ const valid = splits.filter(
6031
3580
  (s) => s.amount > 0n && (exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset))
6032
3581
  );
6033
- if (valid2.length === agents.length) {
3582
+ if (valid.length === agents.length) {
6034
3583
  return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
6035
3584
  }
6036
3585
  const targets = agentsRequiringActivation.length > 0 ? agentsRequiringActivation : agents;
@@ -6049,11 +3598,6 @@ var OwneySDK = class {
6049
3598
  )
6050
3599
  }));
6051
3600
  }
6052
- formatAgentName(agentId) {
6053
- if (agentId === "zyfai") return "Zyfai";
6054
- if (agentId === "yieldseeker") return "Yieldseeker";
6055
- return agentId;
6056
- }
6057
3601
  async validateMinDepositAmount(agent, state, chainId, asset, amount) {
6058
3602
  const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
6059
3603
  const parsedAmount = BigInt(amount);
@@ -6085,12 +3629,12 @@ var OwneySDK = class {
6085
3629
  (t) => t.chainId === chainId && t.asset.toLowerCase() === target
6086
3630
  );
6087
3631
  const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
6088
- const position2 = (balance.positions ?? []).find((p) => {
3632
+ const position = (balance.positions ?? []).find((p) => {
6089
3633
  const positionChain = p.chain.trim().toUpperCase();
6090
3634
  const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
6091
3635
  return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
6092
3636
  });
6093
- return !!token && Number(token.amount) > 0 || !!position2;
3637
+ return !!token && Number(token.amount) > 0 || !!position;
6094
3638
  } catch (error) {
6095
3639
  if (requireReliableRead) {
6096
3640
  throw new OwneyError(
@@ -6135,32 +3679,6 @@ var OwneySDK = class {
6135
3679
  }
6136
3680
  return eligible;
6137
3681
  }
6138
- /**
6139
- * Run owner-approved withdrawals before relayer-only withdrawals. Wallet
6140
- * approval is the only point at which the user can cancel the aggregate
6141
- * operation, so no relayer leg should commit before it has completed.
6142
- */
6143
- orderAgentsForWithdrawal(agents) {
6144
- return agents.map((agent, index) => ({ agent, index })).sort((left, right) => {
6145
- const approvalOrder = Number(Boolean(right.agent.withdrawalRequiresWalletApproval)) - Number(Boolean(left.agent.withdrawalRequiresWalletApproval));
6146
- return approvalOrder || left.index - right.index;
6147
- }).map(({ agent }) => agent);
6148
- }
6149
- isUserRejectedWithdrawal(error) {
6150
- let current = error;
6151
- const seen = /* @__PURE__ */ new Set();
6152
- while (current && typeof current === "object" && !seen.has(current)) {
6153
- seen.add(current);
6154
- const candidate = current;
6155
- if (candidate.code === 4001 || candidate.code === "4001") return true;
6156
- const message = [candidate.message, candidate.shortMessage].filter((value) => typeof value === "string").join(" ");
6157
- if (/user (?:rejected|denied)|rejected by user/i.test(message)) {
6158
- return true;
6159
- }
6160
- current = candidate.cause;
6161
- }
6162
- return false;
6163
- }
6164
3682
  // --- Fund operations ---
6165
3683
  /**
6166
3684
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
@@ -6172,14 +3690,7 @@ var OwneySDK = class {
6172
3690
  * @returns {AgentWithdrawResult} for a single agent, or {OwneyWithdrawResult} with per-agent results
6173
3691
  */
6174
3692
  async withdraw(options) {
6175
- const { asset, amount, agentId, onAgentResult } = options;
6176
- const notifyAgentResult = (id, result) => {
6177
- try {
6178
- onAgentResult?.(id, result);
6179
- } catch (error) {
6180
- console.warn("Withdrawal result observer failed:", error);
6181
- }
6182
- };
3693
+ const { asset, amount, agentId } = options;
6183
3694
  const state = this.requireState();
6184
3695
  const chainId = this.requireChainId();
6185
3696
  const token = asset;
@@ -6195,26 +3706,21 @@ var OwneySDK = class {
6195
3706
  if (agentId) {
6196
3707
  const agent = this.getAgent(agentId);
6197
3708
  this.validateAssetSupport(agent, chainId, asset);
6198
- const result = await withFailureReporting(
3709
+ return withFailureReporting(
6199
3710
  this.apiKey,
6200
3711
  agent.id,
6201
3712
  () => agent.withdraw(state, chainId, token, amount),
6202
3713
  this.routingApiBaseUrl
6203
3714
  );
6204
- notifyAgentResult(agent.id, result);
6205
- return result;
6206
3715
  }
6207
3716
  const eligibleAgents = this.getEligibleAgents(chainId, asset);
6208
- const withdrawalAgents = this.orderAgentsForWithdrawal(eligibleAgents);
6209
3717
  if (!amount) {
6210
3718
  const results2 = {};
6211
3719
  const agentErrors2 = {};
6212
- for (const agent of withdrawalAgents) {
3720
+ for (const agent of eligibleAgents) {
6213
3721
  try {
6214
3722
  results2[agent.id] = await agent.withdraw(state, chainId, token);
6215
- notifyAgentResult(agent.id, results2[agent.id]);
6216
3723
  } catch (err) {
6217
- if (this.isUserRejectedWithdrawal(err)) throw err;
6218
3724
  console.error(`withdraw failed for agent "${agent.id}":`, err);
6219
3725
  agentErrors2[agent.id] = err instanceof Error ? err.message : String(err);
6220
3726
  const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
@@ -6243,10 +3749,6 @@ var OwneySDK = class {
6243
3749
  }
6244
3750
  const requested = BigInt(amount);
6245
3751
  const aggregated = await this.getBalances();
6246
- const unavailableAgents = eligibleAgents.filter(
6247
- (agent) => !(agent.id in aggregated.agentBalances)
6248
- );
6249
- const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
6250
3752
  const balances = projectAgentBalancesForAsset(
6251
3753
  eligibleAgents,
6252
3754
  aggregated.agentBalances,
@@ -6255,18 +3757,7 @@ var OwneySDK = class {
6255
3757
  assetInfo.decimals
6256
3758
  );
6257
3759
  const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
6258
- if (totalAvailable === 0n && unavailableAgents.length > 0) {
6259
- throw new OwneyError(
6260
- "WITHDRAW_BALANCE_UNAVAILABLE",
6261
- `Cannot safely plan the withdrawal because balance data is unavailable for: ${unavailableAgentIds.join(", ")}.`,
6262
- {
6263
- asset,
6264
- unavailableAgents: unavailableAgentIds,
6265
- agentErrors: aggregated.agentErrors
6266
- }
6267
- );
6268
- }
6269
- if (totalAvailable < requested && unavailableAgents.length === 0) {
3760
+ if (totalAvailable < requested) {
6270
3761
  throw new OwneyError(
6271
3762
  "WITHDRAW_INSUFFICIENT_BALANCE",
6272
3763
  `Requested withdrawal "${amount}" exceeds available balance "${totalAvailable.toString()}" for asset "${asset}".`,
@@ -6277,7 +3768,6 @@ var OwneySDK = class {
6277
3768
  }
6278
3769
  );
6279
3770
  }
6280
- const plannedTarget = totalAvailable < requested ? totalAvailable : requested;
6281
3771
  const disabledBalances = balances.filter(
6282
3772
  (b) => this.isAgentDisabled(b.agent.id)
6283
3773
  );
@@ -6286,7 +3776,7 @@ var OwneySDK = class {
6286
3776
  );
6287
3777
  const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
6288
3778
  disabledBalances,
6289
- plannedTarget
3779
+ requested
6290
3780
  );
6291
3781
  const enabledTotal = enabledBalances.reduce((s, b) => s + b.balance, 0n);
6292
3782
  const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
@@ -6295,13 +3785,10 @@ var OwneySDK = class {
6295
3785
  planned: 0n
6296
3786
  }));
6297
3787
  const plans = [...disabledPlans, ...enabledPlans];
6298
- const orderedPlans = this.orderAgentsForWithdrawal(plans.map((p) => p.agent)).map((agent) => plans.find((plan) => plan.agent === agent));
6299
3788
  const results = {};
6300
- const agentErrors = {
6301
- ...aggregated.agentErrors ?? {}
6302
- };
6303
- for (let i = 0; i < orderedPlans.length; i++) {
6304
- const p = orderedPlans[i];
3789
+ const agentErrors = {};
3790
+ for (let i = 0; i < plans.length; i++) {
3791
+ const p = plans[i];
6305
3792
  if (p.planned === 0n) continue;
6306
3793
  try {
6307
3794
  results[p.agent.id] = await p.agent.withdraw(
@@ -6310,9 +3797,7 @@ var OwneySDK = class {
6310
3797
  token,
6311
3798
  p.planned.toString()
6312
3799
  );
6313
- notifyAgentResult(p.agent.id, results[p.agent.id]);
6314
3800
  } catch (err) {
6315
- if (this.isUserRejectedWithdrawal(err)) throw err;
6316
3801
  console.error(`withdraw failed for agent "${p.agent.id}":`, err);
6317
3802
  agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
6318
3803
  const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
@@ -6324,7 +3809,7 @@ var OwneySDK = class {
6324
3809
  );
6325
3810
  const failedAmount = p.planned;
6326
3811
  p.planned = 0n;
6327
- redistributeShare(orderedPlans, i, failedAmount);
3812
+ redistributeShare(plans, i, failedAmount);
6328
3813
  }
6329
3814
  }
6330
3815
  if (Object.keys(results).length === 0) {
@@ -6348,8 +3833,7 @@ var OwneySDK = class {
6348
3833
  requested: amount,
6349
3834
  withdrawn: withdrawn.toString(),
6350
3835
  partialResults: results,
6351
- agentErrors,
6352
- ...unavailableAgentIds.length > 0 ? { unavailableAgents: unavailableAgentIds } : {}
3836
+ agentErrors
6353
3837
  }
6354
3838
  );
6355
3839
  }
@@ -6367,10 +3851,7 @@ var OwneySDK = class {
6367
3851
  if (agentId) {
6368
3852
  const agent = this.getAgent(agentId);
6369
3853
  const result = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
6370
- return {
6371
- ...result,
6372
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
6373
- };
3854
+ return result;
6374
3855
  }
6375
3856
  let totalBalance = 0;
6376
3857
  const results = {};
@@ -6378,13 +3859,7 @@ var OwneySDK = class {
6378
3859
  const balanceResults = await Promise.allSettled(
6379
3860
  entries.map(async ([id, agent]) => {
6380
3861
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
6381
- return [
6382
- id,
6383
- {
6384
- ...b,
6385
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
6386
- }
6387
- ];
3862
+ return [id, b];
6388
3863
  })
6389
3864
  );
6390
3865
  let successCount = 0;
@@ -6406,7 +3881,6 @@ var OwneySDK = class {
6406
3881
  const retryDelay = rateLimitDelay(reason);
6407
3882
  if (retryDelay !== void 0) agentRetryAt[agentId2] = Date.now() + retryDelay;
6408
3883
  agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
6409
- console.error(`[owney-sdk] Balance fetch failed for agent "${agentId2}":`, reason);
6410
3884
  }
6411
3885
  if (successCount === 0) {
6412
3886
  throw new OwneyError(
@@ -6585,10 +4059,7 @@ var OwneySDK = class {
6585
4059
  Promise.all(
6586
4060
  entries.map(async ([id, agent]) => {
6587
4061
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
6588
- return [
6589
- id,
6590
- balanceForApyScope(b, chainId, tokenSymbol)
6591
- ];
4062
+ return [id, balanceForApyScope(b, chainId, tokenSymbol)];
6592
4063
  })
6593
4064
  )
6594
4065
  ]);
@@ -6749,95 +4220,51 @@ var OwneySDK = class {
6749
4220
  return pending;
6750
4221
  }
6751
4222
  /**
6752
- * User-paid approval of Permit2 on the selected token for the active chain.
6753
- * Grants the maximum ERC20 allowance so later deposits do not require another
6754
- * approval. Resolves after one confirmation so the subsequent deposit attempt
6755
- * sees the new allowance. Deposit retries pass their captured chain id so a
6756
- * concurrent activation cannot redirect the approval to another network.
6757
- *
6758
- * @param requiredAmount Raw base-unit amount the pending deposit must cover.
6759
- * @param expectedChainId Chain captured by the deposit that requested approval.
4223
+ * One-time, user-paid approval of Permit2 on the sponsored WETH token for
4224
+ * the active chain. Required once per wallet per chain before gasless WETH
4225
+ * deposits; afterwards deposit() is signature-only. Resolves only after the
4226
+ * approval transaction is mined (1 confirmation), so a subsequent deposit()
4227
+ * will see the new allowance; throws if the transaction reverted.
6760
4228
  * @returns the approval transaction hash.
6761
4229
  */
6762
- async approvePermit2(asset = "WETH", requiredAmount = 0n, expectedChainId) {
4230
+ async approvePermit2(asset = "WETH") {
4231
+ void asset;
6763
4232
  const state = this.requireState();
6764
- const chainId = expectedChainId ?? this.requireChainId();
6765
- this.getEligibleAgents(chainId, asset, { excludeDisabled: true });
6766
- const token = sponsoredTokensFor(asset)[chainId];
4233
+ const chainId = this.requireChainId();
4234
+ this.validateAssetSupport(this.getAgent("zyfai"), chainId, "WETH");
4235
+ const token = SPONSORED_WETH_BY_CHAIN[chainId];
6767
4236
  if (!token) {
6768
4237
  throw new OwneyError(
6769
4238
  "CHAIN_UNSUPPORTED",
6770
- `No sponsored token on chain ${chainId}`
4239
+ `No sponsored WETH on chain ${chainId}`
6771
4240
  );
6772
4241
  }
6773
4242
  const provider = this.requireConnectedProvider();
6774
- const walletChainClient = createPublicClient4({
6775
- chain: VIEM_CHAIN2[chainId],
6776
- transport: custom3(provider)
6777
- });
6778
- const publicClient = this.getPaidRpcClient(chainId);
6779
- const approvalAmount = permit2ApprovalAmount(requiredAmount);
6780
- const wallet = createWalletClient3({
4243
+ const wallet = createWalletClient({
6781
4244
  account: state.walletAddress,
6782
4245
  chain: VIEM_CHAIN2[chainId],
6783
- transport: custom3(provider)
4246
+ transport: custom(provider)
6784
4247
  });
6785
- await ensureWalletOnChain(walletChainClient, wallet, chainId);
6786
4248
  const hash = await wallet.writeContract({
6787
4249
  address: token,
6788
4250
  abi: ERC20_ALLOWANCE_ABI,
6789
4251
  functionName: "approve",
6790
- args: [PERMIT2_ADDRESS, approvalAmount],
4252
+ args: [PERMIT2_ADDRESS, MAX_UINT256],
6791
4253
  account: state.walletAddress,
6792
4254
  chain: VIEM_CHAIN2[chainId]
6793
4255
  });
6794
- const receipt = await withPaidRpcDiagnostics(
6795
- () => publicClient.waitForTransactionReceipt({
6796
- hash,
6797
- confirmations: 1
6798
- }),
6799
- chainId,
6800
- "eth_getTransactionReceipt"
6801
- );
4256
+ const publicClient = createPublicClient2({
4257
+ chain: VIEM_CHAIN2[chainId],
4258
+ transport: custom(provider)
4259
+ });
4260
+ const receipt = await publicClient.waitForTransactionReceipt({
4261
+ hash,
4262
+ confirmations: 1
4263
+ });
6802
4264
  if (receipt.status !== "success") {
6803
4265
  throw new Error(`Permit2 approval reverted (tx ${hash})`);
6804
4266
  }
6805
- let observedAllowance = 0n;
6806
- let verificationError;
6807
- for (let attempt = 0; attempt < PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS; attempt += 1) {
6808
- try {
6809
- observedAllowance = await readPermit2Allowance(
6810
- publicClient,
6811
- token,
6812
- state.walletAddress,
6813
- attempt === 0 ? receipt.blockNumber : void 0
6814
- );
6815
- verificationError = void 0;
6816
- if (observedAllowance >= requiredAmount) return hash;
6817
- } catch (error) {
6818
- verificationError = error;
6819
- }
6820
- if (attempt + 1 < PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS) {
6821
- await new Promise(
6822
- (resolve) => setTimeout(resolve, PERMIT2_ALLOWANCE_VERIFY_DELAY_MS)
6823
- );
6824
- }
6825
- }
6826
- throw new OwneyError(
6827
- "PERMIT2_APPROVAL_REQUIRED",
6828
- "Permit2 approval was confirmed, but the required token allowance was not observable.",
6829
- {
6830
- approvalConfirmed: true,
6831
- approvalTxHash: hash,
6832
- owner: state.walletAddress,
6833
- token,
6834
- spender: PERMIT2_ADDRESS,
6835
- chainId,
6836
- requiredAmount: requiredAmount.toString(),
6837
- observedAllowance: observedAllowance.toString(),
6838
- ...verificationError instanceof Error ? { verificationError: verificationError.message } : {}
6839
- }
6840
- );
4267
+ return hash;
6841
4268
  }
6842
4269
  // --- Discovery (no wallet required) ---
6843
4270
  /**
@@ -6865,9 +4292,7 @@ var OwneySDK = class {
6865
4292
  return this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
6866
4293
  }
6867
4294
  const results = {};
6868
- const agentEntries = [...this.agents.entries()].filter(
6869
- ([id]) => !this.isAgentDisabled(id)
6870
- );
4295
+ const agentEntries = [...this.agents.entries()];
6871
4296
  const apyResults = await Promise.all(
6872
4297
  agentEntries.map(async ([id, agent]) => {
6873
4298
  const apy = await this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
@@ -6942,13 +4367,13 @@ var OwneySDK = class {
6942
4367
  };
6943
4368
 
6944
4369
  // src/agents/zyfai/zyfai.siwx.ts
6945
- import { getAddress as getAddress3 } from "viem";
6946
- import { SiweMessage as SiweMessage2 } from "siwe";
4370
+ import { getAddress } from "viem";
4371
+ import { SiweMessage } from "siwe";
6947
4372
  import { ZyfaiSDK as ZyfaiSDK2 } from "@zyfai/sdk";
6948
4373
 
6949
4374
  // src/agents/zyfai/zyfai.siwx-cache.ts
6950
- var KEY_PREFIX4 = "owney.siwx.session";
6951
- var storage4 = () => {
4375
+ var KEY_PREFIX2 = "owney.siwx.session";
4376
+ var storage2 = () => {
6952
4377
  if (typeof window === "undefined") return null;
6953
4378
  try {
6954
4379
  return window.localStorage;
@@ -6956,8 +4381,8 @@ var storage4 = () => {
6956
4381
  return null;
6957
4382
  }
6958
4383
  };
6959
- var buildKey3 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}`;
6960
- var legacyKeyPrefix2 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}:`;
4384
+ var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
4385
+ var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
6961
4386
  var memorySiwxSessions = /* @__PURE__ */ new Map();
6962
4387
  var readLegacySiwxSession = (store, address) => {
6963
4388
  if (!store) return null;
@@ -6988,17 +4413,17 @@ var readLegacySiwxSession = (store, address) => {
6988
4413
  };
6989
4414
  var readSiwxSession = (address, chainId) => {
6990
4415
  if (typeof window === "undefined") return null;
6991
- const key2 = buildKey3(address);
6992
- const store = storage4();
6993
- let raw2 = null;
4416
+ const key2 = buildKey2(address);
4417
+ const store = storage2();
4418
+ let raw = null;
6994
4419
  try {
6995
- raw2 = store?.getItem(key2) ?? null;
4420
+ raw = store?.getItem(key2) ?? null;
6996
4421
  } catch {
6997
- raw2 = null;
4422
+ raw = null;
6998
4423
  }
6999
- if (raw2) {
4424
+ if (raw) {
7000
4425
  try {
7001
- return JSON.parse(raw2);
4426
+ return JSON.parse(raw);
7002
4427
  } catch {
7003
4428
  memorySiwxSessions.delete(key2);
7004
4429
  try {
@@ -7017,18 +4442,18 @@ var readSiwxSession = (address, chainId) => {
7017
4442
  };
7018
4443
  var writeSiwxSession = (address, _chainId, session) => {
7019
4444
  if (typeof window === "undefined") return;
7020
- const key2 = buildKey3(address);
4445
+ const key2 = buildKey2(address);
7021
4446
  memorySiwxSessions.set(key2, session);
7022
- const store = storage4();
4447
+ const store = storage2();
7023
4448
  try {
7024
4449
  store?.setItem(key2, JSON.stringify(session));
7025
4450
  } catch {
7026
4451
  }
7027
4452
  };
7028
4453
  var clearSiwxSession = (address, _chainId) => {
7029
- const key2 = buildKey3(address);
4454
+ const key2 = buildKey2(address);
7030
4455
  memorySiwxSessions.delete(key2);
7031
- const store = storage4();
4456
+ const store = storage2();
7032
4457
  try {
7033
4458
  store?.removeItem(key2);
7034
4459
  } catch {
@@ -7068,8 +4493,8 @@ function buildSIWXConfig(deps) {
7068
4493
  statement: STATEMENT,
7069
4494
  issuedAt,
7070
4495
  toString() {
7071
- return new SiweMessage2({
7072
- address: getAddress3(accountAddress),
4496
+ return new SiweMessage({
4497
+ address: getAddress(accountAddress),
7073
4498
  chainId: numericChainId(chainId),
7074
4499
  domain,
7075
4500
  uri,
@@ -7111,7 +4536,7 @@ function buildSIWXConfig(deps) {
7111
4536
  const persistSession = async (session) => {
7112
4537
  const address = session.data.accountAddress;
7113
4538
  const id = numericChainId(session.data.chainId);
7114
- const message = new SiweMessage2(session.message);
4539
+ const message = new SiweMessage(session.message);
7115
4540
  const login = await post("/auth/login", {
7116
4541
  message,
7117
4542
  signature: session.signature,
@@ -7160,7 +4585,6 @@ export {
7160
4585
  NotConnectedError,
7161
4586
  OwneyError,
7162
4587
  OwneySDK,
7163
- YieldseekerAgent,
7164
4588
  createOwneySIWX,
7165
4589
  setOwneyDebug
7166
4590
  };