@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.cjs CHANGED
@@ -26,32 +26,11 @@ __export(index_exports, {
26
26
  NotConnectedError: () => NotConnectedError,
27
27
  OwneyError: () => OwneyError,
28
28
  OwneySDK: () => OwneySDK,
29
- YieldseekerAgent: () => YieldseekerAgent,
30
29
  createOwneySIWX: () => createOwneySIWX,
31
30
  setOwneyDebug: () => setOwneyDebug
32
31
  });
33
32
  module.exports = __toCommonJS(index_exports);
34
33
 
35
- // src/lib/deposit-batch-callback.ts
36
- var batchCallbacks = /* @__PURE__ */ new WeakMap();
37
- var getDepositBatchTransfer = (callback) => callback ? batchCallbacks.get(callback) : void 0;
38
- function toBatchTransfer(to, amount, verification) {
39
- return {
40
- to,
41
- amount,
42
- ...verification ? {
43
- yieldseeker: {
44
- signature: verification.signature,
45
- userId: verification.userId,
46
- agentId: verification.yieldseekerAgentId
47
- }
48
- } : {}
49
- };
50
- }
51
- function registerDepositBatch(callback, transfer) {
52
- batchCallbacks.set(callback, transfer);
53
- }
54
-
55
34
  // src/errors.ts
56
35
  var OwneyError = class extends Error {
57
36
  code;
@@ -159,34 +138,6 @@ function rateLimitDelay(error, now = Date.now()) {
159
138
  }
160
139
 
161
140
  // src/lib/agent-reads.ts
162
- function rateLimitDiagnostics(error) {
163
- const seen = /* @__PURE__ */ new Set();
164
- let details = {};
165
- function visit(value, depth = 0) {
166
- if (depth > 6 || !value || typeof value !== "object" || seen.has(value))
167
- return;
168
- seen.add(value);
169
- const record = value;
170
- for (const key2 of [
171
- "rpcSource",
172
- "chainId",
173
- "rpcMethod",
174
- "providerRequestId",
175
- "statusCode"
176
- ]) {
177
- const candidate = record[key2];
178
- if (candidate !== void 0 && details[key2] === void 0)
179
- details = { ...details, [key2]: candidate };
180
- }
181
- for (const key2 of ["details", "cause", "response", "fields", "error"])
182
- visit(record[key2], depth + 1);
183
- }
184
- visit(error);
185
- return {
186
- rpcSource: details.rpcSource ?? "agent-api",
187
- ...details
188
- };
189
- }
190
141
  var AgentReads = class {
191
142
  inFlight = /* @__PURE__ */ new Map();
192
143
  cooldowns = /* @__PURE__ */ new Map();
@@ -194,15 +145,14 @@ var AgentReads = class {
194
145
  clearInFlight() {
195
146
  this.inFlight.clear();
196
147
  }
197
- limited(agentId, until, diagnostics) {
148
+ limited(agentId, until) {
198
149
  return new OwneyError(
199
150
  "AGENT_RATE_LIMITED",
200
151
  "Too many requests. Please wait before trying again.",
201
152
  {
202
153
  statusCode: 429,
203
154
  retryAt: until,
204
- retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3)),
205
- ...diagnostics
155
+ retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3))
206
156
  },
207
157
  agentId
208
158
  );
@@ -210,9 +160,7 @@ var AgentReads = class {
210
160
  run(agentId, key2, fetch2) {
211
161
  const cooldown = this.cooldowns.get(agentId);
212
162
  if (cooldown && cooldown.until > Date.now()) {
213
- return Promise.reject(
214
- this.limited(agentId, cooldown.until, cooldown.diagnostics)
215
- );
163
+ return Promise.reject(this.limited(agentId, cooldown.until));
216
164
  }
217
165
  const requestKey = JSON.stringify([agentId, key2]);
218
166
  const existing = this.inFlight.get(requestKey);
@@ -233,9 +181,8 @@ var AgentReads = class {
233
181
  Math.min(3e4 * 2 ** (failures - 1), 3e5)
234
182
  );
235
183
  const until = Math.max(previous?.until ?? 0, Date.now() + delay);
236
- const diagnostics = rateLimitDiagnostics(error);
237
- this.cooldowns.set(agentId, { until, failures, diagnostics });
238
- throw this.limited(agentId, until, diagnostics);
184
+ this.cooldowns.set(agentId, { until, failures });
185
+ throw this.limited(agentId, until);
239
186
  }
240
187
  ).finally(() => {
241
188
  if (this.inFlight.get(requestKey) === promise)
@@ -248,7 +195,7 @@ var AgentReads = class {
248
195
 
249
196
  // src/agents/zyfai/zyfai.agent.ts
250
197
  var import_sdk = require("@zyfai/sdk");
251
- var import_viem2 = require("viem");
198
+ var import_viem = require("viem");
252
199
  var import_chains = require("viem/chains");
253
200
 
254
201
  // src/types/config.ts
@@ -363,18 +310,18 @@ function tokenDecimals(symbol, explicit) {
363
310
  return explicit;
364
311
  return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
365
312
  }
366
- function mapDeposit(raw2) {
313
+ function mapDeposit(raw) {
367
314
  return {
368
- txHash: raw2.txHash,
369
- smartWallet: raw2.smartWallet,
370
- amount: raw2.amount
315
+ txHash: raw.txHash,
316
+ smartWallet: raw.smartWallet,
317
+ amount: raw.amount
371
318
  };
372
319
  }
373
- function mapWithdraw(raw2) {
320
+ function mapWithdraw(raw) {
374
321
  return {
375
- txHash: raw2.txHash,
376
- type: raw2.type,
377
- amount: raw2.amount
322
+ txHash: raw.txHash,
323
+ type: raw.type,
324
+ amount: raw.amount
378
325
  };
379
326
  }
380
327
  var CHAIN_ID_TO_NAME = {
@@ -393,10 +340,10 @@ function resolveChainId(chain) {
393
340
  if (Number.isFinite(asNum) && asNum > 0) return asNum;
394
341
  return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
395
342
  }
396
- function mapPendingAllocations(raw2) {
397
- if (!Array.isArray(raw2)) return void 0;
343
+ function mapPendingAllocations(raw) {
344
+ if (!Array.isArray(raw)) return void 0;
398
345
  const pending = [];
399
- for (const entry of raw2) {
346
+ for (const entry of raw) {
400
347
  if (typeof entry !== "object" || entry === null) continue;
401
348
  const e = entry;
402
349
  if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
@@ -419,8 +366,8 @@ function mapPendingAllocations(raw2) {
419
366
  }
420
367
  return pending.length > 0 ? pending : void 0;
421
368
  }
422
- function mapBalances(raw2, _chainId, smartWallet) {
423
- const portfolio = raw2.portfolio;
369
+ function mapBalances(raw, _chainId, smartWallet) {
370
+ const portfolio = raw.portfolio;
424
371
  const portfolioByChain = portfolio.portfolioByChain ?? {};
425
372
  let totalBalance = 0;
426
373
  const tokens = [];
@@ -489,8 +436,8 @@ function sumTokenValues(tokens) {
489
436
  function sumTokenEarnings(tokens) {
490
437
  return Object.values(tokens).reduce((sum, val) => sum + Number(val), 0);
491
438
  }
492
- function mapEarnings(raw2, smartWallet) {
493
- const totalEarningsByChain = raw2.data.totalEarningsByChainWithFee ?? raw2.data.totalEarningsByChain ?? {};
439
+ function mapEarnings(raw, smartWallet) {
440
+ const totalEarningsByChain = raw.data.totalEarningsByChainWithFee ?? raw.data.totalEarningsByChain ?? {};
494
441
  const tokens = [];
495
442
  for (const [chainIdKey, tokensBySymbol] of Object.entries(
496
443
  totalEarningsByChain
@@ -509,15 +456,15 @@ function mapEarnings(raw2, smartWallet) {
509
456
  return {
510
457
  smartWallet,
511
458
  lifetimeEarnings: sumTokenEarnings(
512
- raw2.data.totalEarningsByTokenWithFee ?? raw2.data.totalEarningsByToken
459
+ raw.data.totalEarningsByTokenWithFee ?? raw.data.totalEarningsByToken
513
460
  ),
514
461
  tokens
515
462
  };
516
463
  }
517
- function mapWeightedApyByChain(raw2) {
518
- if (!raw2) return void 0;
464
+ function mapWeightedApyByChain(raw) {
465
+ if (!raw) return void 0;
519
466
  const out = {};
520
- for (const [chainKey, tokenApy] of Object.entries(raw2)) {
467
+ for (const [chainKey, tokenApy] of Object.entries(raw)) {
521
468
  const chainId = Number(chainKey);
522
469
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
523
470
  const perAsset = {};
@@ -557,8 +504,8 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
557
504
  }
558
505
  return totalBalance > 0 ? weightedSum / totalBalance : null;
559
506
  }
560
- function mapApyHistory(raw2, chainId, tokenSymbol) {
561
- const history = Object.entries(raw2.history ?? {}).map(([date, entry]) => ({
507
+ function mapApyHistory(raw, chainId, tokenSymbol) {
508
+ const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
562
509
  date,
563
510
  apy: rawPoolApyForChain(entry, chainId, tokenSymbol),
564
511
  // Provider position balances are treated as decimal amounts of the
@@ -574,9 +521,9 @@ function mapApyHistory(raw2, chainId, tokenSymbol) {
574
521
  } : {}
575
522
  })).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
576
523
  return {
577
- walletAddress: raw2.walletAddress,
578
- weightedApyAfterFee: raw2.weightedApyAfterFee ? sumTokenValues(raw2.weightedApyAfterFee) : void 0,
579
- apyByChainAndAsset: mapWeightedApyByChain(raw2.weightedApyAfterFeeByChain),
524
+ walletAddress: raw.walletAddress,
525
+ weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
526
+ apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain),
580
527
  history
581
528
  };
582
529
  }
@@ -672,23 +619,23 @@ function mapEntries(rawEntries, chainId) {
672
619
  };
673
620
  });
674
621
  }
675
- function mapUserProfile(raw2, userAddress) {
622
+ function mapUserProfile(raw, userAddress) {
676
623
  return {
677
624
  address: userAddress,
678
- smartWallet: raw2.smartWallet || "",
679
- chains: raw2.chains || [],
680
- strategy: raw2.strategy,
681
- hasActiveSessionKey: raw2.hasActiveSessionKey || false,
682
- protocols: raw2.protocols || [],
683
- splitting: raw2.splitting,
684
- minSplits: raw2.minSplits
625
+ smartWallet: raw.smartWallet || "",
626
+ chains: raw.chains || [],
627
+ strategy: raw.strategy,
628
+ hasActiveSessionKey: raw.hasActiveSessionKey || false,
629
+ protocols: raw.protocols || [],
630
+ splitting: raw.splitting,
631
+ minSplits: raw.minSplits
685
632
  };
686
633
  }
687
- function mapApyByStrategy(raw2) {
634
+ function mapApyByStrategy(raw) {
688
635
  const apyPerAsset = {};
689
636
  let apySum = 0;
690
637
  let apyCount = 0;
691
- for (const entry of raw2.data) {
638
+ for (const entry of raw.data) {
692
639
  const supported = SupportedAssets.find(
693
640
  (asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
694
641
  );
@@ -800,9 +747,9 @@ function netDeltaForSnapshot(entry, chainId, asset) {
800
747
  debugLog("zyfai:earnings", "gross fallback for daily earnings", { gross });
801
748
  return gross;
802
749
  }
803
- function mapDailyEarnings(raw2, chainId, tokenSymbol) {
750
+ function mapDailyEarnings(raw, chainId, tokenSymbol) {
804
751
  const wanted = tokenSymbol?.toUpperCase();
805
- const snapshots = [...raw2.data ?? []].sort(
752
+ const snapshots = [...raw.data ?? []].sort(
806
753
  (a, b) => a.snapshot_date.localeCompare(b.snapshot_date)
807
754
  );
808
755
  const byAsset = /* @__PURE__ */ new Map();
@@ -817,7 +764,7 @@ function mapDailyEarnings(raw2, chainId, tokenSymbol) {
817
764
  }
818
765
  }
819
766
  const assets = [...byAsset.entries()].map(([asset, series]) => ({ asset, points: series.points })).sort((a, b) => a.asset.localeCompare(b.asset));
820
- return { walletAddress: raw2.walletAddress, chainId, assets };
767
+ return { walletAddress: raw.walletAddress, chainId, assets };
821
768
  }
822
769
 
823
770
  // src/agents/zyfai/zyfai.withdraw-amount.ts
@@ -928,15 +875,15 @@ var readSession = (address, _chainId) => {
928
875
  if (typeof window === "undefined") return null;
929
876
  const key2 = buildKey(address);
930
877
  const store = storage();
931
- let raw2 = null;
878
+ let raw = null;
932
879
  try {
933
- raw2 = store?.getItem(key2) ?? null;
880
+ raw = store?.getItem(key2) ?? null;
934
881
  } catch {
935
- raw2 = null;
882
+ raw = null;
936
883
  }
937
- if (raw2) {
884
+ if (raw) {
938
885
  try {
939
- const parsed = JSON.parse(raw2);
886
+ const parsed = JSON.parse(raw);
940
887
  if (isFreshSession(parsed)) return parsed;
941
888
  } catch {
942
889
  }
@@ -1104,8 +1051,8 @@ function buildChainsByProtocol(protocols, dashboardChainIds) {
1104
1051
  }
1105
1052
  return result;
1106
1053
  }
1107
- function flattenAvailablePools(raw2) {
1108
- const byChain = raw2 ?? {};
1054
+ function flattenAvailablePools(raw) {
1055
+ const byChain = raw ?? {};
1109
1056
  const names = [];
1110
1057
  for (const byToken of Object.values(byChain ?? {})) {
1111
1058
  for (const entry of Object.values(byToken ?? {})) {
@@ -1129,145 +1076,15 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
1129
1076
  return !protocolListsEqual(current.protocols, desiredProtocols);
1130
1077
  }
1131
1078
 
1132
- // src/lib/paid-rpc.ts
1133
- var import_viem = require("viem");
1134
- var PAID_RPC_RETRY_COUNT = 3;
1135
- var PAID_RPC_RETRY_DELAY_MS = 1e3;
1136
- function configuredRpcProxyBaseUrl(baseUrl) {
1137
- const configured = (baseUrl ?? "")?.trim();
1138
- if (!configured) {
1139
- throw new Error(
1140
- "OWNEY_ROUTING_API_BASE_URL is required for RPC proxy requests unless routingApiBaseUrl or all rpcUrls are configured."
1141
- );
1142
- }
1143
- return configured;
1144
- }
1145
- function rpcProxyUrl(chainId, apiKey, baseUrl) {
1146
- const url = new URL(
1147
- `${configuredRpcProxyBaseUrl(baseUrl).replace(/\/$/, "")}/api/v1/rpc/${chainId}`
1148
- );
1149
- if (apiKey) url.searchParams.set("apiKey", apiKey);
1150
- return url.toString();
1151
- }
1152
- function resolveRpcUrl(rpcUrls, chainId, apiKey = "", baseUrl) {
1153
- const url = rpcUrls?.[chainId]?.trim();
1154
- if (url) return url;
1155
- return rpcProxyUrl(chainId, apiKey, baseUrl);
1156
- }
1157
- function resolveRpcUrls(rpcUrls, apiKey = "", baseUrl) {
1158
- return {
1159
- 1: resolveRpcUrl(rpcUrls, 1, apiKey, baseUrl),
1160
- 8453: resolveRpcUrl(rpcUrls, 8453, apiKey, baseUrl),
1161
- 42161: resolveRpcUrl(rpcUrls, 42161, apiKey, baseUrl)
1162
- };
1163
- }
1164
- function createPaidRpcClient(chain, rpcUrls) {
1165
- const url = resolveRpcUrl(
1166
- rpcUrls,
1167
- chain.id
1168
- );
1169
- return (0, import_viem.createPublicClient)({
1170
- chain,
1171
- transport: (0, import_viem.http)(url, {
1172
- retryCount: PAID_RPC_RETRY_COUNT,
1173
- retryDelay: PAID_RPC_RETRY_DELAY_MS
1174
- })
1175
- });
1176
- }
1177
- function headerValue(error, name) {
1178
- const seen = /* @__PURE__ */ new Set();
1179
- let value;
1180
- function visit(candidate, depth = 0) {
1181
- if (value || depth > 6 || !candidate || typeof candidate !== "object")
1182
- return;
1183
- if (seen.has(candidate)) return;
1184
- seen.add(candidate);
1185
- const record = candidate;
1186
- const headers = record.headers;
1187
- let found;
1188
- if (typeof headers?.get === "function") {
1189
- found = headers.get(name);
1190
- } else {
1191
- const headerRecord = headers;
1192
- found = headerRecord?.[name] ?? headerRecord?.[name.toLowerCase()];
1193
- }
1194
- if (typeof found === "string" && found) {
1195
- value = found;
1196
- return;
1197
- }
1198
- for (const key2 of ["cause", "details", "response", "error"])
1199
- visit(record[key2], depth + 1);
1200
- }
1201
- visit(error);
1202
- return value;
1203
- }
1204
- function statusCode(error) {
1205
- const seen = /* @__PURE__ */ new Set();
1206
- let status;
1207
- function visit(candidate, depth = 0) {
1208
- if (status || depth > 6 || !candidate || typeof candidate !== "object")
1209
- return;
1210
- if (seen.has(candidate)) return;
1211
- seen.add(candidate);
1212
- const record = candidate;
1213
- for (const key2 of ["status", "statusCode"]) {
1214
- const parsed = Number(record[key2]);
1215
- if (Number.isInteger(parsed) && parsed >= 100 && parsed <= 599) {
1216
- status = parsed;
1217
- return;
1218
- }
1219
- }
1220
- for (const key2 of ["cause", "details", "response", "error"])
1221
- visit(record[key2], depth + 1);
1222
- }
1223
- visit(error);
1224
- return status;
1225
- }
1226
- function paidRpcError(error, chainId, rpcMethod, agentId) {
1227
- const delay = rateLimitDelay(error);
1228
- const providerRequestId = headerValue(error, "x-alchemy-request-id") ?? headerValue(error, "x-request-id");
1229
- if (delay === void 0) {
1230
- return new OwneyError(
1231
- "AGENT_API_ERROR",
1232
- "The blockchain RPC request failed.",
1233
- {
1234
- rpcSource: "paid-rpc",
1235
- chainId,
1236
- rpcMethod,
1237
- ...statusCode(error) ? { statusCode: statusCode(error) } : {},
1238
- ...providerRequestId ? { providerRequestId } : {}
1239
- },
1240
- agentId
1241
- );
1242
- }
1243
- const retryAt = Date.now() + delay;
1244
- return new OwneyError(
1245
- "AGENT_RATE_LIMITED",
1246
- "The blockchain RPC is rate limited. Please wait before trying again.",
1247
- {
1248
- rpcSource: "paid-rpc",
1249
- chainId,
1250
- rpcMethod,
1251
- statusCode: 429,
1252
- retryAt,
1253
- retryAfterSeconds: Math.max(0, Math.ceil(delay / 1e3)),
1254
- ...providerRequestId ? { providerRequestId } : {}
1255
- },
1256
- agentId
1257
- );
1258
- }
1259
- async function withPaidRpcDiagnostics(operation, chainId, rpcMethod, agentId) {
1260
- try {
1261
- return await operation();
1262
- } catch (error) {
1263
- throw paidRpcError(error, chainId, rpcMethod, agentId);
1264
- }
1265
- }
1266
-
1267
1079
  // src/agents/zyfai/zyfai.agent.ts
1268
- var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem2.parseAbi)([
1080
+ var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem.parseAbi)([
1269
1081
  "function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
1270
1082
  ]);
1083
+ var DEFAULT_ZYFAI_RPC_URLS = {
1084
+ 8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
1085
+ 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
1086
+ 1: "https://eth-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
1087
+ };
1271
1088
  var WETH_ADDRESS_BY_CHAIN = {
1272
1089
  8453: "0x4200000000000000000000000000000000000006",
1273
1090
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
@@ -1333,7 +1150,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1333
1150
  earningsSnapshot = null;
1334
1151
  earningsGeneration = 0;
1335
1152
  constructor(apiKey, rpcUrls, referralSource) {
1336
- this.rpcUrls = resolveRpcUrls(rpcUrls);
1153
+ this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
1337
1154
  this.sdk = new import_sdk.ZyfaiSDK({
1338
1155
  apiKey,
1339
1156
  rpcUrls: this.rpcUrls,
@@ -1347,10 +1164,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
1347
1164
  getPublicClient(chainId) {
1348
1165
  const cached = this.publicClients.get(chainId);
1349
1166
  if (cached) return cached;
1350
- const client = createPaidRpcClient(
1351
- VIEM_CHAIN[chainId],
1352
- this.rpcUrls
1353
- );
1167
+ const client = (0, import_viem.createPublicClient)({
1168
+ chain: VIEM_CHAIN[chainId],
1169
+ transport: (0, import_viem.http)(this.rpcUrls[chainId])
1170
+ });
1354
1171
  this.publicClients.set(chainId, client);
1355
1172
  return client;
1356
1173
  }
@@ -1520,7 +1337,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1520
1337
  * chain/account switch fires the provider's `accountsChanged` →
1521
1338
  * `disconnectAccount` (nulls walletClient + authenticatedUserId) while our
1522
1339
  * own `connectAuth` guard still believes this chain is connected and
1523
- * early-returns. Without this, authenticated calls (depositFunds,
1340
+ * early-returns. Without this, authenticated calls (sendDeposit,
1524
1341
  * withdrawFunds) fail with "No account connected".
1525
1342
  */
1526
1343
  async ensureConnected(state, chainId) {
@@ -1738,8 +1555,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
1738
1555
  const poolResults = await Promise.all(
1739
1556
  universe.map(async (protocol) => {
1740
1557
  try {
1741
- const raw2 = await this.sdk.getAvailablePools(protocol.id, strategy);
1742
- return [protocol.id, flattenAvailablePools(raw2)];
1558
+ const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
1559
+ return [protocol.id, flattenAvailablePools(raw)];
1743
1560
  } catch (error) {
1744
1561
  console.warn(
1745
1562
  `[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
@@ -1805,14 +1622,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
1805
1622
  async readWalletState(ownerAddress) {
1806
1623
  try {
1807
1624
  const { portfolio } = await this.sdk.getPositions(ownerAddress);
1808
- const raw2 = portfolio;
1625
+ const raw = portfolio;
1809
1626
  debugLog("zyfai:onboard", "wallet state from getPositions", {
1810
- predeployed: raw2?.predeployed,
1811
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1627
+ predeployed: raw?.predeployed,
1628
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1812
1629
  });
1813
1630
  return {
1814
- predeployed: raw2?.predeployed,
1815
- hasActiveSessionKey: raw2?.hasActiveSessionKey
1631
+ predeployed: raw?.predeployed,
1632
+ hasActiveSessionKey: raw?.hasActiveSessionKey
1816
1633
  };
1817
1634
  } catch (error) {
1818
1635
  console.warn(
@@ -2098,14 +1915,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
2098
1915
  return { txHash, smartWallet, amount };
2099
1916
  }
2100
1917
  await this.ensureWalletDeployed(this.getAddress(), validChainId);
2101
- const raw2 = await this.sdk.depositFunds(
1918
+ const raw = await this.sdk.sendDeposit(
2102
1919
  this.getAddress(),
2103
1920
  validChainId,
2104
1921
  amount,
2105
1922
  asset,
2106
1923
  "aggressive"
2107
1924
  );
2108
- return mapDeposit(raw2);
1925
+ return mapDeposit(raw);
2109
1926
  } catch (error) {
2110
1927
  throw error;
2111
1928
  }
@@ -2114,27 +1931,27 @@ var ZyfaiAgent = class _ZyfaiAgent {
2114
1931
  async withdraw(state, chainId, token, amount) {
2115
1932
  const validChainId = isValidChainId(chainId);
2116
1933
  await this.ensureConnected(state, validChainId);
2117
- const raw2 = await this.sdk.withdrawFunds(
1934
+ const raw = await this.sdk.withdrawFunds(
2118
1935
  this.getAddress(),
2119
1936
  validChainId,
2120
1937
  amount,
2121
1938
  token
2122
1939
  );
2123
- if (!raw2.success) {
1940
+ if (!raw.success) {
2124
1941
  throw new OwneyError(
2125
1942
  "WITHDRAW_FAILED",
2126
- raw2.message || "Zyfai withdraw failed.",
2127
- { chainId: validChainId, token, amount, response: raw2 },
1943
+ raw.message || "Zyfai withdraw failed.",
1944
+ { chainId: validChainId, token, amount, response: raw },
2128
1945
  this.id
2129
1946
  );
2130
1947
  }
2131
- return mapWithdraw(raw2);
1948
+ return mapWithdraw(raw);
2132
1949
  }
2133
1950
  // --- IAgent: Portfolio reads ---
2134
1951
  async getBalances(state, chainId) {
2135
1952
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
2136
- const raw2 = await this.sdk.getPortfolio(this.getAddress());
2137
- return mapBalances(raw2, validChainId, smartWallet);
1953
+ const raw = await this.sdk.getPortfolio(this.getAddress());
1954
+ return mapBalances(raw, validChainId, smartWallet);
2138
1955
  }
2139
1956
  earningsKey(state, chainId, smartWallet) {
2140
1957
  return JSON.stringify([
@@ -2147,11 +1964,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
2147
1964
  const existing = this.earningsReads.get(key2);
2148
1965
  if (existing) return existing;
2149
1966
  const generation = this.earningsGeneration;
2150
- const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw2) => {
1967
+ const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw) => {
2151
1968
  if (generation === this.earningsGeneration) {
2152
- this.earningsSnapshot = { key: key2, raw: raw2, at: Date.now() };
1969
+ this.earningsSnapshot = { key: key2, raw, at: Date.now() };
2153
1970
  }
2154
- return raw2;
1971
+ return raw;
2155
1972
  }).finally(() => {
2156
1973
  if (this.earningsReads.get(key2) === pending)
2157
1974
  this.earningsReads.delete(key2);
@@ -2161,11 +1978,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
2161
1978
  }
2162
1979
  async getEarnings(state, chainId) {
2163
1980
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
2164
- const raw2 = await this.readEarnings(
1981
+ const raw = await this.readEarnings(
2165
1982
  this.earningsKey(state, chainId, smartWallet),
2166
1983
  smartWallet
2167
1984
  );
2168
- return mapEarnings(raw2, smartWallet);
1985
+ return mapEarnings(raw, smartWallet);
2169
1986
  }
2170
1987
  async refreshEarnings(state, chainId) {
2171
1988
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
@@ -2192,17 +2009,17 @@ var ZyfaiAgent = class _ZyfaiAgent {
2192
2009
  }
2193
2010
  async getAccountApy(state, chainId, days, tokenSymbol) {
2194
2011
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
2195
- const raw2 = await this.sdk.getDailyApyHistory(smartWallet, days);
2196
- return mapApyHistory(raw2, chainId, tokenSymbol);
2012
+ const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
2013
+ return mapApyHistory(raw, chainId, tokenSymbol);
2197
2014
  }
2198
2015
  async getDailyEarnings(state, chainId, days, tokenSymbol) {
2199
2016
  const { smartWallet } = await this.resolveSmartWallet(state, chainId);
2200
2017
  const start = new Date(Date.now() - (DayFilterMapping[days] + 1) * 864e5);
2201
- const raw2 = await this.sdk.getDailyEarnings(
2018
+ const raw = await this.sdk.getDailyEarnings(
2202
2019
  smartWallet,
2203
2020
  start.toISOString().slice(0, 10)
2204
2021
  );
2205
- return mapDailyEarnings(raw2, chainId, tokenSymbol);
2022
+ return mapDailyEarnings(raw, chainId, tokenSymbol);
2206
2023
  }
2207
2024
  /**
2208
2025
  * Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
@@ -2237,7 +2054,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2237
2054
  const matched = [];
2238
2055
  let backendExhausted = false;
2239
2056
  for (let i = 0; i < MAX_BACKEND_CALLS && matched.length < limit; i++) {
2240
- const raw2 = await this.sdk.getHistory(smartWallet, validChainId, {
2057
+ const raw = await this.sdk.getHistory(smartWallet, validChainId, {
2241
2058
  limit: backendPageSize,
2242
2059
  offset,
2243
2060
  fromDate: options?.fromDate,
@@ -2248,13 +2065,13 @@ var ZyfaiAgent = class _ZyfaiAgent {
2248
2065
  // asset's rows and handing back a page that filters to nothing.
2249
2066
  assetType
2250
2067
  });
2251
- raw2.data.forEach((entry, idx) => {
2068
+ raw.data.forEach((entry, idx) => {
2252
2069
  if (entry.chainId === validChainId) {
2253
2070
  matched.push({ entry, rawIdx: offset + idx });
2254
2071
  }
2255
2072
  });
2256
- offset += raw2.data.length;
2257
- if (raw2.data.length < backendPageSize) {
2073
+ offset += raw.data.length;
2074
+ if (raw.data.length < backendPageSize) {
2258
2075
  backendExhausted = true;
2259
2076
  break;
2260
2077
  }
@@ -2276,18 +2093,18 @@ var ZyfaiAgent = class _ZyfaiAgent {
2276
2093
  }
2277
2094
  async getUserProfile(state, chainId) {
2278
2095
  await this.connectAuth(state, chainId);
2279
- const raw2 = await this.sdk.getUserDetails();
2096
+ const raw = await this.sdk.getUserDetails();
2280
2097
  debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
2281
2098
  asset: "USDC (default \u2014 no asset passed)",
2282
- splitting: raw2.splitting,
2283
- minSplits: raw2.minSplits,
2284
- strategy: raw2.strategy,
2285
- chains: raw2.chains,
2286
- protocolCount: raw2.protocols?.length,
2287
- hasActiveSessionKey: raw2.hasActiveSessionKey,
2288
- smartWallet: raw2.smartWallet
2099
+ splitting: raw.splitting,
2100
+ minSplits: raw.minSplits,
2101
+ strategy: raw.strategy,
2102
+ chains: raw.chains,
2103
+ protocolCount: raw.protocols?.length,
2104
+ hasActiveSessionKey: raw.hasActiveSessionKey,
2105
+ smartWallet: raw.smartWallet
2289
2106
  });
2290
- return mapUserProfile(raw2, this.connectedAddress);
2107
+ return mapUserProfile(raw, this.connectedAddress);
2291
2108
  }
2292
2109
  async ensureAutoSelectProtocols(state, chainId, asset) {
2293
2110
  await this.connectAuth(state, chainId);
@@ -2306,2233 +2123,116 @@ var ZyfaiAgent = class _ZyfaiAgent {
2306
2123
  }
2307
2124
  // --- IAgent: Discovery (no wallet required) ---
2308
2125
  async getAgentApy(days, options) {
2309
- const raw2 = await this.sdk.getAPYPerStrategy(
2126
+ const raw = await this.sdk.getAPYPerStrategy(
2310
2127
  false,
2311
2128
  DayFilterMapping[days],
2312
2129
  "aggressive",
2313
2130
  options?.chainId,
2314
2131
  options?.tokenSymbol
2315
2132
  );
2316
- return mapApyByStrategy(raw2);
2133
+ return mapApyByStrategy(raw);
2317
2134
  }
2318
2135
  };
2319
2136
 
2320
- // src/agents/yieldseeker/yieldseeker.agent.ts
2321
- var import_viem7 = require("viem");
2322
- var import_chains3 = require("viem/chains");
2323
-
2324
- // src/lib/chain-guard.ts
2325
- var CHAIN_NAMES = {
2326
- 1: "Ethereum",
2327
- 8453: "Base",
2328
- 42161: "Arbitrum"
2329
- };
2330
- function chainName(chainId) {
2331
- return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
2332
- }
2333
- async function ensureWalletOnChain(pub, wallet, expected) {
2334
- const actual = await pub.getChainId();
2335
- if (actual === expected) return;
2137
+ // src/lib/routing-api.ts
2138
+ var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2139
+ async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
2140
+ const url = `${baseUrl}/api/v1/agent/org-config`;
2336
2141
  try {
2337
- await wallet.switchChain({ id: expected });
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
+ if (res.status !== 404) {
2151
+ console.warn(
2152
+ `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
2153
+ );
2154
+ }
2155
+ return null;
2156
+ }
2157
+ const json = await res.json();
2158
+ const policy = json.success ? json.data ?? null : null;
2159
+ debugLog(
2160
+ "owney-sdk",
2161
+ policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
2162
+ policy ?? void 0
2163
+ );
2164
+ return policy;
2338
2165
  } catch (error) {
2166
+ console.warn(
2167
+ "[owney-sdk] Could not read org agent config (non-fatal):",
2168
+ error instanceof Error ? error.message : String(error)
2169
+ );
2170
+ return null;
2171
+ }
2172
+ }
2173
+ async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
2174
+ const url = `${baseUrl}/api/v1/agent/keys`;
2175
+ const res = await fetch(url, {
2176
+ method: "GET",
2177
+ headers: {
2178
+ "Content-Type": "application/json",
2179
+ "x-owney-api-key": `${apiKey}`
2180
+ }
2181
+ });
2182
+ if (!res.ok) {
2183
+ const text = await res.text().catch(() => "");
2339
2184
  throw new OwneyError(
2340
- "CHAIN_MISMATCH",
2341
- `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2342
- {
2343
- expectedChainId: expected,
2344
- actualChainId: actual,
2345
- cause: error instanceof Error ? error.message : String(error)
2346
- }
2185
+ "API_ROUTING_ERROR",
2186
+ `Routing API error ${res.status}: ${text}`,
2187
+ { statusCode: res.status, responseBody: text }
2347
2188
  );
2348
2189
  }
2349
- const after = await pub.getChainId();
2350
- if (after !== expected) {
2190
+ const json = await res.json();
2191
+ if (!json.success) {
2351
2192
  throw new OwneyError(
2352
- "CHAIN_MISMATCH",
2353
- `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2354
- { expectedChainId: expected, actualChainId: after }
2193
+ "API_ROUTING_FAILED",
2194
+ `Routing API request failed: ${json.message}`,
2195
+ { message: json.message }
2355
2196
  );
2356
2197
  }
2198
+ return json.data;
2357
2199
  }
2358
2200
 
2359
- // src/lib/transfer-auth.ts
2360
- var import_viem3 = require("viem");
2361
-
2362
- // src/lib/sponsor-client.ts
2363
- var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2364
- async function postPaymasterIntent(input) {
2365
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2366
- let res;
2201
+ // src/lib/health-report.ts
2202
+ var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2203
+ async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
2367
2204
  try {
2368
- res = await fetch(`${base5}/api/v1/sponsor/paymaster-intent`, {
2205
+ await fetch(`${baseUrl}/api/v1/agent/health-report`, {
2369
2206
  method: "POST",
2370
2207
  headers: {
2371
- "content-type": "application/json",
2372
- "x-owney-api-key": input.apiKey,
2373
- Authorization: `Signature ${input.yieldseekerSignature}`
2208
+ "Content-Type": "application/json",
2209
+ "x-owney-api-key": apiKey
2374
2210
  },
2375
- body: JSON.stringify(input.body)
2211
+ body: JSON.stringify({
2212
+ agent_type: agentType,
2213
+ error_code: errorCode,
2214
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2215
+ })
2376
2216
  });
2377
- } catch (networkError) {
2378
- throw new OwneyError(
2379
- "SPONSOR_REQUEST_FAILED",
2380
- `Paymaster intent network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2381
- { cause: String(networkError), safeToFallback: true }
2382
- );
2383
- }
2384
- const text = await res.text();
2385
- let parsed = null;
2386
- try {
2387
- parsed = JSON.parse(text);
2388
- } catch {
2389
- }
2390
- if (!res.ok || !parsed?.success || typeof parsed.data?.intent !== "string" || typeof parsed.data.expiresAt !== "number") {
2391
- throw new OwneyError(
2392
- "SPONSOR_REQUEST_FAILED",
2393
- `Paymaster intent API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2394
- {
2395
- statusCode: res.status,
2396
- responseBody: text.slice(0, 500),
2397
- safeToFallback: true
2398
- }
2399
- );
2400
- }
2401
- return parsed.data;
2402
- }
2403
- async function getSponsorRelayerAddress(input) {
2404
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2405
- let res;
2406
- try {
2407
- res = await fetch(
2408
- `${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2409
- {
2410
- headers: { "x-owney-api-key": input.apiKey }
2411
- }
2412
- );
2413
- } catch (networkError) {
2414
- throw new OwneyError(
2415
- "SPONSOR_REQUEST_FAILED",
2416
- `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2417
- { cause: String(networkError), safeToFallback: true }
2418
- );
2419
- }
2420
- const text = await res.text();
2421
- let parsed = null;
2422
- try {
2423
- parsed = JSON.parse(text);
2424
- } catch {
2425
- }
2426
- if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
2427
- throw new OwneyError(
2428
- "SPONSOR_REQUEST_FAILED",
2429
- `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2430
- {
2431
- statusCode: res.status,
2432
- responseBody: text.slice(0, 500),
2433
- safeToFallback: true
2434
- }
2217
+ } catch (err) {
2218
+ console.warn(
2219
+ `[owney-sdk] health-report failed for agent "${agentType}":`,
2220
+ err instanceof Error ? err.message : err
2435
2221
  );
2436
2222
  }
2437
- return parsed.data.relayer;
2438
2223
  }
2439
- async function postSponsorBatchTransfer(input) {
2440
- let res;
2224
+ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
2441
2225
  try {
2442
- res = await fetch(
2443
- `${input.baseUrl ?? ROUTING_API_BASE_URL}/api/v1/sponsor/permit2-batch`,
2444
- {
2445
- method: "POST",
2446
- headers: {
2447
- "content-type": "application/json",
2448
- "x-owney-api-key": input.apiKey
2449
- },
2450
- body: JSON.stringify(input.body)
2451
- }
2452
- );
2453
- } catch {
2454
- throw new OwneyError(
2455
- "SPONSOR_REQUEST_FAILED",
2456
- "Deposit status is unknown. Retry the same amount to check it.",
2457
- { safeToFallback: false }
2458
- );
2459
- }
2460
- const parsed = await res.json().catch(() => null);
2461
- if (!res.ok || !parsed?.success || !/^0x[0-9a-fA-F]{64}$/.test(parsed.data?.txHash ?? "")) {
2462
- throw new OwneyError(
2463
- "SPONSOR_REQUEST_FAILED",
2464
- "Deposit could not be confirmed. Retry the same amount to check its status.",
2465
- {
2466
- statusCode: res.status,
2467
- safeToFallback: false,
2468
- notSubmitted: parsed?.notSubmitted === true || parsed?.error?.notSubmitted === true || parsed?.error?.details?.notSubmitted === true
2469
- }
2470
- );
2471
- }
2472
- return parsed.data;
2473
- }
2474
-
2475
- // src/lib/permit2.ts
2476
- var import_viem4 = require("viem");
2477
- var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2478
- var MAX_UINT256 = 2n ** 256n - 1n;
2479
- function permit2ApprovalAmount(requiredAmount) {
2480
- if (requiredAmount <= 0n) {
2481
- throw new Error("Permit2 approval requires a positive deposit amount");
2482
- }
2483
- return MAX_UINT256;
2484
- }
2485
- var ERC20_ALLOWANCE_ABI = [
2486
- {
2487
- type: "function",
2488
- name: "allowance",
2489
- stateMutability: "view",
2490
- inputs: [
2491
- { name: "owner", type: "address" },
2492
- { name: "spender", type: "address" }
2493
- ],
2494
- outputs: [{ name: "", type: "uint256" }]
2495
- },
2496
- {
2497
- type: "function",
2498
- name: "approve",
2499
- stateMutability: "nonpayable",
2500
- inputs: [
2501
- { name: "spender", type: "address" },
2502
- { name: "amount", type: "uint256" }
2503
- ],
2504
- outputs: [{ name: "", type: "bool" }]
2505
- },
2506
- {
2507
- type: "function",
2508
- name: "balanceOf",
2509
- stateMutability: "view",
2510
- inputs: [{ name: "account", type: "address" }],
2511
- outputs: [{ name: "", type: "uint256" }]
2512
- }
2513
- ];
2514
- function randomPermit2Nonce() {
2515
- const bytes = new Uint8Array(32);
2516
- globalThis.crypto.getRandomValues(bytes);
2517
- return BigInt((0, import_viem4.bytesToHex)(bytes));
2518
- }
2519
- async function readPermit2Allowance(publicClient, token, owner, blockNumber) {
2520
- return publicClient.readContract({
2521
- address: token,
2522
- abi: ERC20_ALLOWANCE_ABI,
2523
- functionName: "allowance",
2524
- args: [owner, PERMIT2_ADDRESS],
2525
- ...blockNumber === void 0 ? {} : { blockNumber }
2526
- });
2527
- }
2528
- async function readErc20Balance(publicClient, token, owner) {
2529
- return publicClient.readContract({
2530
- address: token,
2531
- abi: ERC20_ALLOWANCE_ABI,
2532
- functionName: "balanceOf",
2533
- args: [owner]
2534
- });
2535
- }
2536
-
2537
- // src/lib/sponsored-deposit.ts
2538
- var AUTH_WINDOW_SECONDS = 15 * 60;
2539
- var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
2540
- function provideDepositVerificationContext(callback, context) {
2541
- callback[verificationSetter]?.(context);
2542
- }
2543
- function makeVerificationAwareDepositCallback(implementation) {
2544
- let nextVerification;
2545
- const callback = async (smartWallet, chainId, amount) => {
2546
- const verification = nextVerification;
2547
- nextVerification = void 0;
2548
- return implementation(smartWallet, chainId, amount, verification);
2549
- };
2550
- Object.defineProperty(callback, verificationSetter, {
2551
- value: (context) => {
2552
- nextVerification = context;
2553
- }
2554
- });
2555
- return callback;
2556
- }
2557
-
2558
- // src/agents/yieldseeker/yieldseeker.auth.ts
2559
- var import_siwe = require("siwe");
2560
- var import_viem5 = require("viem");
2561
- var import_chains2 = require("viem/chains");
2562
-
2563
- // src/agents/yieldseeker/yieldseeker.auth-cache.ts
2564
- var KEY_PREFIX2 = "owney.yieldseeker.session.v5";
2565
- var INVALIDATED_KEY_PREFIXES = [
2566
- "owney.yieldseeker.session",
2567
- "owney.yieldseeker.session.v3",
2568
- "owney.yieldseeker.session.v4"
2569
- ];
2570
- var storage2 = () => {
2571
- if (typeof window === "undefined") return null;
2572
- try {
2573
- return window.localStorage;
2574
- } catch {
2575
- return null;
2576
- }
2577
- };
2578
- var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
2579
- var invalidatedKeys = (address, chainId) => INVALIDATED_KEY_PREFIXES.map(
2580
- (prefix) => `${prefix}:${address.toLowerCase()}:${chainId}`
2581
- );
2582
- var clearInvalidatedSessions = (store, address, chainId) => {
2583
- for (const key2 of invalidatedKeys(address, chainId)) {
2584
- memorySessions2.delete(key2);
2585
- try {
2586
- store?.removeItem(key2);
2587
- } catch {
2588
- }
2589
- }
2590
- };
2591
- var memorySessions2 = /* @__PURE__ */ new Map();
2592
- var isValidSession = (session) => {
2593
- if (!session?.token) return false;
2594
- try {
2595
- const parsed = JSON.parse(atob(session.token));
2596
- return typeof parsed.message === "string" && typeof parsed.signature === "string" && parsed.signature.startsWith("0x");
2597
- } catch {
2598
- return false;
2599
- }
2600
- };
2601
- var readYieldseekerSession = (address, chainId) => {
2602
- if (typeof window === "undefined") return null;
2603
- const key2 = buildKey2(address, chainId);
2604
- const store = storage2();
2605
- clearInvalidatedSessions(store, address, chainId);
2606
- let raw2 = null;
2607
- try {
2608
- raw2 = store?.getItem(key2) ?? null;
2609
- } catch {
2610
- raw2 = null;
2611
- }
2612
- if (raw2) {
2613
- try {
2614
- const parsed = JSON.parse(raw2);
2615
- if (isValidSession(parsed)) return parsed.token;
2616
- } catch {
2617
- }
2618
- memorySessions2.delete(key2);
2619
- try {
2620
- store?.removeItem(key2);
2621
- } catch {
2622
- }
2623
- return null;
2624
- }
2625
- const cached = memorySessions2.get(key2);
2626
- if (isValidSession(cached)) return cached.token;
2627
- if (cached) memorySessions2.delete(key2);
2628
- return null;
2629
- };
2630
- var writeYieldseekerSession = (address, chainId, token) => {
2631
- if (typeof window === "undefined") return;
2632
- const session = { token };
2633
- if (!isValidSession(session)) return;
2634
- const key2 = buildKey2(address, chainId);
2635
- memorySessions2.set(key2, session);
2636
- const store = storage2();
2637
- try {
2638
- store?.setItem(key2, JSON.stringify(session));
2639
- } catch {
2640
- }
2641
- };
2642
- var clearYieldseekerSession = (address, chainId) => {
2643
- const key2 = buildKey2(address, chainId);
2644
- memorySessions2.delete(key2);
2645
- const store = storage2();
2646
- clearInvalidatedSessions(store, address, chainId);
2647
- try {
2648
- store?.removeItem(key2);
2649
- } catch {
2650
- }
2651
- };
2652
-
2653
- // src/agents/yieldseeker/yieldseeker.auth.ts
2654
- function resolveSiweOrigin(override) {
2655
- const origin = override?.trim() || (typeof window !== "undefined" ? window.location?.origin : void 0);
2656
- if (!origin || origin === "null") {
2657
- throw new Error("Yieldseeker sign-in requires the requesting app's browser origin.");
2658
- }
2659
- const url = new URL(origin);
2660
- if (url.protocol !== "https:" && url.protocol !== "http:") {
2661
- throw new Error("Yieldseeker sign-in requires an HTTP or HTTPS app origin.");
2662
- }
2663
- if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
2664
- throw new Error("Yieldseeker SIWE override must be an origin without credentials, path, query, or fragment.");
2665
- }
2666
- return url;
2667
- }
2668
- function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
2669
- const url = resolveSiweOrigin(dependencies.origin);
2670
- return new import_siwe.SiweMessage({
2671
- scheme: url.protocol.slice(0, -1),
2672
- domain: url.host,
2673
- address: (0, import_viem5.getAddress)(address),
2674
- uri: url.origin,
2675
- version: "1",
2676
- chainId,
2677
- nonce: (dependencies.nonce ?? import_siwe.generateNonce)(),
2678
- issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
2679
- }).prepareMessage();
2680
- }
2681
- function encodeYieldseekerAuthToken(token) {
2682
- const bytes = new TextEncoder().encode(JSON.stringify(token));
2683
- let binary = "";
2684
- for (const byte of bytes) binary += String.fromCharCode(byte);
2685
- return btoa(binary);
2686
- }
2687
- var YieldseekerAuth = class {
2688
- constructor(dependencies = {}) {
2689
- this.dependencies = dependencies;
2690
- }
2691
- dependencies;
2692
- tokens = /* @__PURE__ */ new Map();
2693
- pending = /* @__PURE__ */ new Map();
2694
- scopes = /* @__PURE__ */ new Map();
2695
- key(state, chainId) {
2696
- return `${state.walletAddress.toLowerCase()}:${chainId}:${resolveSiweOrigin(this.dependencies.origin).origin}`;
2697
- }
2698
- async getToken(state, chainId) {
2699
- const key2 = this.key(state, chainId);
2700
- const scope = { address: state.walletAddress, chainId };
2701
- this.scopes.set(key2, scope);
2702
- const cached = this.tokens.get(key2);
2703
- if (cached) return cached;
2704
- const persisted = readYieldseekerSession(scope.address, scope.chainId);
2705
- if (persisted && this.matchesOrigin(persisted)) {
2706
- this.tokens.set(key2, persisted);
2707
- return persisted;
2708
- }
2709
- if (persisted) clearYieldseekerSession(scope.address, scope.chainId);
2710
- const inFlight = this.pending.get(key2);
2711
- if (inFlight) return inFlight;
2712
- const request = this.sign(state, chainId).then((token) => {
2713
- if (this.pending.get(key2) !== request) throw new Error("Wallet sign-in session changed. Please try again.");
2714
- this.tokens.set(key2, token);
2715
- writeYieldseekerSession(scope.address, scope.chainId, token);
2716
- return token;
2717
- });
2718
- this.pending.set(key2, request);
2719
- try {
2720
- return await request;
2721
- } finally {
2722
- if (this.pending.get(key2) === request) this.pending.delete(key2);
2723
- }
2724
- }
2725
- async refreshToken(state, chainId, rejectedToken) {
2726
- const key2 = this.key(state, chainId);
2727
- if (this.tokens.get(key2) === rejectedToken) {
2728
- this.tokens.delete(key2);
2729
- clearYieldseekerSession(state.walletAddress, chainId);
2730
- }
2731
- return this.getToken(state, chainId);
2732
- }
2733
- matchesOrigin(token) {
2734
- try {
2735
- const message = new import_siwe.SiweMessage(JSON.parse(atob(token)).message);
2736
- const url = resolveSiweOrigin(this.dependencies.origin);
2737
- return message.domain === url.host && message.uri === url.origin && message.scheme === url.protocol.slice(0, -1);
2738
- } catch {
2739
- return false;
2740
- }
2741
- }
2742
- clear(state, chainId) {
2743
- if (!state || chainId === void 0) {
2744
- for (const scope of this.scopes.values()) {
2745
- clearYieldseekerSession(scope.address, scope.chainId);
2746
- }
2747
- this.tokens.clear();
2748
- this.pending.clear();
2749
- this.scopes.clear();
2750
- return;
2751
- }
2752
- const key2 = this.key(state, chainId);
2753
- this.tokens.delete(key2);
2754
- this.pending.delete(key2);
2755
- this.scopes.delete(key2);
2756
- clearYieldseekerSession(state.walletAddress, chainId);
2757
- }
2758
- async sign(state, chainId) {
2759
- const account = (0, import_viem5.getAddress)(state.walletAddress);
2760
- const publicClient = (0, import_viem5.createPublicClient)({
2761
- chain: import_chains2.base,
2762
- transport: (0, import_viem5.custom)(state.provider)
2763
- });
2764
- const walletClient = (0, import_viem5.createWalletClient)({
2765
- account,
2766
- chain: import_chains2.base,
2767
- transport: (0, import_viem5.custom)(state.provider)
2768
- });
2769
- await ensureWalletOnChain(
2770
- publicClient,
2771
- walletClient,
2772
- 8453
2773
- );
2774
- const message = createYieldseekerSiweMessage(
2775
- account,
2776
- chainId,
2777
- this.dependencies
2778
- );
2779
- const signature = await walletClient.signMessage({ account, message });
2780
- return encodeYieldseekerAuthToken({ message, signature });
2781
- }
2782
- };
2783
-
2784
- // src/agents/yieldseeker/yieldseeker.identity-cache.ts
2785
- var KEY_PREFIX3 = "owney.yieldseeker.identity.v1";
2786
- var YIELDSEEKER_IDENTITY_TTL_MS = 24 * 60 * 60 * 1e3;
2787
- var memoryIdentities = /* @__PURE__ */ new Map();
2788
- var storage3 = () => {
2789
- if (typeof window === "undefined") return null;
2790
- try {
2791
- return window.localStorage;
2792
- } catch {
2793
- return null;
2794
- }
2795
- };
2796
- var keyFor = (walletAddress, chainId) => `${KEY_PREFIX3}:${walletAddress.toLowerCase()}:${chainId}`;
2797
- function valid(value, walletAddress, chainId, now) {
2798
- return Boolean(
2799
- 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
2800
- );
2801
- }
2802
- function readYieldseekerIdentity(walletAddress, chainId, now = Date.now()) {
2803
- if (typeof window === "undefined") return null;
2804
- const key2 = keyFor(walletAddress, chainId);
2805
- const store = storage3();
2806
- let parsed = null;
2807
- try {
2808
- const raw2 = store?.getItem(key2);
2809
- parsed = raw2 ? JSON.parse(raw2) : null;
2810
- } catch {
2811
- parsed = null;
2812
- }
2813
- const candidate = parsed ?? memoryIdentities.get(key2);
2814
- if (valid(candidate, walletAddress, chainId, now)) {
2815
- memoryIdentities.set(key2, candidate);
2816
- return { userId: candidate.userId };
2817
- }
2818
- memoryIdentities.delete(key2);
2819
- try {
2820
- store?.removeItem(key2);
2821
- } catch {
2822
- }
2823
- return null;
2824
- }
2825
- function writeYieldseekerIdentity(walletAddress, chainId, userId, now = Date.now()) {
2826
- if (typeof window === "undefined") return;
2827
- const identity = {
2828
- userId,
2829
- walletAddress,
2830
- chainId,
2831
- expiresAt: now + YIELDSEEKER_IDENTITY_TTL_MS
2832
- };
2833
- if (!valid(identity, walletAddress, chainId, now)) return;
2834
- const key2 = keyFor(walletAddress, chainId);
2835
- memoryIdentities.set(key2, identity);
2836
- try {
2837
- storage3()?.setItem(key2, JSON.stringify(identity));
2838
- } catch {
2839
- }
2840
- }
2841
- function clearYieldseekerIdentity(walletAddress, chainId) {
2842
- const key2 = keyFor(walletAddress, chainId);
2843
- memoryIdentities.delete(key2);
2844
- try {
2845
- storage3()?.removeItem(key2);
2846
- } catch {
2847
- }
2848
- }
2849
-
2850
- // src/agents/yieldseeker/yieldseeker.client.ts
2851
- var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2852
- function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
2853
- return `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/agent/yieldseeker`;
2854
- }
2855
- var YIELDSEEKER_API_BASE_URL = getYieldseekerProxyBaseUrl();
2856
- var YieldseekerApiError = class extends Error {
2857
- constructor(status, providerCode, responseFields) {
2858
- super(`Yieldseeker request failed (${status}): ${providerCode}`);
2859
- this.status = status;
2860
- this.providerCode = providerCode;
2861
- this.responseFields = responseFields;
2862
- this.name = "YieldseekerApiError";
2863
- }
2864
- status;
2865
- providerCode;
2866
- responseFields;
2867
- get isAuthenticationError() {
2868
- return this.status === 401 || this.status === 403;
2869
- }
2870
- };
2871
- function providerError(body, fallback) {
2872
- if (!body || typeof body !== "object") return { code: fallback };
2873
- const record = body;
2874
- return {
2875
- code: typeof record.message === "string" ? record.message : fallback,
2876
- fields: record.fields && typeof record.fields === "object" ? record.fields : void 0
2877
- };
2878
- }
2879
- var YieldseekerApiClient = class {
2880
- constructor(owneyApiKey, baseUrl = YIELDSEEKER_API_BASE_URL, fetchFn = fetch.bind(globalThis)) {
2881
- this.owneyApiKey = owneyApiKey;
2882
- this.baseUrl = baseUrl;
2883
- this.fetchFn = fetchFn;
2884
- }
2885
- owneyApiKey;
2886
- baseUrl;
2887
- fetchFn;
2888
- async request(path, options = {}) {
2889
- const controller = new AbortController();
2890
- const timer = setTimeout(
2891
- () => controller.abort(),
2892
- options.timeoutMs ?? 15e3
2893
- );
2894
- try {
2895
- const response = await this.fetchFn(`${this.baseUrl}${path}`, {
2896
- method: options.method ?? "GET",
2897
- headers: {
2898
- "Content-Type": "application/json",
2899
- "x-owney-api-key": this.owneyApiKey,
2900
- ...options.signature ? { Authorization: `Signature ${options.signature}` } : {}
2901
- },
2902
- body: options.body ? JSON.stringify(options.body) : void 0,
2903
- signal: controller.signal
2904
- });
2905
- const payload = await response.json().catch(() => null);
2906
- if (!response.ok) {
2907
- const error = providerError(payload, `HTTP_${response.status}`);
2908
- const retryAfter = response.headers.get("Retry-After");
2909
- throw new YieldseekerApiError(
2910
- response.status,
2911
- error.code,
2912
- retryAfter ? { ...error.fields, headers: { "Retry-After": retryAfter } } : error.fields
2913
- );
2914
- }
2915
- if (payload && typeof payload === "object" && payload.success === true && "data" in payload) {
2916
- return payload.data;
2917
- }
2918
- return payload;
2919
- } catch (error) {
2920
- if (error instanceof YieldseekerApiError) throw error;
2921
- if (error instanceof DOMException && error.name === "AbortError") {
2922
- throw new YieldseekerApiError(408, "REQUEST_TIMEOUT");
2923
- }
2924
- throw new YieldseekerApiError(0, "NETWORK_ERROR", {
2925
- cause: error instanceof Error ? error.message : String(error)
2926
- });
2927
- } finally {
2928
- clearTimeout(timer);
2929
- }
2930
- }
2931
- };
2932
-
2933
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2934
- var import_viem6 = require("viem");
2935
-
2936
- // src/lib/helpers/snapshot-apy.ts
2937
- var DAY_MS = 864e5;
2938
- function snapshotTime(date) {
2939
- if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return void 0;
2940
- const time = Date.parse(date);
2941
- return Number.isFinite(time) && new Date(time).toISOString().slice(0, 10) === date ? time : void 0;
2942
- }
2943
- function returnFactor(value) {
2944
- if (typeof value !== "number" && typeof value !== "string") return void 0;
2945
- if (typeof value === "string" && value.trim() === "") return void 0;
2946
- const factor = Number(value);
2947
- return Number.isFinite(factor) && factor >= 0 ? factor : void 0;
2948
- }
2949
- function calculateSnapshotApy(snapshots, lookbackDays, now = Date.now()) {
2950
- if (!Number.isFinite(lookbackDays) || lookbackDays <= 0 || !Number.isFinite(now)) {
2951
- return void 0;
2952
- }
2953
- const points = snapshots.flatMap((snapshot) => {
2954
- const time = snapshotTime(snapshot.date);
2955
- return time !== void 0 && time <= now ? [{ snapshot, time }] : [];
2956
- }).sort((a, b) => a.time - b.time);
2957
- const end = points.at(-1);
2958
- if (!end) return void 0;
2959
- const cutoff = end.time - lookbackDays * DAY_MS;
2960
- const start = points.find((point) => point.time >= cutoff);
2961
- const actualDays = (end.time - start.time) / DAY_MS;
2962
- if (actualDays <= 0) return void 0;
2963
- const startFactor = returnFactor(start.snapshot.cumulativeReturnFactor);
2964
- const endFactor = returnFactor(end.snapshot.cumulativeReturnFactor);
2965
- if (startFactor === void 0 || startFactor === 0 || endFactor === void 0) {
2966
- return void 0;
2967
- }
2968
- const periodReturn = endFactor / startFactor - 1;
2969
- const apy = Math.pow(1 + periodReturn, 365 / actualDays) - 1;
2970
- return Number.isFinite(apy) ? apy : void 0;
2971
- }
2972
-
2973
- // src/agents/yieldseeker/yieldseeker.types.ts
2974
- var YIELDSEEKER_ASSET_METADATA = {
2975
- USDC: {
2976
- address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
2977
- decimals: 6
2978
- },
2979
- WETH: {
2980
- address: "0x4200000000000000000000000000000000000006",
2981
- decimals: 18
2982
- }
2983
- };
2984
-
2985
- // src/agents/yieldseeker/yieldseeker.mapper.ts
2986
- function invalid(endpoint, detail) {
2987
- throw new OwneyError(
2988
- "AGENT_INVALID_RESPONSE",
2989
- `Yieldseeker returned an invalid ${endpoint} response: ${detail}.`,
2990
- { endpoint, detail },
2991
- "yieldseeker"
2992
- );
2993
- }
2994
- function raw(value, endpoint) {
2995
- if (typeof value !== "string" || !/^-?[0-9]+$/.test(value)) {
2996
- return invalid(endpoint, "expected a base-10 integer string");
2997
- }
2998
- return BigInt(value);
2999
- }
3000
- function decimal(value, decimals, endpoint) {
3001
- return (0, import_viem6.formatUnits)(raw(value, endpoint), decimals);
3002
- }
3003
- function usd(rawAmount, decimals, price) {
3004
- return Number((0, import_viem6.formatUnits)(rawAmount, decimals)) * price;
3005
- }
3006
- function percent(value) {
3007
- const result = Number(value);
3008
- return Number.isFinite(result) ? result * 100 : 0;
3009
- }
3010
- var YIELDSEEKER_POSITIVE_YIELD_FEE_RATE = 0.1;
3011
- function publicApyAfterYieldseekerFee(value) {
3012
- const grossPercent = percent(value);
3013
- if (grossPercent <= 0) return grossPercent;
3014
- const netPercent = grossPercent * (1 - YIELDSEEKER_POSITIVE_YIELD_FEE_RATE);
3015
- return Math.round(netPercent * 1e12) / 1e12;
3016
- }
3017
- function riskAdjustedApyForDays(option, days) {
3018
- if (days === "7D") return option.riskAdjustedApy7dAverage;
3019
- if (days === "30D") return option.riskAdjustedApy30dAverage;
3020
- return (option.riskAdjustedApy7dAverage + option.riskAdjustedApy30dAverage) / 2;
3021
- }
3022
- function assetAddressValue(record, address) {
3023
- const entry = Object.entries(record).find(
3024
- ([key2]) => key2.toLowerCase() === address.toLowerCase()
3025
- );
3026
- return entry?.[1] ?? "0";
3027
- }
3028
- function position(value, asset, baseAssetDecimals) {
3029
- const option = value?.yieldOption;
3030
- if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem6.isAddress)(option.address)) {
3031
- return invalid("yield positions", "missing vault metadata");
3032
- }
3033
- return {
3034
- chain: "BASE",
3035
- protocol: option.provider,
3036
- protocolId: option.address,
3037
- pool: option.name,
3038
- asset,
3039
- // `assetsRaw` is the ERC-4626 vault-share quantity, whose decimals can
3040
- // differ from the underlying asset. Yieldseeker already converts it to
3041
- // underlying base-asset units in `assetsBase`; pair that value with the
3042
- // snapshot's corresponding `baseAssetDecimals` for display. Keep the raw
3043
- // share quantity separate from the withdrawable underlying asset amount.
3044
- amount: decimal(
3045
- value.assetsBase,
3046
- baseAssetDecimals,
3047
- "yield positions"
3048
- ),
3049
- amountRaw: String(value.assetsRaw),
3050
- withdrawableAmountRaw: String(value.withdrawableAssetsRaw),
3051
- apy: percent(option.riskAdjustedApy),
3052
- tvl: Number(option.totalDepositsUsd),
3053
- liquidity: Number(option.withdrawableDepositsUsd)
3054
- };
3055
- }
3056
- function mapYieldseekerBalances(contexts) {
3057
- const tokens = [];
3058
- const assetBalances = [];
3059
- const positions = [];
3060
- let totalUsd = 0;
3061
- for (const context of contexts) {
3062
- const metadata = YIELDSEEKER_ASSET_METADATA[context.asset];
3063
- assetBalances.push({
3064
- chain: "BASE",
3065
- chainId: 8453,
3066
- asset: context.asset,
3067
- amount: decimal(context.snapshot.totalValueBase, context.snapshot.baseAssetDecimals, "snapshot")
3068
- });
3069
- const idle = assetAddressValue(
3070
- context.snapshot.tokenBalances,
3071
- metadata.address
3072
- );
3073
- tokens.push({
3074
- chain: "BASE",
3075
- chainId: 8453,
3076
- asset: context.asset,
3077
- amount: decimal(idle, metadata.decimals, "snapshot")
3078
- });
3079
- positions.push(
3080
- ...context.positions.map(
3081
- (entry) => position(
3082
- entry,
3083
- context.asset,
3084
- context.snapshot.baseAssetDecimals
3085
- )
3086
- )
3087
- );
3088
- totalUsd += usd(
3089
- raw(context.snapshot.totalValueBase, "snapshot"),
3090
- context.snapshot.baseAssetDecimals,
3091
- context.snapshot.baseAssetPriceUsd
3092
- );
3093
- }
3094
- return {
3095
- ...contexts.length === 1 ? { smartWallet: contexts[0].wallet.walletAddress } : {},
3096
- totalBalance: String(totalUsd),
3097
- totalBalanceAsset: "usdc",
3098
- assetBalances,
3099
- tokens,
3100
- positions
3101
- };
3102
- }
3103
- function mapYieldseekerEarnings(contexts) {
3104
- const tokens = [];
3105
- let lifetimeEarnings = 0;
3106
- for (const context of contexts) {
3107
- const amount = raw(context.snapshot.cumulativeYieldBase, "snapshot");
3108
- tokens.push({
3109
- chain: "BASE",
3110
- chainId: 8453,
3111
- asset: context.asset,
3112
- amount: (0, import_viem6.formatUnits)(amount, context.snapshot.baseAssetDecimals)
3113
- });
3114
- lifetimeEarnings += usd(
3115
- amount,
3116
- context.snapshot.baseAssetDecimals,
3117
- context.snapshot.baseAssetPriceUsd
3118
- );
3119
- }
3120
- return {
3121
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
3122
- lifetimeEarnings,
3123
- tokens
3124
- };
3125
- }
3126
- function apyForDays(context, days, now) {
3127
- if (days === "7D") return percent(context.snapshot.apy7d);
3128
- if (days === "30D") return percent(context.snapshot.apy30d);
3129
- const apy = calculateSnapshotApy(context.historic?.dailyYieldSnapshots ?? [], 14, now);
3130
- const apyPercent = apy === void 0 ? void 0 : apy * 100;
3131
- return apyPercent !== void 0 && Number.isFinite(apyPercent) ? apyPercent : void 0;
3132
- }
3133
- function dailyApy(point) {
3134
- const total = raw(point.totalValueBase, "historic position");
3135
- const earned = raw(point.dailyYieldBase, "historic position");
3136
- const principal = total - earned;
3137
- if (principal <= 0n || earned === 0n) return 0;
3138
- return Number(earned) / Number(principal) * 365 * 100;
3139
- }
3140
- function aggregateHistory(contexts, dayCount, now) {
3141
- const today = new Date(now).toISOString().slice(0, 10);
3142
- const cutoff = new Date(Date.parse(today) - (dayCount - 1) * 864e5).toISOString().slice(0, 10);
3143
- const assets = new Set(contexts.map((context) => context.asset.toUpperCase()));
3144
- const unit = assets.size === 1 ? [...assets][0] : "USD";
3145
- const byDate = /* @__PURE__ */ new Map();
3146
- for (const context of contexts) {
3147
- const points = context.historic?.dailyYieldSnapshots ?? [];
3148
- for (const point of points) {
3149
- if (!/^\d{4}-\d{2}-\d{2}$/.test(point.date) || !Number.isFinite(Date.parse(point.date)) || point.date < cutoff || point.date > today) continue;
3150
- const tokens = Number(decimal(point.totalValueBase, point.baseAssetDecimals, "historic position"));
3151
- const amount = assets.size === 1 ? tokens : tokens * point.baseAssetPriceUsd;
3152
- if (!Number.isFinite(amount) || amount < 0) {
3153
- invalid("historic position", "expected a finite non-negative balance");
3154
- }
3155
- const current = byDate.get(point.date) ?? { weighted: 0, amount: 0 };
3156
- current.weighted += dailyApy(point) * amount;
3157
- current.amount += amount;
3158
- byDate.set(point.date, current);
3159
- }
3160
- }
3161
- return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
3162
- date,
3163
- apy: value.amount > 0 ? value.weighted / value.amount : 0,
3164
- historicalBalance: { amount: value.amount, unit }
3165
- }));
3166
- }
3167
- function mapYieldseekerApy(walletAddress, contexts, days, now = Date.now()) {
3168
- let weighted = 0;
3169
- let totalUsd = 0;
3170
- const byAsset = {};
3171
- for (const context of contexts) {
3172
- const valueUsd = usd(
3173
- raw(context.snapshot.totalValueBase, "snapshot"),
3174
- context.snapshot.baseAssetDecimals,
3175
- context.snapshot.baseAssetPriceUsd
3176
- );
3177
- const apy = apyForDays(context, days, now);
3178
- if (apy === void 0) continue;
3179
- weighted += apy * valueUsd;
3180
- totalUsd += valueUsd;
3181
- byAsset[context.asset] = apy;
3182
- }
3183
- const dayCount = Number(days.slice(0, -1));
3184
- return {
3185
- walletAddress,
3186
- ...days !== "14D" || Object.keys(byAsset).length > 0 ? { weightedApyAfterFee: totalUsd > 0 ? weighted / totalUsd : 0 } : {},
3187
- apyByChainAndAsset: { 8453: byAsset },
3188
- history: aggregateHistory(contexts, dayCount, now)
3189
- };
3190
- }
3191
- function actionType(value) {
3192
- const normalized = value.toLowerCase();
3193
- if (normalized.includes("deposit")) return "Deposit";
3194
- if (normalized.includes("withdraw")) return "Withdraw";
3195
- if (normalized.includes("yield") || normalized.includes("earn"))
3196
- return "Earned";
3197
- return "Rebalance";
3198
- }
3199
- function transactionHashes(details) {
3200
- if (!details) return [];
3201
- const values = [
3202
- details.transactionHash,
3203
- details.txHash,
3204
- ...Array.isArray(details.transactionHashes) ? details.transactionHashes : [],
3205
- ...Array.isArray(details.txHashes) ? details.txHashes : []
3206
- ];
3207
- return values.filter(
3208
- (value) => typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value)
3209
- ).filter((value, index, all) => all.indexOf(value) === index);
3210
- }
3211
- function actionEntry(action) {
3212
- if (action.actionType.toLowerCase().includes("withdraw")) return void 0;
3213
- return {
3214
- agent: "yieldseeker",
3215
- action: actionType(action.actionType),
3216
- date: action.createdDate,
3217
- oldApy: null,
3218
- newApy: null,
3219
- transactions: [
3220
- {
3221
- txHashes: transactionHashes(action.details),
3222
- chainId: 8453
3223
- }
3224
- ],
3225
- rebalanceLog: []
3226
- };
3227
- }
3228
- function depositDestination(context, movement) {
3229
- const to = movement.toAddress.toLowerCase();
3230
- const option = context.positions.find(({ yieldOption }) => yieldOption.chainId === movement.chainId && yieldOption.assetAddress.toLowerCase() === context.agent.assetAddress.toLowerCase() && yieldOption.address.toLowerCase() === to)?.yieldOption;
3231
- if (option) return { protocol: option.provider || "Vault", pool: option.name, tokenSymbol: context.asset };
3232
- const receipt = context.historic?.assets.find((asset) => asset.chainId === movement.chainId && !asset.isSpam && asset.address.toLowerCase() === to && asset.address.toLowerCase() !== context.agent.assetAddress.toLowerCase());
3233
- 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);
3234
- if (receipt && minted) return { protocol: "Vault", pool: receipt.name || receipt.symbol, tokenSymbol: context.asset };
3235
- return void 0;
3236
- }
3237
- function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddresses, destination) {
3238
- const from = movement.fromAddress.toLowerCase();
3239
- const to = movement.toAddress.toLowerCase();
3240
- const owner = ownerAddress.toLowerCase();
3241
- const agentWallet = wallet.walletAddress.toLowerCase();
3242
- const baseAsset = agent.assetAddress.toLowerCase();
3243
- if (movement.chainId !== agent.chainId || movement.assetAddress.toLowerCase() !== baseAsset) {
3244
- return void 0;
3245
- }
3246
- let action;
3247
- if (to === agentWallet && !vaultAddresses.has(from)) {
3248
- action = "Top up";
3249
- } else if (from === agentWallet && to === owner) {
3250
- action = "Withdraw";
3251
- } else if (from === agentWallet && destination) {
3252
- action = "Deposit";
3253
- }
3254
- if (!action) return void 0;
3255
- return {
3256
- agent: "yieldseeker",
3257
- action,
3258
- ...action === "Deposit" && destination ? { positions: [{
3259
- ...destination,
3260
- amount: decimal(movement.assetAmount, YIELDSEEKER_ASSET_METADATA[asset].decimals, "historic position")
3261
- }] } : {},
3262
- date: movement.blockDate,
3263
- oldApy: null,
3264
- newApy: null,
3265
- transactions: [
3266
- {
3267
- txHashes: [movement.transactionHash],
3268
- chainId: agent.chainId,
3269
- tokenSymbol: asset,
3270
- amount: decimal(
3271
- movement.assetAmount,
3272
- YIELDSEEKER_ASSET_METADATA[asset].decimals,
3273
- "historic position"
3274
- )
3275
- }
3276
- ],
3277
- rebalanceLog: []
3278
- };
3279
- }
3280
- function mapYieldseekerHistory(contexts, options) {
3281
- const entries = contexts.flatMap((context) => {
3282
- const seenMovements = /* @__PURE__ */ new Set();
3283
- const movements = (context.historic?.movements ?? []).filter((movement) => {
3284
- const key2 = `${movement.chainId}:${movement.transactionHash.toLowerCase()}:${movement.logIndex}`;
3285
- if (seenMovements.has(key2)) return false;
3286
- seenMovements.add(key2);
3287
- return true;
3288
- });
3289
- return [
3290
- ...movements.map(
3291
- (movement) => movementEntry(
3292
- movement,
3293
- context.wallet,
3294
- context.agent,
3295
- context.asset,
3296
- options.ownerAddress,
3297
- options.vaultAddresses,
3298
- depositDestination(context, movement)
3299
- )
3300
- ),
3301
- ...(context.actions ?? []).map(actionEntry)
3302
- ].filter((entry) => entry !== void 0);
3303
- });
3304
- const grouped = /* @__PURE__ */ new Map();
3305
- const ungrouped = [];
3306
- for (const entry of entries) {
3307
- const tx = entry.transactions[0];
3308
- const hash = tx?.txHashes[0];
3309
- if (!hash) {
3310
- ungrouped.push(entry);
3311
- continue;
3312
- }
3313
- const key2 = `${entry.agent}:${entry.action}:${tx.chainId}:${hash.toLowerCase()}`;
3314
- const previous = grouped.get(key2);
3315
- if (!previous) {
3316
- grouped.set(key2, entry);
3317
- continue;
3318
- }
3319
- if (entry.action === "Deposit" && entry.positions?.length) {
3320
- if (!previous.positions?.length) {
3321
- grouped.set(key2, entry);
3322
- continue;
3323
- }
3324
- previous.positions.push(...entry.positions);
3325
- previous.transactions.push(...entry.transactions);
3326
- }
3327
- }
3328
- 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));
3329
- return {
3330
- data: filtered.slice(0, options.limit),
3331
- // v1 returns the whole action/movement collection and defines no cursor.
3332
- // Report a terminal page so callers never loop over the same prefix.
3333
- hasMore: false
3334
- };
3335
- }
3336
- function mapYieldseekerProfile(address, contexts) {
3337
- const protocols = /* @__PURE__ */ new Set();
3338
- for (const context of contexts) {
3339
- for (const current of context.positions) {
3340
- if (current.yieldOption?.provider) {
3341
- protocols.add(String(current.yieldOption.provider));
3342
- }
3343
- }
3344
- }
3345
- return {
3346
- address,
3347
- smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
3348
- chains: contexts.length > 0 ? [8453] : [],
3349
- hasActiveSessionKey: contexts.some(
3350
- (context) => context.wallet.initializedDate != null
3351
- ),
3352
- protocols: [...protocols]
3353
- };
3354
- }
3355
- function mapYieldseekerAgentApy(options, days) {
3356
- const perAsset = {};
3357
- const all = [];
3358
- for (const entry of options) {
3359
- const apys = entry.yieldOptions.map(
3360
- (option) => publicApyAfterYieldseekerFee(riskAdjustedApyForDays(option, days))
3361
- ).filter(Number.isFinite);
3362
- if (apys.length === 0) continue;
3363
- const average = apys.reduce((sum, value) => sum + value, 0) / apys.length;
3364
- perAsset[entry.asset] = average;
3365
- all.push(average);
3366
- }
3367
- return {
3368
- averageApy: all.length > 0 ? all.reduce((sum, value) => sum + value, 0) / all.length : 0,
3369
- detailedApys: { apyPerAsset: { 8453: perAsset } }
3370
- };
3371
- }
3372
-
3373
- // src/agents/yieldseeker/yieldseeker.agent.ts
3374
- var OWNEY_AGENT_NAME = "owney";
3375
- var YIELDSEEKER_USERNAME_PREFIX = "owney_";
3376
- var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
3377
- var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
3378
- var YIELDSEEKER_YIELD_OPTIONS_CACHE_MS = 6e4;
3379
- var YIELDSEEKER_AGENT_LIST_CACHE_MS = 12e4;
3380
- var YIELDSEEKER_PORTFOLIO_CACHE_MS = 12e4;
3381
- var YIELDSEEKER_SETTLEMENT_CACHE_MS = 5e3;
3382
- var YIELDSEEKER_SETTLEMENT_ACTIVITY_CACHE_MS = 15e3;
3383
- var YIELDSEEKER_READ_FAILURE_COOLDOWN_MS = 6e4;
3384
- var YIELDSEEKER_SETTLEMENT_WINDOW_MS = 5 * 6e4;
3385
- var YIELDSEEKER_ACTIVITY_CACHE_MS = 6e4;
3386
- function generateYieldseekerUsername() {
3387
- const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
3388
- return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
3389
- }
3390
- function isUsernameConflict(error) {
3391
- if (!(error instanceof YieldseekerApiError)) return false;
3392
- const code = error.providerCode.toUpperCase();
3393
- return code.includes("USERNAME") && (code.includes("TAKEN") || code.includes("EXIST") || code.includes("UNAVAILABLE") || code.includes("IN_USE"));
3394
- }
3395
- var YIELDSEEKER_AGENT_WALLET_ABI = [
3396
- {
3397
- type: "function",
3398
- name: "withdrawAssetToUser",
3399
- stateMutability: "nonpayable",
3400
- inputs: [
3401
- { name: "recipient", type: "address" },
3402
- { name: "asset", type: "address" },
3403
- { name: "amount", type: "uint256" }
3404
- ],
3405
- outputs: []
3406
- },
3407
- {
3408
- type: "function",
3409
- name: "withdrawAllAssetToUser",
3410
- stateMutability: "nonpayable",
3411
- inputs: [
3412
- { name: "recipient", type: "address" },
3413
- { name: "asset", type: "address" }
3414
- ],
3415
- outputs: []
3416
- }
3417
- ];
3418
- function query(params) {
3419
- const search = new URLSearchParams();
3420
- for (const [key2, value] of Object.entries(params)) {
3421
- if (value !== void 0) search.set(key2, String(value));
3422
- }
3423
- const encoded = search.toString();
3424
- return encoded ? `?${encoded}` : "";
3425
- }
3426
- var YieldseekerAgent = class {
3427
- id = "yieldseeker";
3428
- balanceComposition = "tokens-plus-positions";
3429
- withdrawalRequiresWalletApproval = true;
3430
- supportedChainIds = [8453];
3431
- supportedAssets = [
3432
- {
3433
- chainId: 8453,
3434
- chain: "BASE",
3435
- assets: [
3436
- { symbol: "USDC", minDepositAmount: "10000000" },
3437
- { symbol: "WETH", minDepositAmount: "1" }
3438
- ]
3439
- }
3440
- ];
3441
- api;
3442
- auth;
3443
- rpcUrls;
3444
- receiptClient;
3445
- transactionExecutor;
3446
- unwindReceiptWaiter;
3447
- agentContexts = /* @__PURE__ */ new Map();
3448
- users = /* @__PURE__ */ new Map();
3449
- pendingAgents = /* @__PURE__ */ new Map();
3450
- pendingWalletContexts = /* @__PURE__ */ new Map();
3451
- readCache = /* @__PURE__ */ new Map();
3452
- pendingReads = /* @__PURE__ */ new Map();
3453
- readGeneration = 0;
3454
- portfolioVersions = /* @__PURE__ */ new Map();
3455
- snapshotFailures = /* @__PURE__ */ new Map();
3456
- standardReadFailures = /* @__PURE__ */ new Map();
3457
- reconcileUntil = /* @__PURE__ */ new Map();
3458
- activityRefreshUntil = /* @__PURE__ */ new Map();
3459
- // null means a confirmed movement has no reliable baseline. Do not guess
3460
- // settlement; keep slow reconciliation after the fast window expires.
3461
- snapshotMovements = /* @__PURE__ */ new Map();
3462
- movementEpochs = /* @__PURE__ */ new Map();
3463
- yieldOptions = /* @__PURE__ */ new Map();
3464
- pendingYieldOptions = /* @__PURE__ */ new Map();
3465
- constructor(owneyApiKey, options = {}) {
3466
- this.api = new YieldseekerApiClient(
3467
- owneyApiKey,
3468
- options.baseUrl ?? getYieldseekerProxyBaseUrl(),
3469
- options.fetchFn
3470
- );
3471
- this.auth = new YieldseekerAuth(options.auth);
3472
- this.rpcUrls = options.rpcUrls;
3473
- this.transactionExecutor = options.transactionExecutor;
3474
- this.unwindReceiptWaiter = options.unwindReceiptWaiter;
3475
- }
3476
- getReceiptClient() {
3477
- this.receiptClient ??= createPaidRpcClient(import_chains3.base, this.rpcUrls);
3478
- return this.receiptClient;
3479
- }
3480
- async disconnect() {
3481
- this.readGeneration += 1;
3482
- this.auth.clear();
3483
- for (const key2 of this.users.keys()) {
3484
- const [walletAddress, chainId] = key2.split(":");
3485
- clearYieldseekerIdentity(walletAddress, Number(chainId));
3486
- }
3487
- this.users.clear();
3488
- this.agentContexts.clear();
3489
- this.pendingAgents.clear();
3490
- this.pendingWalletContexts.clear();
3491
- this.readCache.clear();
3492
- this.pendingReads.clear();
3493
- this.portfolioVersions.clear();
3494
- this.snapshotFailures.clear();
3495
- this.standardReadFailures.clear();
3496
- this.reconcileUntil.clear();
3497
- this.activityRefreshUntil.clear();
3498
- this.snapshotMovements.clear();
3499
- this.movementEpochs.clear();
3500
- }
3501
- async activateAgent(state, chainId, asset) {
3502
- this.assertChain(chainId);
3503
- const targetAsset = asset ?? "USDC";
3504
- this.assertAsset(targetAsset);
3505
- await this.ensureAgent(state, chainId, targetAsset);
3506
- }
3507
- async deposit(state, chainId, amount, asset, depositCallback) {
3508
- this.assertChain(chainId);
3509
- this.assertAsset(asset);
3510
- if (BigInt(amount) <= 0n) {
3511
- throw new OwneyError(
3512
- "DEPOSIT_AMOUNT_BELOW_MINIMUM",
3513
- "Yieldseeker deposits must be greater than zero.",
3514
- { amount, minDepositAmount: "1" },
3515
- this.id
3516
- );
3517
- }
3518
- const context = await this.ensureAgent(state, chainId, asset);
3519
- const generation = this.readGeneration;
3520
- const movement = this.snapshotMovement(state, chainId, context, BigInt(amount));
3521
- let txHash;
3522
- if (depositCallback) {
3523
- provideDepositVerificationContext(depositCallback, {
3524
- agentId: "yieldseeker",
3525
- signature: await this.auth.getToken(state, chainId),
3526
- userId: context.user.userId,
3527
- yieldseekerAgentId: context.agent.agentId
3528
- });
3529
- txHash = await depositCallback(
3530
- context.wallet.walletAddress,
3531
- chainId,
3532
- amount
3533
- );
3534
- await this.waitForReceipt(state, chainId, txHash);
3535
- } else {
3536
- txHash = await this.submitTransaction(state, chainId, {
3537
- from: (0, import_viem7.getAddress)(state.walletAddress),
3538
- to: YIELDSEEKER_ASSET_METADATA[asset].address,
3539
- data: (0, import_viem7.encodeFunctionData)({
3540
- abi: import_viem7.erc20Abi,
3541
- functionName: "transfer",
3542
- args: [(0, import_viem7.getAddress)(context.wallet.walletAddress), BigInt(amount)]
3543
- }),
3544
- value: "0",
3545
- chainId
3546
- });
3547
- }
3548
- if (this.readGeneration === generation) {
3549
- await this.refreshSnapshotAfterMovement(state, chainId, context, "deposit", movement);
3550
- }
3551
- return {
3552
- txHash,
3553
- smartWallet: context.wallet.walletAddress,
3554
- amount
3555
- };
3556
- }
3557
- async withdraw(state, chainId, asset, amount) {
3558
- this.assertChain(chainId);
3559
- this.assertAsset(asset);
3560
- if (amount !== void 0 && BigInt(amount) <= 0n) {
3561
- throw new OwneyError(
3562
- "WITHDRAW_FAILED",
3563
- "Yieldseeker withdrawals must be greater than zero.",
3564
- { amount },
3565
- this.id
3566
- );
3567
- }
3568
- const context = await this.findAgent(state, chainId, asset);
3569
- if (!context) {
3570
- throw new OwneyError(
3571
- "WITHDRAW_INSUFFICIENT_BALANCE",
3572
- `No Yieldseeker ${asset} agent exists for this wallet.`,
3573
- { asset, available: "0" },
3574
- this.id
3575
- );
3576
- }
3577
- const generation = this.readGeneration;
3578
- let confirmedMovement = false;
3579
- let settlement = null;
3580
- try {
3581
- const portfolio = await this.loadPortfolioContext(
3582
- state,
3583
- chainId,
3584
- context
3585
- );
3586
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3587
- const idleEntry = Object.entries(portfolio.snapshot.tokenBalances).find(
3588
- ([address]) => address.toLowerCase() === metadata.address.toLowerCase()
3589
- );
3590
- const idle = BigInt(idleEntry?.[1] ?? "0");
3591
- const deployed = portfolio.positions.reduce(
3592
- (total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
3593
- 0n
3594
- );
3595
- const totalAvailable = idle + deployed;
3596
- const requested = amount === void 0 ? totalAvailable : BigInt(amount);
3597
- const plannedMovement = this.snapshotMovement(state, chainId, context, -requested);
3598
- if (requested > totalAvailable) {
3599
- throw new OwneyError(
3600
- "WITHDRAW_INSUFFICIENT_BALANCE",
3601
- `Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
3602
- {
3603
- asset,
3604
- requested: requested.toString(),
3605
- available: totalAvailable.toString()
3606
- },
3607
- this.id
3608
- );
3609
- }
3610
- let remaining = requested > idle ? requested - idle : 0n;
3611
- for (const position2 of portfolio.positions) {
3612
- if (remaining === 0n) break;
3613
- const available = BigInt(position2.withdrawableAssetsRaw);
3614
- if (available <= 0n) continue;
3615
- const assetsRaw = available < remaining ? available : remaining;
3616
- const response = await this.walletRequest(
3617
- state,
3618
- chainId,
3619
- this.agentPath(context, "withdraw-from-position"),
3620
- {
3621
- method: "POST",
3622
- body: {
3623
- chainId,
3624
- vaultAddress: position2.yieldOption.address,
3625
- assetsRaw: assetsRaw.toString()
3626
- }
3627
- }
3628
- );
3629
- if (!this.isTransactionHash(response?.transactionHash)) {
3630
- throw this.invalidResponse("position withdrawal");
3631
- }
3632
- await this.waitForReceipt(state, chainId, response.transactionHash);
3633
- confirmedMovement = true;
3634
- remaining -= assetsRaw;
3635
- }
3636
- if (remaining > 0n) {
3637
- throw this.invalidResponse("yield positions", {
3638
- reason: "Withdrawable positions could not cover the request.",
3639
- remaining: remaining.toString()
3640
- });
3641
- }
3642
- const account = (0, import_viem7.getAddress)(state.walletAddress);
3643
- const txHash = await this.submitTransaction(state, chainId, {
3644
- from: account,
3645
- to: (0, import_viem7.getAddress)(context.wallet.walletAddress),
3646
- data: amount === void 0 ? (0, import_viem7.encodeFunctionData)({
3647
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3648
- functionName: "withdrawAllAssetToUser",
3649
- args: [account, metadata.address]
3650
- }) : (0, import_viem7.encodeFunctionData)({
3651
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
3652
- functionName: "withdrawAssetToUser",
3653
- args: [account, metadata.address, requested]
3654
- }),
3655
- value: "0",
3656
- chainId
3657
- });
3658
- confirmedMovement = true;
3659
- settlement = plannedMovement;
3660
- return {
3661
- txHash,
3662
- type: amount === void 0 ? "full" : "partial",
3663
- amount: requested.toString()
3664
- };
3665
- } finally {
3666
- if (confirmedMovement && this.readGeneration === generation) {
3667
- await this.refreshSnapshotAfterMovement(
3668
- state,
3669
- chainId,
3670
- context,
3671
- "withdrawal",
3672
- settlement
3673
- );
3674
- }
3675
- }
3676
- }
3677
- async getBalances(state, chainId) {
3678
- this.assertChain(chainId);
3679
- return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, {}));
3680
- }
3681
- async getEarnings(state, chainId) {
3682
- this.assertChain(chainId);
3683
- return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
3684
- }
3685
- async getAccountApy(state, chainId, days, tokenSymbol) {
3686
- this.assertChain(chainId);
3687
- const asset = tokenSymbol?.toUpperCase();
3688
- if (asset !== void 0) this.assertAsset(asset);
3689
- const contexts = await this.loadPortfolio(state, chainId, {
3690
- ...asset ? { asset } : {},
3691
- historic: true
3692
- });
3693
- return mapYieldseekerApy(state.walletAddress, contexts, days);
3694
- }
3695
- async getHistory(state, chainId, options) {
3696
- this.assertChain(chainId);
3697
- const asset = options?.tokenSymbol?.toUpperCase();
3698
- if (asset !== void 0) this.assertAsset(asset);
3699
- const contexts = await this.loadPortfolio(state, chainId, {
3700
- ...asset ? { asset } : {},
3701
- historic: true,
3702
- actions: true
3703
- });
3704
- const catalog = await Promise.all(
3705
- [...new Set(contexts.map((context) => context.asset))].map(
3706
- (contextAsset) => this.loadYieldOptions(contextAsset)
3707
- )
3708
- );
3709
- const vaultAddresses = new Set(
3710
- catalog.flat().filter(
3711
- (yieldOption) => yieldOption.chainId === chainId && (0, import_viem7.isAddress)(yieldOption.address)
3712
- ).map((yieldOption) => yieldOption.address.toLowerCase())
3713
- );
3714
- return mapYieldseekerHistory(contexts, {
3715
- limit: options?.limit ?? 10,
3716
- ownerAddress: state.walletAddress,
3717
- vaultAddresses,
3718
- ...options?.fromDate ? { fromDate: options.fromDate } : {},
3719
- ...options?.toDate ? { toDate: options.toDate } : {}
3720
- });
3721
- }
3722
- async getUserProfile(state, chainId) {
3723
- this.assertChain(chainId);
3724
- return mapYieldseekerProfile(
3725
- state.walletAddress,
3726
- await this.loadPortfolio(state, chainId, {})
3727
- );
3728
- }
3729
- async getAgentApy(days, options) {
3730
- this.assertOptionalChain(options?.chainId);
3731
- const requested = options?.tokenSymbol?.toUpperCase();
3732
- if (requested !== void 0) this.assertAsset(requested);
3733
- const assets = requested ? [requested] : ["USDC", "WETH"];
3734
- const values = await Promise.all(
3735
- assets.map(async (asset) => {
3736
- return { asset, yieldOptions: await this.loadYieldOptions(asset) };
3737
- })
3738
- );
3739
- return mapYieldseekerAgentApy(values, days);
3740
- }
3741
- async loadYieldOptions(asset) {
3742
- const cached = this.yieldOptions.get(asset);
3743
- if (cached && cached.expiresAt > Date.now()) return cached.value;
3744
- const pending = this.pendingYieldOptions.get(asset);
3745
- if (pending) return pending;
3746
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3747
- const request = this.api.request(
3748
- `/chains/8453/assets/${metadata.address}/yield-options`
3749
- ).then((response) => {
3750
- if (!Array.isArray(response?.yieldOptions)) {
3751
- throw this.invalidResponse("yield options");
3752
- }
3753
- this.yieldOptions.set(asset, {
3754
- expiresAt: Date.now() + YIELDSEEKER_YIELD_OPTIONS_CACHE_MS,
3755
- value: response.yieldOptions
3756
- });
3757
- return response.yieldOptions;
3758
- }).finally(() => this.pendingYieldOptions.delete(asset));
3759
- this.pendingYieldOptions.set(asset, request);
3760
- return request;
3761
- }
3762
- userKey(state, chainId) {
3763
- return `${state.walletAddress.toLowerCase()}:${chainId}`;
3764
- }
3765
- contextKey(state, chainId, asset) {
3766
- return `${this.userKey(state, chainId)}:${asset}`;
3767
- }
3768
- assertSession(generation, chainId, asset) {
3769
- if (this.readGeneration !== generation) {
3770
- throw new OwneyError(
3771
- "NOT_CONNECTED",
3772
- "Wallet session changed during the Yieldseeker request.",
3773
- { rpcSource: "agent-api", chainId, ...asset ? { asset } : {} },
3774
- this.id
3775
- );
3776
- }
3777
- }
3778
- cachedRead(key2, ttlMs, read2) {
3779
- const cached = this.readCache.get(key2);
3780
- if (cached && cached.expiresAt > Date.now()) {
3781
- return Promise.resolve(cached.value);
3782
- }
3783
- const pending = this.pendingReads.get(key2);
3784
- if (pending) return pending;
3785
- const generation = this.readGeneration;
3786
- const request = Promise.resolve().then(read2).then((value) => {
3787
- if (this.readGeneration === generation && this.pendingReads.get(key2) === request) {
3788
- this.readCache.set(key2, {
3789
- expiresAt: Date.now() + ttlMs,
3790
- value
3791
- });
3792
- }
3793
- return value;
3794
- }).finally(() => {
3795
- if (this.pendingReads.get(key2) === request) {
3796
- this.pendingReads.delete(key2);
3797
- }
3798
- });
3799
- this.pendingReads.set(key2, request);
3800
- return request;
3801
- }
3802
- agentListKey(state, chainId) {
3803
- return `agents:${this.userKey(state, chainId)}`;
3804
- }
3805
- async listAgents(state, chainId, user) {
3806
- const response = await this.cachedRead(
3807
- this.agentListKey(state, chainId),
3808
- YIELDSEEKER_AGENT_LIST_CACHE_MS,
3809
- async () => {
3810
- const response2 = await this.walletRequest(
3811
- state,
3812
- chainId,
3813
- `/users/${user.userId}/agents`
3814
- );
3815
- if (!Array.isArray(response2?.agents)) {
3816
- throw this.invalidResponse("agent list");
3817
- }
3818
- return response2;
3819
- }
3820
- );
3821
- return response.agents;
3822
- }
3823
- async contextForAgent(state, chainId, user, agent, asset) {
3824
- const key2 = this.contextKey(state, chainId, asset);
3825
- const cached = this.agentContexts.get(key2);
3826
- if (cached?.agent.agentId === agent.agentId) return cached;
3827
- const pending = this.pendingWalletContexts.get(key2);
3828
- if (pending) return pending;
3829
- const generation = this.readGeneration;
3830
- const request = this.walletRequest(
3831
- state,
3832
- chainId,
3833
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3834
- ).then((walletResponse) => {
3835
- this.assertSession(generation, chainId, asset);
3836
- if (!walletResponse?.agentWallet || !(0, import_viem7.isAddress)(walletResponse.agentWallet.walletAddress)) {
3837
- throw this.invalidResponse("agent wallet");
3838
- }
3839
- const context = {
3840
- user,
3841
- agent,
3842
- wallet: walletResponse.agentWallet,
3843
- asset
3844
- };
3845
- this.agentContexts.set(key2, context);
3846
- return context;
3847
- });
3848
- this.pendingWalletContexts.set(key2, request);
3849
- try {
3850
- return await request;
3851
- } finally {
3852
- if (this.pendingWalletContexts.get(key2) === request) {
3853
- this.pendingWalletContexts.delete(key2);
3854
- }
3855
- }
3856
- }
3857
- async resolveUser(state, chainId) {
3858
- const key2 = this.userKey(state, chainId);
3859
- const inMemory = this.users.get(key2);
3860
- if (inMemory) return inMemory;
3861
- const persisted = readYieldseekerIdentity(state.walletAddress, chainId);
3862
- if (persisted) {
3863
- this.users.set(key2, persisted);
3864
- return persisted;
3865
- }
3866
- const walletAddress = (0, import_viem7.getAddress)(state.walletAddress);
3867
- const generation = this.readGeneration;
3868
- let user = null;
3869
- try {
3870
- const login = await this.providerRequest(
3871
- state,
3872
- chainId,
3873
- "/users/login-with-wallet",
3874
- { method: "POST", body: { walletAddress } }
3875
- );
3876
- user = login?.user ?? null;
3877
- if (!user) {
3878
- throw this.invalidResponse("wallet login", {
3879
- reason: "A successful login returned no user."
3880
- });
3881
- }
3882
- } catch (error) {
3883
- if (!(error instanceof YieldseekerApiError) || error.providerCode !== "NO_USER") {
3884
- if (error instanceof OwneyError) throw error;
3885
- throw this.mapApiError(error);
3886
- }
3887
- let created;
3888
- for (let attempt = 0; attempt < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS; attempt += 1) {
3889
- try {
3890
- created = await this.providerRequest(
3891
- state,
3892
- chainId,
3893
- "/users",
3894
- {
3895
- method: "POST",
3896
- body: {
3897
- walletAddress,
3898
- username: generateYieldseekerUsername()
3899
- }
3900
- }
3901
- );
3902
- break;
3903
- } catch (createError) {
3904
- const canRetry = isUsernameConflict(createError) && attempt + 1 < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS;
3905
- if (canRetry) continue;
3906
- throw this.mapApiError(createError);
3907
- }
3908
- }
3909
- user = created?.user ?? null;
3910
- }
3911
- if (!user || !/^[a-zA-Z0-9_-]{1,128}$/.test(user.userId)) {
3912
- throw this.invalidResponse("wallet identity");
3913
- }
3914
- this.assertSession(generation, chainId);
3915
- const resolved = { userId: user.userId };
3916
- this.users.set(key2, resolved);
3917
- writeYieldseekerIdentity(state.walletAddress, chainId, resolved.userId);
3918
- return resolved;
3919
- }
3920
- forgetUser(state, chainId) {
3921
- this.users.delete(this.userKey(state, chainId));
3922
- clearYieldseekerIdentity(state.walletAddress, chainId);
3923
- }
3924
- async ensureAgent(state, chainId, asset) {
3925
- const key2 = this.contextKey(state, chainId, asset);
3926
- const cached = this.agentContexts.get(key2);
3927
- if (cached) return cached;
3928
- const pending = this.pendingAgents.get(key2);
3929
- if (pending) return pending;
3930
- const generation = this.readGeneration;
3931
- const request = this.resolveAgent(state, chainId, asset, true).then(
3932
- async (context) => {
3933
- this.assertSession(generation, chainId, asset);
3934
- if (!context) throw this.invalidResponse("agent creation");
3935
- await this.deployAgent(state, chainId, context);
3936
- this.assertSession(generation, chainId, asset);
3937
- this.agentContexts.set(key2, context);
3938
- return context;
3939
- }
3940
- );
3941
- this.pendingAgents.set(key2, request);
3942
- try {
3943
- return await request;
3944
- } finally {
3945
- if (this.pendingAgents.get(key2) === request) this.pendingAgents.delete(key2);
3946
- }
3947
- }
3948
- async findAgent(state, chainId, asset) {
3949
- const key2 = this.contextKey(state, chainId, asset);
3950
- const cached = this.agentContexts.get(key2);
3951
- if (cached) return cached;
3952
- const generation = this.readGeneration;
3953
- const context = await this.resolveAgent(state, chainId, asset, false);
3954
- this.assertSession(generation, chainId, asset);
3955
- if (context) this.agentContexts.set(key2, context);
3956
- return context;
3957
- }
3958
- async resolveAgent(state, chainId, asset, createIfMissing) {
3959
- const generation = this.readGeneration;
3960
- const user = await this.resolveUser(state, chainId);
3961
- this.assertSession(generation, chainId, asset);
3962
- const agents = await this.listAgents(state, chainId, user);
3963
- this.assertSession(generation, chainId, asset);
3964
- const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3965
- let agent = agents.find(
3966
- (candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
3967
- );
3968
- if (!agent && createIfMissing) {
3969
- const created = await this.walletRequest(
3970
- state,
3971
- chainId,
3972
- `/users/${user.userId}/agents`,
3973
- {
3974
- method: "POST",
3975
- body: {
3976
- name: OWNEY_AGENT_NAME,
3977
- emoji: "\u{1F989}",
3978
- chainId,
3979
- assetAddress: metadata.address,
3980
- type: "vault",
3981
- rulePreset: null
3982
- }
3983
- }
3984
- );
3985
- this.assertSession(generation, chainId, asset);
3986
- agent = created?.agent;
3987
- if (agent) {
3988
- this.readCache.set(this.agentListKey(state, chainId), {
3989
- expiresAt: Date.now() + YIELDSEEKER_AGENT_LIST_CACHE_MS,
3990
- value: {
3991
- agents: [...agents, agent]
3992
- }
3993
- });
3994
- }
3995
- }
3996
- if (!agent) return null;
3997
- this.assertAgent(agent);
3998
- return this.contextForAgent(state, chainId, user, agent, asset);
3999
- }
4000
- async loadPortfolio(state, chainId, options) {
4001
- const generation = this.readGeneration;
4002
- const user = await this.resolveUser(state, chainId);
4003
- this.assertSession(generation, chainId);
4004
- const agents = await this.listAgents(state, chainId, user);
4005
- this.assertSession(generation, chainId);
4006
- const contexts = [];
4007
- for (const agent of agents) {
4008
- const asset = this.assetForAgent(agent);
4009
- if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
4010
- continue;
4011
- }
4012
- this.assertAgent(agent);
4013
- contexts.push(this.contextForAgent(state, chainId, user, agent, asset));
4014
- }
4015
- const resolvedContexts = await Promise.all(contexts);
4016
- this.assertSession(generation, chainId);
4017
- return Promise.all(
4018
- resolvedContexts.map(
4019
- (context) => this.loadPortfolioContext(state, chainId, context, options)
4020
- )
4021
- );
4022
- }
4023
- portfolioVersion(contextKey) {
4024
- return this.portfolioVersions.get(contextKey) ?? 0;
4025
- }
4026
- portfolioCacheMs(contextKey) {
4027
- return (this.reconcileUntil.get(contextKey) ?? 0) > Date.now() ? YIELDSEEKER_SETTLEMENT_CACHE_MS : YIELDSEEKER_PORTFOLIO_CACHE_MS;
4028
- }
4029
- snapshotMovement(state, chainId, context, delta) {
4030
- const key2 = this.contextKey(state, chainId, context.asset);
4031
- const previous = this.snapshotMovements.get(key2);
4032
- if (this.snapshotMovements.has(key2)) {
4033
- if (!previous || previous.delta > 0n !== delta > 0n) return null;
4034
- return {
4035
- ...previous,
4036
- epoch: this.movementEpochs.get(key2) ?? 0,
4037
- delta: previous.delta + delta,
4038
- expectedBalance: previous.expectedBalance + delta,
4039
- expectedNetDeposits: previous.expectedNetDeposits + delta
4040
- };
4041
- }
4042
- const cached = this.readCache.get(`snapshot:${key2}`);
4043
- if (!cached || cached.expiresAt <= Date.now()) return null;
4044
- const snapshot = cached.value.agentSnapshot;
4045
- if (snapshot.baseAssetDecimals !== YIELDSEEKER_ASSET_METADATA[context.asset].decimals) return null;
4046
- if (!/^-?\d+$/.test(snapshot.netDepositsBase) || !/^\d+$/.test(snapshot.totalValueBase)) return null;
4047
- return {
4048
- epoch: this.movementEpochs.get(key2) ?? 0,
4049
- delta,
4050
- decimals: snapshot.baseAssetDecimals,
4051
- expectedBalance: BigInt(snapshot.totalValueBase) + delta,
4052
- expectedNetDeposits: BigInt(snapshot.netDepositsBase) + delta
4053
- };
4054
- }
4055
- advancePortfolioVersion(contextKey) {
4056
- const version = this.portfolioVersion(contextKey) + 1;
4057
- this.portfolioVersions.set(contextKey, version);
4058
- this.snapshotFailures.delete(contextKey);
4059
- for (const kind of ["snapshot", "positions", "historic", "actions"]) {
4060
- const key2 = `${kind}:${contextKey}`;
4061
- this.readCache.delete(key2);
4062
- this.pendingReads.delete(key2);
4063
- }
4064
- return version;
4065
- }
4066
- requestPortfolioSnapshot(state, chainId, context, contextKey, version, generation, forceRefresh = false) {
4067
- return this.walletRequest(
4068
- state,
4069
- chainId,
4070
- `${this.agentPath(context, "snapshot")}${query(forceRefresh ? { shouldForceRefresh: true } : { shouldOnlyUseRecentValue: true, shouldAllowStaleOnError: true })}`
4071
- ).then((response) => {
4072
- if (!response?.agentSnapshot) {
4073
- throw this.invalidResponse("agent snapshot");
4074
- }
4075
- if (this.readGeneration === generation && this.portfolioVersion(contextKey) === version) {
4076
- this.snapshotFailures.delete(contextKey);
4077
- const movement = this.snapshotMovements.get(contextKey);
4078
- const snapshot = response.agentSnapshot;
4079
- if (movement && snapshot.baseAssetDecimals === movement.decimals && /^-?\d+$/.test(snapshot.netDepositsBase) && /^\d+$/.test(snapshot.totalValueBase)) {
4080
- const balance = BigInt(snapshot.totalValueBase);
4081
- const netDeposits = BigInt(snapshot.netDepositsBase);
4082
- const reconciled = movement.delta > 0n ? balance >= movement.expectedBalance && netDeposits >= movement.expectedNetDeposits : balance <= movement.expectedBalance && netDeposits <= movement.expectedNetDeposits;
4083
- if (reconciled) {
4084
- this.snapshotMovements.delete(contextKey);
4085
- this.reconcileUntil.delete(contextKey);
4086
- }
4087
- }
4088
- }
4089
- return response;
4090
- }).catch((error) => {
4091
- if (this.readGeneration === generation && this.portfolioVersion(contextKey) === version) {
4092
- this.snapshotFailures.set(contextKey, {
4093
- retryAt: Date.now() + Math.max(YIELDSEEKER_READ_FAILURE_COOLDOWN_MS, rateLimitDelay(error) ?? 0),
4094
- error
4095
- });
4096
- }
4097
- throw error;
4098
- });
4099
- }
4100
- portfolioSnapshot(state, chainId, context, contextKey) {
4101
- const key2 = `snapshot:${contextKey}`;
4102
- const cached = this.readCache.get(key2);
4103
- if ((!cached || cached.expiresAt <= Date.now()) && !this.pendingReads.has(key2)) {
4104
- const failure = this.snapshotFailures.get(contextKey);
4105
- if (failure && failure.retryAt > Date.now()) throw failure.error;
4106
- this.advancePortfolioVersion(contextKey);
4107
- }
4108
- const version = this.portfolioVersion(contextKey);
4109
- const generation = this.readGeneration;
4110
- return {
4111
- version,
4112
- read: this.cachedRead(key2, this.portfolioCacheMs(contextKey), () => (
4113
- // Only event-driven reconciliation forces refreshes. Routine reads
4114
- // remain non-forced; the cache and shared cooldown still bound calls.
4115
- this.requestPortfolioSnapshot(
4116
- state,
4117
- chainId,
4118
- context,
4119
- contextKey,
4120
- version,
4121
- generation,
4122
- this.snapshotMovements.has(contextKey)
4123
- )
4124
- ))
4125
- };
4126
- }
4127
- async loadPortfolioContext(state, chainId, context, options = {}) {
4128
- const contextKey = this.contextKey(state, chainId, context.asset);
4129
- const generation = this.readGeneration;
4130
- const assertSession = () => this.assertSession(generation, chainId, context.asset);
4131
- for (let attempt = 0; attempt < 2; attempt++) {
4132
- const { version, read: read2 } = this.portfolioSnapshot(state, chainId, context, contextKey);
4133
- try {
4134
- const snapshot = await read2;
4135
- assertSession();
4136
- if (this.portfolioVersion(contextKey) !== version) continue;
4137
- const [positions, historic, actions] = await Promise.all([
4138
- this.cachedRead(
4139
- `positions:${contextKey}`,
4140
- this.portfolioCacheMs(contextKey),
4141
- async () => {
4142
- const response = await this.walletRequest(
4143
- state,
4144
- chainId,
4145
- this.agentPath(context, "yield-positions")
4146
- );
4147
- if (!Array.isArray(response?.yieldPositions)) {
4148
- throw this.invalidResponse("yield positions");
4149
- }
4150
- return response;
4151
- }
4152
- ),
4153
- options.historic ? this.cachedRead(
4154
- `historic:${contextKey}`,
4155
- (this.activityRefreshUntil.get(contextKey) ?? 0) > Date.now() ? YIELDSEEKER_SETTLEMENT_ACTIVITY_CACHE_MS : YIELDSEEKER_ACTIVITY_CACHE_MS,
4156
- () => this.walletRequest(
4157
- state,
4158
- chainId,
4159
- this.agentPath(context, "wallet/historic-position")
4160
- )
4161
- ) : Promise.resolve(void 0),
4162
- options.actions ? this.cachedRead(
4163
- `actions:${contextKey}`,
4164
- (this.activityRefreshUntil.get(contextKey) ?? 0) > Date.now() ? YIELDSEEKER_SETTLEMENT_ACTIVITY_CACHE_MS : YIELDSEEKER_ACTIVITY_CACHE_MS,
4165
- () => this.walletRequest(
4166
- state,
4167
- chainId,
4168
- this.agentPath(context, "actions")
4169
- )
4170
- ) : Promise.resolve(void 0)
4171
- ]);
4172
- assertSession();
4173
- if (this.portfolioVersion(contextKey) !== version) continue;
4174
- if (!Array.isArray(positions?.yieldPositions)) {
4175
- throw this.invalidResponse("yield positions");
4176
- }
4177
- return {
4178
- ...context,
4179
- snapshot: snapshot.agentSnapshot,
4180
- positions: positions.yieldPositions,
4181
- ...historic?.position ? { historic: historic.position } : {},
4182
- ...actions?.actions ? { actions: actions.actions } : {}
4183
- };
4184
- } catch (error) {
4185
- assertSession();
4186
- if (this.portfolioVersion(contextKey) !== version) continue;
4187
- throw error;
4188
- }
4189
- }
4190
- throw new OwneyError(
4191
- "AGENT_API_ERROR",
4192
- "Yieldseeker portfolio changed during the read. Please retry.",
4193
- { rpcSource: "agent-api", chainId, asset: context.asset },
4194
- this.id
4195
- );
4196
- }
4197
- async deployAgent(state, chainId, context) {
4198
- if (context.wallet.initializedDate != null) return;
4199
- const walletAddress = context.wallet.walletAddress.toLowerCase();
4200
- const deployed = await this.walletRequest(
4201
- state,
4202
- chainId,
4203
- this.agentPath(context, "deploy"),
4204
- { method: "POST", body: {} }
4205
- );
4206
- if (!deployed?.agentWallet || !(0, import_viem7.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
4207
- throw this.invalidResponse("agent deployment", {
4208
- reason: "Deploy did not return the expected Agent Wallet."
4209
- });
4210
- }
4211
- context.wallet = deployed.agentWallet;
4212
- }
4213
- async refreshSnapshotAfterMovement(state, chainId, context, movement, settlement) {
4214
- const contextKey = this.contextKey(state, chainId, context.asset);
4215
- this.reconcileUntil.set(contextKey, Date.now() + YIELDSEEKER_SETTLEMENT_WINDOW_MS);
4216
- this.activityRefreshUntil.set(contextKey, Date.now() + YIELDSEEKER_SETTLEMENT_WINDOW_MS);
4217
- const epoch = this.movementEpochs.get(contextKey) ?? 0;
4218
- this.snapshotMovements.set(contextKey, settlement?.epoch === epoch ? settlement : null);
4219
- this.movementEpochs.set(contextKey, epoch + 1);
4220
- const version = this.advancePortfolioVersion(contextKey);
4221
- const generation = this.readGeneration;
4222
- try {
4223
- await this.cachedRead(
4224
- `snapshot:${contextKey}`,
4225
- YIELDSEEKER_SETTLEMENT_CACHE_MS,
4226
- () => this.requestPortfolioSnapshot(state, chainId, context, contextKey, version, generation, true)
4227
- );
4228
- } catch (error) {
4229
- console.warn(
4230
- `[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
4231
- error
4232
- );
4233
- }
4234
- }
4235
- agentPath(context, suffix) {
4236
- return `/users/${context.user.userId}/agents/${context.agent.agentId}/${suffix}`;
4237
- }
4238
- async walletRequest(state, chainId, path, options = {}) {
4239
- const read2 = (options.method ?? "GET") === "GET";
4240
- const userKey = this.userKey(state, chainId);
4241
- if (read2) {
4242
- const failure = this.standardReadFailures.get(userKey);
4243
- if (failure && failure.retryAt > Date.now()) throw failure.error;
4244
- if (failure) this.standardReadFailures.delete(userKey);
4245
- }
4246
- const generation = this.readGeneration;
4247
- try {
4248
- return await this.providerRequest(state, chainId, path, options);
4249
- } catch (error) {
4250
- const mapped = this.mapApiError(error);
4251
- const delay = read2 ? rateLimitDelay(mapped) : void 0;
4252
- if (delay !== void 0 && this.readGeneration === generation) {
4253
- this.standardReadFailures.set(userKey, {
4254
- retryAt: Date.now() + Math.max(YIELDSEEKER_READ_FAILURE_COOLDOWN_MS, delay),
4255
- error: mapped
4256
- });
4257
- }
4258
- throw mapped;
4259
- }
4260
- }
4261
- async providerRequest(state, chainId, path, options = {}) {
4262
- this.assertChain(chainId);
4263
- const request = (signature2) => this.api.request(path, {
4264
- ...options,
4265
- signature: signature2
4266
- });
4267
- let signature = await this.auth.getToken(state, chainId);
4268
- try {
4269
- return await request(signature);
4270
- } catch (error) {
4271
- if (!(error instanceof YieldseekerApiError)) throw error;
4272
- if (error.providerCode === "NO_USER") throw error;
4273
- if (!error.isAuthenticationError) throw error;
4274
- signature = await this.auth.refreshToken(state, chainId, signature);
4275
- try {
4276
- return await request(signature);
4277
- } catch (retryError) {
4278
- if (retryError instanceof YieldseekerApiError && retryError.isAuthenticationError) {
4279
- this.forgetUser(state, chainId);
4280
- }
4281
- throw retryError;
4282
- }
4283
- }
4284
- }
4285
- mapApiError(error) {
4286
- if (!(error instanceof YieldseekerApiError)) {
4287
- return new OwneyError(
4288
- "AGENT_API_ERROR",
4289
- "Yieldseeker request failed.",
4290
- { cause: error instanceof Error ? error.message : String(error) },
4291
- this.id
4292
- );
4293
- }
4294
- const code = error.isAuthenticationError ? "AGENT_AUTH_FAILED" : error.providerCode === "REQUEST_TIMEOUT" ? "AGENT_TIMEOUT" : "AGENT_API_ERROR";
4295
- return new OwneyError(
4296
- code,
4297
- `Yieldseeker request failed: ${error.providerCode}.`,
4298
- {
4299
- rpcSource: "agent-api",
4300
- statusCode: error.status,
4301
- providerCode: error.providerCode,
4302
- ...error.responseFields ? { fields: error.responseFields } : {}
4303
- },
4304
- this.id
4305
- );
4306
- }
4307
- async submitTransaction(state, chainId, transaction) {
4308
- if (this.transactionExecutor) {
4309
- return this.transactionExecutor(state, chainId, transaction);
4310
- }
4311
- this.assertTransaction(transaction, state, chainId);
4312
- const account = (0, import_viem7.getAddress)(state.walletAddress);
4313
- const walletClient = (0, import_viem7.createWalletClient)({
4314
- account,
4315
- chain: import_chains3.base,
4316
- transport: (0, import_viem7.custom)(state.provider)
4317
- });
4318
- const walletChainClient = (0, import_viem7.createPublicClient)({
4319
- chain: import_chains3.base,
4320
- transport: (0, import_viem7.custom)(state.provider)
4321
- });
4322
- await ensureWalletOnChain(
4323
- walletChainClient,
4324
- walletClient,
4325
- 8453
4326
- );
4327
- const hash = await walletClient.sendTransaction({
4328
- account,
4329
- chain: import_chains3.base,
4330
- to: (0, import_viem7.getAddress)(transaction.to),
4331
- data: transaction.data,
4332
- value: BigInt(transaction.value)
4333
- });
4334
- const receipt = await withPaidRpcDiagnostics(
4335
- () => this.getReceiptClient().waitForTransactionReceipt({
4336
- hash,
4337
- confirmations: 1
4338
- }),
4339
- 8453,
4340
- "eth_getTransactionReceipt",
4341
- this.id
4342
- );
4343
- if (receipt.status !== "success") {
4344
- throw new OwneyError(
4345
- "AGENT_TRANSACTION_REVERTED",
4346
- `Yieldseeker transaction reverted (${hash}).`,
4347
- { transactionHash: hash },
4348
- this.id
4349
- );
4350
- }
4351
- return hash;
4352
- }
4353
- async waitForReceipt(state, chainId, transactionHash) {
4354
- if (this.unwindReceiptWaiter) {
4355
- await this.unwindReceiptWaiter(state, chainId, transactionHash);
4356
- return;
4357
- }
4358
- const receipt = await withPaidRpcDiagnostics(
4359
- () => this.getReceiptClient().waitForTransactionReceipt({
4360
- hash: transactionHash,
4361
- confirmations: 1
4362
- }),
4363
- 8453,
4364
- "eth_getTransactionReceipt",
4365
- this.id
4366
- );
4367
- if (receipt.status !== "success") {
4368
- throw new OwneyError(
4369
- "AGENT_TRANSACTION_REVERTED",
4370
- `Yieldseeker transaction reverted (${transactionHash}).`,
4371
- { transactionHash },
4372
- this.id
4373
- );
4374
- }
4375
- }
4376
- assertTransaction(transaction, state, chainId) {
4377
- if (!transaction || typeof transaction.from !== "string" || !(0, import_viem7.isAddress)(transaction.from) || typeof transaction.to !== "string" || !(0, import_viem7.isAddress)(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 || (0, import_viem7.getAddress)(transaction.from) !== (0, import_viem7.getAddress)(state.walletAddress)) {
4378
- throw this.invalidResponse("transaction");
4379
- }
4380
- }
4381
- assertAgent(agent) {
4382
- if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem7.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
4383
- throw this.invalidResponse("agent");
4384
- }
4385
- }
4386
- isOwneyAgent(agent) {
4387
- return typeof agent.name === "string" && agent.name.trim().toLowerCase() === OWNEY_AGENT_NAME;
4388
- }
4389
- assetForAgent(agent) {
4390
- for (const asset of ["USDC", "WETH"]) {
4391
- if (agent.assetAddress.toLowerCase() === YIELDSEEKER_ASSET_METADATA[asset].address.toLowerCase()) {
4392
- return asset;
4393
- }
4394
- }
4395
- return null;
4396
- }
4397
- isTransactionHash(value) {
4398
- return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
4399
- }
4400
- assertChain(chainId) {
4401
- if (chainId !== 8453) {
4402
- throw new OwneyError(
4403
- "CHAIN_UNSUPPORTED",
4404
- `Yieldseeker does not support chain ${chainId}.`,
4405
- { chainId, supportedChainIds: [8453] },
4406
- this.id
4407
- );
4408
- }
4409
- }
4410
- assertOptionalChain(chainId) {
4411
- if (chainId !== void 0) this.assertChain(chainId);
4412
- }
4413
- assertAsset(asset) {
4414
- if (asset !== "USDC" && asset !== "WETH") {
4415
- throw new OwneyError(
4416
- "ASSET_UNSUPPORTED",
4417
- `Yieldseeker does not support asset ${asset} in the Owney rollout.`,
4418
- {
4419
- asset,
4420
- supportedAssets: ["USDC", "WETH"],
4421
- providerAlsoAdvertises: ["cbBTC"]
4422
- },
4423
- this.id
4424
- );
4425
- }
4426
- }
4427
- invalidResponse(operation, details = {}) {
4428
- return new OwneyError(
4429
- "AGENT_INVALID_RESPONSE",
4430
- `Yieldseeker returned an invalid ${operation} response.`,
4431
- details,
4432
- this.id
4433
- );
4434
- }
4435
- };
4436
-
4437
- // src/lib/routing-api.ts
4438
- var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
4439
- async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
4440
- const url = `${baseUrl}/api/v1/agent/org-config`;
4441
- try {
4442
- const res = await fetch(url, {
4443
- method: "GET",
4444
- headers: {
4445
- "Content-Type": "application/json",
4446
- "x-owney-api-key": `${apiKey}`
4447
- }
4448
- });
4449
- if (!res.ok) {
4450
- if (res.status !== 404) {
4451
- console.warn(
4452
- `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
4453
- );
4454
- }
4455
- return null;
4456
- }
4457
- const json = await res.json();
4458
- const policy = json.success ? json.data ?? null : null;
4459
- debugLog(
4460
- "owney-sdk",
4461
- policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
4462
- policy ?? void 0
4463
- );
4464
- return policy;
4465
- } catch (error) {
4466
- console.warn(
4467
- "[owney-sdk] Could not read org agent config (non-fatal):",
4468
- error instanceof Error ? error.message : String(error)
4469
- );
4470
- return null;
4471
- }
4472
- }
4473
- async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
4474
- const url = `${baseUrl}/api/v1/agent/keys`;
4475
- const res = await fetch(url, {
4476
- method: "GET",
4477
- headers: {
4478
- "Content-Type": "application/json",
4479
- "x-owney-api-key": `${apiKey}`
4480
- }
4481
- });
4482
- if (!res.ok) {
4483
- const text = await res.text().catch(() => "");
4484
- throw new OwneyError(
4485
- "API_ROUTING_ERROR",
4486
- `Routing API error ${res.status}: ${text}`,
4487
- { statusCode: res.status, responseBody: text }
4488
- );
4489
- }
4490
- const json = await res.json();
4491
- if (!json.success) {
4492
- throw new OwneyError(
4493
- "API_ROUTING_FAILED",
4494
- `Routing API request failed: ${json.message}`,
4495
- { message: json.message }
4496
- );
4497
- }
4498
- return json.data;
4499
- }
4500
-
4501
- // src/lib/health-report.ts
4502
- var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
4503
- async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL3) {
4504
- try {
4505
- await fetch(`${baseUrl}/api/v1/agent/health-report`, {
4506
- method: "POST",
4507
- headers: {
4508
- "Content-Type": "application/json",
4509
- "x-owney-api-key": apiKey
4510
- },
4511
- body: JSON.stringify({
4512
- agent_type: agentType,
4513
- error_code: errorCode,
4514
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
4515
- })
4516
- });
4517
- } catch (err) {
4518
- console.warn(
4519
- `[owney-sdk] health-report failed for agent "${agentType}":`,
4520
- err instanceof Error ? err.message : err
4521
- );
4522
- }
4523
- }
4524
- async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
4525
- try {
4526
- return await fn();
4527
- } catch (err) {
4528
- const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
4529
- void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
4530
- throw err;
2226
+ return await fn();
2227
+ } catch (err) {
2228
+ const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
2229
+ void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
2230
+ throw err;
4531
2231
  }
4532
2232
  }
4533
2233
 
4534
2234
  // src/lib/helpers/withdraw-helper.ts
4535
- var import_viem8 = require("viem");
2235
+ var import_viem2 = require("viem");
4536
2236
  function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
4537
2237
  const target = asset.toUpperCase();
4538
2238
  return agents.map((agent) => {
@@ -4540,29 +2240,8 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
4540
2240
  const tokenBalance = agentBalance?.tokens.find(
4541
2241
  (t) => t.chainId === chainId && t.asset.toUpperCase() === target
4542
2242
  );
4543
- let balance = tokenBalance ? (0, import_viem8.parseUnits)(tokenBalance.amount, decimals) : 0n;
4544
- if (agent.balanceComposition === "tokens-plus-positions") {
4545
- const chainNameById = {
4546
- 1: "ETHEREUM",
4547
- 8453: "BASE",
4548
- 42161: "ARBITRUM"
4549
- };
4550
- const targetChain = chainNameById[chainId];
4551
- for (const position2 of agentBalance?.positions ?? []) {
4552
- const positionChain = position2.chain.trim().toUpperCase();
4553
- const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
4554
- if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
4555
- balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : (0, import_viem8.parseUnits)(position2.amount, decimals);
4556
- }
4557
- }
4558
- const assetTotal = agentBalance?.assetBalances?.find(
4559
- (t) => t.chainId === chainId && t.asset.toUpperCase() === target
4560
- );
4561
- if (assetTotal) {
4562
- const total = (0, import_viem8.parseUnits)(assetTotal.amount, decimals);
4563
- if (total < balance) balance = total > 0n ? total : 0n;
4564
- }
4565
- return { agent, balance };
2243
+ if (!tokenBalance) return { agent, balance: 0n };
2244
+ return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
4566
2245
  });
4567
2246
  }
4568
2247
  function planProportionalShares(balances, requested, totalAvailable) {
@@ -4588,9 +2267,7 @@ function planProportionalShares(balances, requested, totalAvailable) {
4588
2267
  return plans;
4589
2268
  }
4590
2269
  function planDisabledDrain(disabled, requested) {
4591
- const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
4592
- (a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
4593
- );
2270
+ const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
4594
2271
  const plans = [];
4595
2272
  let remaining = requested;
4596
2273
  for (const { agent, balance } of sorted) {
@@ -4641,13 +2318,6 @@ function balanceForApyScope(balance, chainId, tokenSymbol) {
4641
2318
  return Number.isFinite(total) && total > 0 ? total : 0;
4642
2319
  }
4643
2320
  const normalizedToken = tokenSymbol.toUpperCase();
4644
- const snapshots = balance.assetBalances?.filter(
4645
- (token) => Number(token.chainId) === chainId && String(token.asset).toUpperCase() === normalizedToken
4646
- );
4647
- if (snapshots?.length) {
4648
- const amount = snapshots.reduce((sum, token) => sum + Number(token.amount), 0);
4649
- if (Number.isFinite(amount)) return Math.max(0, amount);
4650
- }
4651
2321
  return balance.tokens.reduce((total, token) => {
4652
2322
  if (Number(token.chainId) !== chainId || String(token.asset).toUpperCase() !== normalizedToken) {
4653
2323
  return total;
@@ -4718,379 +2388,438 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
4718
2388
  }
4719
2389
 
4720
2390
  // src/client.ts
4721
- var import_viem12 = require("viem");
4722
- var import_chains4 = require("viem/chains");
4723
-
4724
- // src/lib/sponsored-token-batch.ts
4725
- var import_viem10 = require("viem");
2391
+ var import_viem6 = require("viem");
2392
+ var import_chains2 = require("viem/chains");
4726
2393
 
4727
- // src/lib/permit2-batch.ts
4728
- var import_viem9 = require("viem");
4729
- var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
4730
- var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
4731
- var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
4732
- var ERC2612_PERMIT_TYPES = {
4733
- Permit: [
4734
- { name: "owner", type: "address" },
4735
- { name: "spender", type: "address" },
4736
- { name: "value", type: "uint256" },
4737
- { name: "nonce", type: "uint256" },
4738
- { name: "deadline", type: "uint256" }
4739
- ]
4740
- };
4741
- var ERC2612_READ_ABI = (0, import_viem9.parseAbi)([
4742
- "function name() view returns (string)",
4743
- "function version() view returns (string)",
4744
- "function nonces(address owner) view returns (uint256)"
4745
- ]);
4746
- function erc2612TypedData(input) {
2394
+ // src/lib/transfer-auth.ts
2395
+ var import_viem3 = require("viem");
2396
+ var ERC20_META_ABI = [
2397
+ { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
2398
+ { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
2399
+ ];
2400
+ function buildTransferWithAuthorizationTypedData(input) {
4747
2401
  return {
4748
- domain: {
4749
- name: input.permit.tokenName,
4750
- version: input.permit.tokenVersion,
4751
- chainId: input.chainId,
4752
- verifyingContract: input.token
2402
+ domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
2403
+ types: {
2404
+ TransferWithAuthorization: [
2405
+ { name: "from", type: "address" },
2406
+ { name: "to", type: "address" },
2407
+ { name: "value", type: "uint256" },
2408
+ { name: "validAfter", type: "uint256" },
2409
+ { name: "validBefore", type: "uint256" },
2410
+ { name: "nonce", type: "bytes32" }
2411
+ ]
4753
2412
  },
4754
- types: ERC2612_PERMIT_TYPES,
4755
- primaryType: "Permit",
4756
- message: {
4757
- owner: input.owner,
4758
- spender: BATCH_PERMIT2_ADDRESS,
4759
- value: BigInt(input.permit.value),
4760
- nonce: BigInt(input.permit.nonce),
4761
- deadline: BigInt(input.permit.deadline)
4762
- }
2413
+ primaryType: "TransferWithAuthorization",
2414
+ message: input.message
4763
2415
  };
4764
2416
  }
4765
- var PERMIT_BATCH_TYPES = {
4766
- PermitBatchWitnessTransferFrom: [
4767
- { name: "permitted", type: "TokenPermissions[]" },
4768
- { name: "spender", type: "address" },
4769
- { name: "nonce", type: "uint256" },
4770
- { name: "deadline", type: "uint256" },
4771
- { name: "witness", type: "Deposit" }
4772
- ],
4773
- Deposit: [{ name: "recipients", type: "address[]" }],
4774
- TokenPermissions: [
4775
- { name: "token", type: "address" },
4776
- { name: "amount", type: "uint256" }
4777
- ]
4778
- };
4779
- var PERMIT2_BATCH_ABI = (0, import_viem9.parseAbi)([
4780
- "struct TokenPermissions { address token; uint256 amount; }",
4781
- "struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
4782
- "struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
4783
- "function permitWitnessTransferFrom(PermitBatchTransferFrom permit,SignatureTransferDetails[] transferDetails,address owner,bytes32 witness,string witnessTypeString,bytes signature)",
4784
- "function nonceBitmap(address owner,uint256 wordPos) view returns (uint256)"
4785
- ]);
4786
- function batchPermit(b) {
4787
- return {
4788
- permitted: b.transfers.map((t) => ({
4789
- token: b.token,
4790
- amount: BigInt(t.amount)
4791
- })),
4792
- nonce: BigInt(b.nonce),
4793
- deadline: BigInt(b.deadline)
4794
- };
2417
+ async function readTokenMeta(publicClient, token) {
2418
+ const [tokenName, tokenVersion] = await Promise.all([
2419
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
2420
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
2421
+ ]);
2422
+ return { tokenName, tokenVersion };
2423
+ }
2424
+ function randomAuthNonce() {
2425
+ const bytes = new Uint8Array(32);
2426
+ globalThis.crypto.getRandomValues(bytes);
2427
+ return (0, import_viem3.bytesToHex)(bytes);
2428
+ }
2429
+
2430
+ // src/lib/sponsor-client.ts
2431
+ var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2432
+ async function postSponsorTransferAuth(input) {
2433
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2434
+ let res;
2435
+ try {
2436
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2437
+ method: "POST",
2438
+ headers: {
2439
+ "content-type": "application/json",
2440
+ "x-owney-api-key": input.apiKey
2441
+ },
2442
+ body: JSON.stringify(input.body)
2443
+ });
2444
+ } catch (networkError) {
2445
+ throw new OwneyError(
2446
+ "SPONSOR_REQUEST_FAILED",
2447
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2448
+ { cause: String(networkError) }
2449
+ );
2450
+ }
2451
+ const text = await res.text();
2452
+ let parsed = null;
2453
+ try {
2454
+ parsed = JSON.parse(text);
2455
+ } catch {
2456
+ }
2457
+ if (!res.ok || !parsed?.success || !parsed.data) {
2458
+ throw new OwneyError(
2459
+ "SPONSOR_REQUEST_FAILED",
2460
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2461
+ {
2462
+ statusCode: res.status,
2463
+ responseBody: text.slice(0, 500),
2464
+ // 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
2465
+ // before broadcast, so it is safe to fall back to a user-paid deposit.
2466
+ safeToFallback: res.status === 503
2467
+ }
2468
+ );
2469
+ }
2470
+ return parsed.data;
2471
+ }
2472
+ async function postSponsorPermit2Transfer(input) {
2473
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2474
+ let res;
2475
+ try {
2476
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2477
+ method: "POST",
2478
+ headers: {
2479
+ "content-type": "application/json",
2480
+ "x-owney-api-key": input.apiKey
2481
+ },
2482
+ body: JSON.stringify(input.body)
2483
+ });
2484
+ } catch (networkError) {
2485
+ throw new OwneyError(
2486
+ "SPONSOR_REQUEST_FAILED",
2487
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2488
+ { cause: String(networkError), safeToFallback: false }
2489
+ );
2490
+ }
2491
+ const text = await res.text();
2492
+ let parsed = null;
2493
+ try {
2494
+ parsed = JSON.parse(text);
2495
+ } catch {
2496
+ }
2497
+ if (!res.ok || !parsed?.success || !parsed.data) {
2498
+ throw new OwneyError(
2499
+ "SPONSOR_REQUEST_FAILED",
2500
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2501
+ {
2502
+ statusCode: res.status,
2503
+ responseBody: text.slice(0, 500),
2504
+ safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
2505
+ }
2506
+ );
2507
+ }
2508
+ return parsed.data;
2509
+ }
2510
+ async function getSponsorRelayerAddress(input) {
2511
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2512
+ let res;
2513
+ try {
2514
+ res = await fetch(
2515
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2516
+ {
2517
+ headers: { "x-owney-api-key": input.apiKey }
2518
+ }
2519
+ );
2520
+ } catch (networkError) {
2521
+ throw new OwneyError(
2522
+ "SPONSOR_REQUEST_FAILED",
2523
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
2524
+ { cause: String(networkError), safeToFallback: true }
2525
+ );
2526
+ }
2527
+ const text = await res.text();
2528
+ let parsed = null;
2529
+ try {
2530
+ parsed = JSON.parse(text);
2531
+ } catch {
2532
+ }
2533
+ if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
2534
+ throw new OwneyError(
2535
+ "SPONSOR_REQUEST_FAILED",
2536
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
2537
+ {
2538
+ statusCode: res.status,
2539
+ responseBody: text.slice(0, 500),
2540
+ safeToFallback: true
2541
+ }
2542
+ );
2543
+ }
2544
+ return parsed.data.relayer;
4795
2545
  }
4796
- function batchTypedData(b, spender) {
2546
+
2547
+ // src/lib/permit2.ts
2548
+ var import_viem4 = require("viem");
2549
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2550
+ var MAX_UINT256 = 2n ** 256n - 1n;
2551
+ var ERC20_ALLOWANCE_ABI = [
2552
+ {
2553
+ type: "function",
2554
+ name: "allowance",
2555
+ stateMutability: "view",
2556
+ inputs: [
2557
+ { name: "owner", type: "address" },
2558
+ { name: "spender", type: "address" }
2559
+ ],
2560
+ outputs: [{ name: "", type: "uint256" }]
2561
+ },
2562
+ {
2563
+ type: "function",
2564
+ name: "approve",
2565
+ stateMutability: "nonpayable",
2566
+ inputs: [
2567
+ { name: "spender", type: "address" },
2568
+ { name: "amount", type: "uint256" }
2569
+ ],
2570
+ outputs: [{ name: "", type: "bool" }]
2571
+ },
2572
+ {
2573
+ type: "function",
2574
+ name: "balanceOf",
2575
+ stateMutability: "view",
2576
+ inputs: [{ name: "account", type: "address" }],
2577
+ outputs: [{ name: "", type: "uint256" }]
2578
+ }
2579
+ ];
2580
+ function buildPermitTransferFromTypedData(input) {
4797
2581
  return {
4798
2582
  domain: {
4799
2583
  name: "Permit2",
4800
- chainId: b.chainId,
4801
- verifyingContract: BATCH_PERMIT2_ADDRESS
2584
+ chainId: input.chainId,
2585
+ verifyingContract: PERMIT2_ADDRESS
4802
2586
  },
4803
- types: PERMIT_BATCH_TYPES,
4804
- primaryType: "PermitBatchWitnessTransferFrom",
4805
- message: {
4806
- ...batchPermit(b),
4807
- spender,
4808
- witness: { recipients: b.transfers.map((t) => t.to) }
4809
- }
2587
+ types: {
2588
+ PermitTransferFrom: [
2589
+ { name: "permitted", type: "TokenPermissions" },
2590
+ { name: "spender", type: "address" },
2591
+ { name: "nonce", type: "uint256" },
2592
+ { name: "deadline", type: "uint256" }
2593
+ ],
2594
+ TokenPermissions: [
2595
+ { name: "token", type: "address" },
2596
+ { name: "amount", type: "uint256" }
2597
+ ]
2598
+ },
2599
+ primaryType: "PermitTransferFrom",
2600
+ message: input.message
4810
2601
  };
4811
2602
  }
4812
-
4813
- // src/lib/sponsored-token-batch.ts
4814
- var memory = /* @__PURE__ */ new Map();
4815
- var inflight = /* @__PURE__ */ new Map();
4816
- var planOf = (transfers) => JSON.stringify(
4817
- transfers.map((t) => ({
4818
- to: t.to.toLowerCase(),
4819
- amount: BigInt(t.amount).toString()
4820
- }))
4821
- );
4822
- function read(key2) {
4823
- return typeof window === "undefined" ? memory.get(key2) : window.localStorage.getItem(key2);
2603
+ function randomPermit2Nonce() {
2604
+ const bytes = new Uint8Array(32);
2605
+ globalThis.crypto.getRandomValues(bytes);
2606
+ return BigInt((0, import_viem4.bytesToHex)(bytes));
4824
2607
  }
4825
- function save(key2, body) {
4826
- const value = JSON.stringify({
4827
- ...body,
4828
- transfers: body.transfers.map(({ to, amount }) => ({ to, amount }))
2608
+ async function readPermit2Allowance(publicClient, token, owner) {
2609
+ return publicClient.readContract({
2610
+ address: token,
2611
+ abi: ERC20_ALLOWANCE_ABI,
2612
+ functionName: "allowance",
2613
+ args: [owner, PERMIT2_ADDRESS]
4829
2614
  });
4830
- if (typeof window === "undefined") memory.set(key2, value);
4831
- else window.localStorage.setItem(key2, value);
4832
2615
  }
4833
- function clear(key2) {
4834
- if (typeof window === "undefined") memory.delete(key2);
4835
- else window.localStorage.removeItem(key2);
2616
+ async function readErc20Balance(publicClient, token, owner) {
2617
+ return publicClient.readContract({
2618
+ address: token,
2619
+ abi: ERC20_ALLOWANCE_ABI,
2620
+ functionName: "balanceOf",
2621
+ args: [owner]
2622
+ });
4836
2623
  }
4837
- function sponsorTokenBatch(i) {
4838
- const key2 = `owney.token-batch.v1:${(0, import_viem10.keccak256)((0, import_viem10.toBytes)(i.apiKey))}:${i.baseUrl ?? "default"}:${i.chainId}:${i.owner.toLowerCase()}:${i.token.toLowerCase()}`;
4839
- const plan = planOf(i.transfers);
4840
- const active = inflight.get(key2);
4841
- if (active) {
4842
- if (active.plan !== plan)
4843
- return Promise.reject(
4844
- new Error(
4845
- "A token deposit is already in progress. Wait for its result before depositing again."
4846
- )
4847
- );
4848
- return active.promise;
4849
- }
4850
- const promise = execute(i, key2, plan).finally(() => inflight.delete(key2));
4851
- inflight.set(key2, { plan, promise });
4852
- return promise;
2624
+
2625
+ // src/lib/chain-guard.ts
2626
+ var CHAIN_NAMES = {
2627
+ 1: "Ethereum",
2628
+ 8453: "Base",
2629
+ 42161: "Arbitrum"
2630
+ };
2631
+ function chainName(chainId) {
2632
+ return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
4853
2633
  }
4854
- async function execute(i, key2, plan) {
4855
- if (!i.transfers.length || i.transfers.length > 16 || i.transfers.some(
4856
- (t) => BigInt(t.amount) <= 0n || BigInt(t.amount) >= 1n << 256n
4857
- ) || new Set(i.transfers.map((t) => t.to.toLowerCase())).size !== i.transfers.length)
4858
- throw new Error("Invalid token deposit shares.");
4859
- const send = async (initial) => {
4860
- let body = initial;
4861
- save(key2, body);
4862
- try {
4863
- if (!body.serializedTransaction) {
4864
- const prepared = await postSponsorBatchTransfer({
4865
- apiKey: i.apiKey,
4866
- baseUrl: i.baseUrl,
4867
- body
4868
- });
4869
- if (!prepared.serializedTransaction || (0, import_viem10.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
4870
- throw new Error(
4871
- "Sponsorship API did not return a valid prepared transaction."
4872
- );
4873
- body = {
4874
- ...body,
4875
- serializedTransaction: prepared.serializedTransaction
4876
- };
4877
- save(key2, body);
4878
- }
4879
- const result = await postSponsorBatchTransfer({
4880
- apiKey: i.apiKey,
4881
- baseUrl: i.baseUrl,
4882
- body
4883
- });
4884
- if (result.txHash !== (0, import_viem10.keccak256)(body.serializedTransaction))
4885
- throw new Error(
4886
- "Sponsorship receipt does not match the pending transaction."
4887
- );
4888
- clear(key2);
4889
- return result.txHash;
4890
- } catch (error) {
4891
- if (!body.serializedTransaction || error instanceof OwneyError && error.details?.notSubmitted === true)
4892
- clear(key2);
4893
- throw error;
4894
- }
4895
- };
4896
- const saved = read(key2);
4897
- if (saved) {
4898
- const previous = JSON.parse(saved);
4899
- if (previous.chainId !== i.chainId || !(0, import_viem10.isAddressEqual)(previous.from, i.owner) || !(0, import_viem10.isAddressEqual)(previous.token, i.token) || planOf(previous.transfers) !== plan)
4900
- throw new Error(
4901
- "Retry the previous token deposit and agent split first to reconcile its status."
4902
- );
4903
- i.onApproved?.();
4904
- return send({ ...previous, transfers: i.transfers });
4905
- }
4906
- const total = i.transfers.reduce((sum, t) => sum + BigInt(t.amount), 0n);
4907
- const [balance, allowance] = await Promise.all([
4908
- readErc20Balance(i.pub, i.token, i.owner),
4909
- readPermit2Allowance(i.pub, i.token, i.owner)
4910
- ]);
4911
- if (balance < total)
2634
+ async function ensureWalletOnChain(pub, wallet, expected) {
2635
+ const actual = await pub.getChainId();
2636
+ if (actual === expected) return;
2637
+ try {
2638
+ await wallet.switchChain({ id: expected });
2639
+ } catch (error) {
4912
2640
  throw new OwneyError(
4913
- "DEPOSIT_INSUFFICIENT_BALANCE",
4914
- "Insufficient token balance for this deposit."
2641
+ "CHAIN_MISMATCH",
2642
+ `Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
2643
+ {
2644
+ expectedChainId: expected,
2645
+ actualChainId: actual,
2646
+ cause: error instanceof Error ? error.message : String(error)
2647
+ }
4915
2648
  );
4916
- if (allowance < total && (i.chainId !== 8453 || !(0, import_viem10.isAddressEqual)(i.token, BASE_USDC_ADDRESS)))
2649
+ }
2650
+ const after = await pub.getChainId();
2651
+ if (after !== expected) {
4917
2652
  throw new OwneyError(
4918
- "PERMIT2_APPROVAL_REQUIRED",
4919
- "token deposits need a one-time Permit2 approval."
2653
+ "CHAIN_MISMATCH",
2654
+ `Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
2655
+ { expectedChainId: expected, actualChainId: after }
4920
2656
  );
4921
- const now = (await i.pub.getBlock()).timestamp;
4922
- let erc2612Permit;
4923
- if (allowance < total) {
4924
- const [tokenName, tokenVersion, permitNonce] = await Promise.all([
4925
- i.pub.readContract({
4926
- address: i.token,
4927
- abi: ERC2612_READ_ABI,
4928
- functionName: "name"
4929
- }),
4930
- i.pub.readContract({
4931
- address: i.token,
4932
- abi: ERC2612_READ_ABI,
4933
- functionName: "version"
4934
- }),
4935
- i.pub.readContract({
4936
- address: i.token,
4937
- abi: ERC2612_READ_ABI,
4938
- functionName: "nonces",
4939
- args: [i.owner]
4940
- })
4941
- ]);
4942
- const unsignedPermit = {
4943
- value: MAX_UINT256.toString(),
4944
- nonce: permitNonce.toString(),
4945
- deadline: (now + 900n).toString(),
4946
- tokenName,
4947
- tokenVersion
4948
- };
4949
- const signature2 = await i.wallet.signTypedData({
4950
- account: i.owner,
4951
- ...erc2612TypedData({
4952
- chainId: 8453,
4953
- token: i.token,
4954
- owner: i.owner,
4955
- permit: unsignedPermit
4956
- })
4957
- });
4958
- erc2612Permit = { ...unsignedPermit, signature: signature2 };
4959
2657
  }
4960
- const spender = erc2612Permit ? MULTICALL3_ADDRESS : await getSponsorRelayerAddress({
4961
- apiKey: i.apiKey,
4962
- baseUrl: i.baseUrl,
4963
- chainId: i.chainId
4964
- });
4965
- const unsigned = {
4966
- chainId: i.chainId,
4967
- token: i.token,
4968
- from: i.owner,
4969
- transfers: i.transfers,
4970
- nonce: randomPermit2Nonce().toString(),
4971
- deadline: (now + 900n).toString(),
4972
- ...erc2612Permit ? { erc2612Permit } : {}
4973
- };
4974
- const signature = await i.wallet.signTypedData({
4975
- account: i.owner,
4976
- ...batchTypedData(unsigned, spender)
4977
- });
4978
- i.onApproved?.();
4979
- return send({ ...unsigned, signature });
4980
2658
  }
4981
2659
 
4982
- // src/lib/sponsored-token-deposit.ts
4983
- function makeSponsoredTokenCallback(deps) {
4984
- const batch = async (chainId, transfers) => {
4985
- if (chainId !== 8453 && chainId !== 42161 && chainId !== 1)
2660
+ // src/lib/sponsored-deposit.ts
2661
+ var AUTH_WINDOW_SECONDS = 15 * 60;
2662
+ function makeSponsoredDepositCallback(deps) {
2663
+ const post = deps.httpPost ?? postSponsorTransferAuth;
2664
+ return async (smartWallet, chainId, amount) => {
2665
+ const cid = chainId;
2666
+ const token = deps.tokenAddressByChain[cid];
2667
+ if (!token) {
4986
2668
  throw new OwneyError(
4987
2669
  "CHAIN_UNSUPPORTED",
4988
2670
  `No sponsored token configured for chain ${chainId}`
4989
2671
  );
4990
- const token = deps.tokenAddressByChain[chainId];
4991
- if (!token)
4992
- throw new OwneyError(
4993
- "CHAIN_UNSUPPORTED",
4994
- `No sponsored token configured for chain ${chainId}`
2672
+ }
2673
+ const pub = deps.getPublicClient(cid);
2674
+ const wallet = deps.getWalletClient(cid);
2675
+ await ensureWalletOnChain(pub, wallet, cid);
2676
+ try {
2677
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2678
+ if (balance < BigInt(amount)) {
2679
+ throw new OwneyError(
2680
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2681
+ "Insufficient balance for this deposit.",
2682
+ { token, chainId: cid, balance: balance.toString(), amount }
2683
+ );
2684
+ }
2685
+ } catch (err) {
2686
+ if (err instanceof OwneyError) throw err;
2687
+ console.warn(
2688
+ "[owney-sdk] Deposit balance pre-check failed (non-fatal):",
2689
+ err instanceof Error ? err.message : String(err)
4995
2690
  );
4996
- const pub = deps.getPublicClient(chainId), walletChain = deps.getWalletChainClient?.(chainId) ?? pub, wallet = deps.getWalletClient(chainId);
4997
- await ensureWalletOnChain(walletChain, wallet, chainId);
4998
- return sponsorTokenBatch({
4999
- apiKey: deps.apiKey,
5000
- baseUrl: deps.baseUrl,
5001
- owner: deps.ownerAddress,
2691
+ }
2692
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
2693
+ const validAfter = 0n;
2694
+ const validBefore = BigInt(
2695
+ Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
2696
+ );
2697
+ const nonce = randomAuthNonce();
2698
+ const typedData = buildTransferWithAuthorizationTypedData({
5002
2699
  token,
5003
- chainId,
5004
- transfers,
5005
- pub,
5006
- wallet,
5007
- onApproved: deps.onApproved
2700
+ chainId: cid,
2701
+ tokenName,
2702
+ tokenVersion,
2703
+ message: {
2704
+ from: deps.ownerAddress,
2705
+ to: smartWallet,
2706
+ value: BigInt(amount),
2707
+ validAfter,
2708
+ validBefore,
2709
+ nonce
2710
+ }
5008
2711
  });
2712
+ const authSignature = await wallet.signTypedData({
2713
+ account: deps.ownerAddress,
2714
+ ...typedData
2715
+ });
2716
+ deps.onApproved?.();
2717
+ const result = await post({
2718
+ baseUrl: deps.baseUrl,
2719
+ apiKey: deps.apiKey,
2720
+ body: {
2721
+ chainId: cid,
2722
+ token,
2723
+ from: deps.ownerAddress,
2724
+ to: smartWallet,
2725
+ value: amount,
2726
+ validAfter: validAfter.toString(),
2727
+ validBefore: validBefore.toString(),
2728
+ nonce,
2729
+ authSignature,
2730
+ tokenName,
2731
+ tokenVersion
2732
+ }
2733
+ });
2734
+ return result.txHash;
5009
2735
  };
5010
- const callback = makeVerificationAwareDepositCallback(
5011
- (to, chainId, amount, verification) => batch(chainId, [toBatchTransfer(to, amount, verification)])
5012
- );
5013
- registerDepositBatch(callback, batch);
5014
- return callback;
5015
2736
  }
5016
2737
 
5017
- // src/lib/agent-deposit-batch.ts
5018
- function deferred() {
5019
- let resolve, reject;
5020
- const promise = new Promise((yes, no) => {
5021
- resolve = yes;
5022
- reject = no;
5023
- });
5024
- void promise.catch(() => {
5025
- });
5026
- return { promise, resolve, reject };
5027
- }
5028
- async function runAgentDepositBatch(chainId, legs, transfer) {
5029
- const funding = deferred();
5030
- const tasks = [];
5031
- const transfers = [];
5032
- try {
5033
- for (const leg of legs) {
5034
- const ready = deferred();
5035
- let entered = false;
5036
- const callback = makeVerificationAwareDepositCallback(
5037
- (to, cid, amount, verification) => {
5038
- if (entered || cid !== chainId || BigInt(amount) !== BigInt(leg.amount)) {
5039
- const error = new Error(
5040
- "Agent changed its prepared deposit share."
5041
- );
5042
- ready.reject(error);
5043
- throw error;
5044
- }
5045
- entered = true;
5046
- ready.resolve(toBatchTransfer(to, amount, verification));
5047
- return funding.promise;
5048
- }
5049
- );
5050
- const task = Promise.resolve().then(() => leg.run(callback));
5051
- tasks.push(task);
5052
- void task.then(
5053
- () => {
5054
- if (!entered)
5055
- ready.reject(
5056
- new Error("Agent did not prepare a deposit transfer.")
5057
- );
5058
- },
5059
- (error) => ready.reject(error)
2738
+ // src/lib/sponsored-weth-deposit.ts
2739
+ var PERMIT_WINDOW_SECONDS = 15 * 60;
2740
+ function makeSponsoredWethCallback(deps) {
2741
+ const get = deps.httpGet ?? getSponsorRelayerAddress;
2742
+ const post = deps.httpPost ?? postSponsorPermit2Transfer;
2743
+ return async (smartWallet, chainId, amount) => {
2744
+ const cid = chainId;
2745
+ const token = deps.tokenAddressByChain[cid];
2746
+ if (!token) {
2747
+ throw new OwneyError(
2748
+ "CHAIN_UNSUPPORTED",
2749
+ `No sponsored WETH configured for chain ${chainId}`
5060
2750
  );
5061
- transfers.push(await ready.promise);
5062
2751
  }
5063
- const txHash = await transfer(chainId, transfers);
5064
- funding.resolve(txHash);
5065
- const settled = await Promise.allSettled(tasks);
5066
- const agentResults = {};
5067
- const failures = [];
5068
- for (const [index, result] of settled.entries()) {
5069
- if (result.status === "fulfilled")
5070
- agentResults[legs[index].id] = result.value;
5071
- else failures.push(legs[index].id);
2752
+ const amountWei = BigInt(amount);
2753
+ const pub = deps.getPublicClient(cid);
2754
+ const wallet = deps.getWalletClient(cid);
2755
+ await ensureWalletOnChain(pub, wallet, cid);
2756
+ try {
2757
+ const balance = await readErc20Balance(pub, token, deps.ownerAddress);
2758
+ if (balance < amountWei) {
2759
+ throw new OwneyError(
2760
+ "DEPOSIT_INSUFFICIENT_BALANCE",
2761
+ "Insufficient WETH balance for this deposit.",
2762
+ { token, chainId: cid, balance: balance.toString(), amount }
2763
+ );
2764
+ }
2765
+ } catch (err) {
2766
+ if (err instanceof OwneyError) throw err;
2767
+ console.warn(
2768
+ "[owney-sdk] WETH balance pre-check failed (non-fatal):",
2769
+ err instanceof Error ? err.message : String(err)
2770
+ );
5072
2771
  }
5073
- if (failures.length)
2772
+ const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
2773
+ if (allowance < amountWei) {
5074
2774
  throw new OwneyError(
5075
- "DEPOSIT_PARTIAL_FAILURE",
5076
- "The deposit was sent to all agents, but some agent updates could not be confirmed. Check activity before depositing again.",
5077
- {
5078
- txHash,
5079
- fundsSubmitted: true,
5080
- agentResults,
5081
- failedAgentIds: failures
5082
- }
2775
+ "PERMIT2_APPROVAL_REQUIRED",
2776
+ "WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
2777
+ { token, chainId: cid, allowance: allowance.toString(), amount }
5083
2778
  );
5084
- return { agentResults };
5085
- } catch (error) {
5086
- funding.reject(error);
5087
- await Promise.allSettled(tasks);
5088
- throw error;
5089
- }
2779
+ }
2780
+ const relayer = await get({
2781
+ baseUrl: deps.baseUrl,
2782
+ apiKey: deps.apiKey,
2783
+ chainId: cid
2784
+ });
2785
+ const nonce = randomPermit2Nonce();
2786
+ const deadline = BigInt(
2787
+ Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
2788
+ );
2789
+ const typedData = buildPermitTransferFromTypedData({
2790
+ chainId: cid,
2791
+ message: {
2792
+ permitted: { token, amount: amountWei },
2793
+ spender: relayer,
2794
+ nonce,
2795
+ deadline
2796
+ }
2797
+ });
2798
+ const signature = await wallet.signTypedData({
2799
+ account: deps.ownerAddress,
2800
+ ...typedData
2801
+ });
2802
+ deps.onApproved?.();
2803
+ const result = await post({
2804
+ baseUrl: deps.baseUrl,
2805
+ apiKey: deps.apiKey,
2806
+ body: {
2807
+ chainId: cid,
2808
+ token,
2809
+ from: deps.ownerAddress,
2810
+ to: smartWallet,
2811
+ amount,
2812
+ nonce: nonce.toString(),
2813
+ deadline: deadline.toString(),
2814
+ signature
2815
+ }
2816
+ });
2817
+ return result.txHash;
2818
+ };
5090
2819
  }
5091
2820
 
5092
2821
  // src/lib/sponsored-calls-deposit.ts
5093
- var import_viem11 = require("viem");
2822
+ var import_viem5 = require("viem");
5094
2823
  var DEFAULT_POLL_INTERVAL_MS = 1500;
5095
2824
  var DEFAULT_MAX_POLLS = 30;
5096
2825
  async function paymasterSupported(provider, owner, chainId) {
@@ -5098,7 +2827,7 @@ async function paymasterSupported(provider, owner, chainId) {
5098
2827
  method: "wallet_getCapabilities",
5099
2828
  params: [owner]
5100
2829
  });
5101
- const forChain = caps?.[(0, import_viem11.toHex)(chainId)] ?? caps?.[String(chainId)];
2830
+ const forChain = caps?.[(0, import_viem5.toHex)(chainId)] ?? caps?.[String(chainId)];
5102
2831
  return Boolean(forChain?.paymasterService?.supported);
5103
2832
  }
5104
2833
  function makeSponsoredCallsCallback(deps) {
@@ -5116,7 +2845,7 @@ function makeSponsoredCallsCallback(deps) {
5116
2845
  }
5117
2846
  return new URL(configured, origin).toString();
5118
2847
  };
5119
- const batch = async (chainId, transfers) => {
2848
+ return async (smartWallet, chainId, amount) => {
5120
2849
  const cid = chainId;
5121
2850
  const token = deps.tokenAddressByChain[cid];
5122
2851
  if (!token) {
@@ -5132,53 +2861,22 @@ function makeSponsoredCallsCallback(deps) {
5132
2861
  { chainId }
5133
2862
  );
5134
2863
  }
5135
- const calls = transfers.map((transfer) => ({
5136
- to: token,
5137
- value: "0x0",
5138
- data: (0, import_viem11.encodeFunctionData)({
5139
- abi: import_viem11.erc20Abi,
5140
- functionName: "transfer",
5141
- args: [transfer.to, BigInt(transfer.amount)]
5142
- })
5143
- }));
5144
- let paymasterUrl = absolutePaymasterUrl();
5145
- for (const transfer of transfers) {
5146
- const verification = transfer.yieldseeker;
5147
- if (!verification) continue;
5148
- if (chainId !== 8453)
5149
- throw new OwneyError(
5150
- "CHAIN_UNSUPPORTED",
5151
- `Yieldseeker sponsorship is not available on chain ${chainId}.`
5152
- );
5153
- const { intent } = await postPaymasterIntent({
5154
- baseUrl: deps.routingApiBaseUrl,
5155
- apiKey: deps.apiKey,
5156
- yieldseekerSignature: verification.signature,
5157
- body: {
5158
- chainId,
5159
- token,
5160
- from: deps.ownerAddress,
5161
- to: transfer.to,
5162
- amount: transfer.amount,
5163
- yieldseekerUserId: verification.userId,
5164
- yieldseekerAgentId: verification.agentId
5165
- }
5166
- });
5167
- const url = new URL(paymasterUrl);
5168
- url.searchParams.append("owneyIntent", intent);
5169
- paymasterUrl = url.toString();
5170
- }
2864
+ const data = (0, import_viem5.encodeFunctionData)({
2865
+ abi: import_viem5.erc20Abi,
2866
+ functionName: "transfer",
2867
+ args: [smartWallet, BigInt(amount)]
2868
+ });
5171
2869
  const sendResult = await deps.provider.request({
5172
2870
  method: "wallet_sendCalls",
5173
2871
  params: [
5174
2872
  {
5175
2873
  version: "2.0.0",
5176
2874
  from: deps.ownerAddress,
5177
- chainId: (0, import_viem11.toHex)(chainId),
5178
- atomicRequired: transfers.length > 1,
5179
- calls,
2875
+ chainId: (0, import_viem5.toHex)(chainId),
2876
+ atomicRequired: false,
2877
+ calls: [{ to: token, value: "0x0", data }],
5180
2878
  capabilities: {
5181
- paymasterService: { url: paymasterUrl }
2879
+ paymasterService: { url: absolutePaymasterUrl() }
5182
2880
  }
5183
2881
  }
5184
2882
  ]
@@ -5198,24 +2896,7 @@ function makeSponsoredCallsCallback(deps) {
5198
2896
  params: [callsId]
5199
2897
  });
5200
2898
  const txHash = status?.receipts?.[0]?.transactionHash;
5201
- if (status?.receipts?.some((receipt) => receipt.status === "0x0") || typeof status?.status === "number" && status.status >= 400) {
5202
- throw new OwneyError(
5203
- "SPONSOR_REQUEST_FAILED",
5204
- "The sponsored deposit did not complete successfully.",
5205
- { chainId, callsId, safeToFallback: false }
5206
- );
5207
- }
5208
- if (txHash && (transfers.length === 1 || status?.status === 200 || status?.status === "CONFIRMED")) {
5209
- if (status?.receipts?.some(
5210
- (receipt) => receipt.transactionHash !== txHash
5211
- ))
5212
- throw new OwneyError(
5213
- "SPONSORED_CALLS_NO_RECEIPT",
5214
- "The wallet returned multiple transactions for an atomic deposit. Check activity before trying again.",
5215
- { chainId, callsId }
5216
- );
5217
- return txHash;
5218
- }
2899
+ if (txHash) return txHash;
5219
2900
  if (pollIntervalMs > 0) {
5220
2901
  await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
5221
2902
  }
@@ -5226,16 +2907,9 @@ function makeSponsoredCallsCallback(deps) {
5226
2907
  { chainId, callsId }
5227
2908
  );
5228
2909
  };
5229
- const callback = makeVerificationAwareDepositCallback(
5230
- (to, chainId, amount, verification) => batch(chainId, [toBatchTransfer(to, amount, verification)])
5231
- );
5232
- registerDepositBatch(callback, batch);
5233
- return callback;
5234
2910
  }
5235
2911
 
5236
2912
  // src/client.ts
5237
- var PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS = 6;
5238
- var PERMIT2_ALLOWANCE_VERIFY_DELAY_MS = 250;
5239
2913
  function encodeMultiAgentCursor(map) {
5240
2914
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
5241
2915
  }
@@ -5262,20 +2936,15 @@ var SPONSORED_USDC_BY_CHAIN = {
5262
2936
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
5263
2937
  };
5264
2938
  var VIEM_CHAIN2 = {
5265
- 8453: import_chains4.base,
5266
- 42161: import_chains4.arbitrum,
5267
- 1: import_chains4.mainnet
2939
+ 8453: import_chains2.base,
2940
+ 42161: import_chains2.arbitrum,
2941
+ 1: import_chains2.mainnet
5268
2942
  };
5269
2943
  var SPONSORED_WETH_BY_CHAIN = {
5270
2944
  8453: "0x4200000000000000000000000000000000000006",
5271
2945
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
5272
2946
  1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
5273
2947
  };
5274
- var SPONSORED_TOKENS_BY_ASSET = { USDC: SPONSORED_USDC_BY_CHAIN, WETH: SPONSORED_WETH_BY_CHAIN };
5275
- function sponsoredTokensFor(asset) {
5276
- if (!Object.prototype.hasOwnProperty.call(SPONSORED_TOKENS_BY_ASSET, asset)) throw new OwneyError("ASSET_UNSUPPORTED", `No sponsored token configured for ${asset}`);
5277
- return SPONSORED_TOKENS_BY_ASSET[asset];
5278
- }
5279
2948
  function shouldFallbackToUserPaid(error, asset, appCallback) {
5280
2949
  return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
5281
2950
  }
@@ -5296,10 +2965,7 @@ var OwneySDK = class {
5296
2965
  // leave every user's agent profile alone.
5297
2966
  orgAgentConfig;
5298
2967
  orgAgentConfigPromise = null;
5299
- rpcUrls;
5300
2968
  zyfaiRpcUrls;
5301
- yieldseekerApiBaseUrl;
5302
- yieldseekerSiweOrigin;
5303
2969
  routingApiBaseUrl;
5304
2970
  referralSource;
5305
2971
  cachedSponsoredCallback = null;
@@ -5321,14 +2987,7 @@ var OwneySDK = class {
5321
2987
  constructor(config) {
5322
2988
  this.apiKey = config.apiKey;
5323
2989
  if (config.debug) setOwneyDebug(true);
5324
- this.rpcUrls = resolveRpcUrls(
5325
- config.rpcUrls,
5326
- config.apiKey,
5327
- config.routingApiBaseUrl
5328
- );
5329
- this.zyfaiRpcUrls = config.rpcUrls ? void 0 : config.zyfaiRpcUrls;
5330
- this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
5331
- this.yieldseekerSiweOrigin = config.yieldseekerSiweOrigin;
2990
+ this.zyfaiRpcUrls = config.zyfaiRpcUrls;
5332
2991
  this.routingApiBaseUrl = config.routingApiBaseUrl;
5333
2992
  this.paymasterServiceUrl = config.paymasterServiceUrl;
5334
2993
  this.referralSource = config.referralSource;
@@ -5362,7 +3021,6 @@ var OwneySDK = class {
5362
3021
  * After calling this, `connect()` must be called again before using agent methods.
5363
3022
  */
5364
3023
  async disconnect() {
5365
- this.state = null;
5366
3024
  for (const agent of this.agents.values()) {
5367
3025
  await agent.disconnect();
5368
3026
  }
@@ -5416,16 +3074,18 @@ var OwneySDK = class {
5416
3074
  }
5417
3075
  return this.state.provider;
5418
3076
  }
5419
- getPaidRpcClient(chainId) {
5420
- return createPaidRpcClient(VIEM_CHAIN2[chainId], this.rpcUrls);
5421
- }
5422
- /** Builds the default USDC batch callback for the connected wallet. */
3077
+ /**
3078
+ * Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
3079
+ * used when the caller omits `depositCallback`. Wraps the connected EIP-1193
3080
+ * provider with viem `custom(provider)` to read token meta and sign the
3081
+ * `TransferWithAuthorization`, then POSTs to the sponsor API.
3082
+ */
5423
3083
  getDefaultSponsoredCallback(onApproved) {
5424
3084
  if (!onApproved && this.cachedSponsoredCallback)
5425
3085
  return this.cachedSponsoredCallback;
5426
3086
  const provider = this.requireConnectedProvider();
5427
3087
  const owner = this.state.walletAddress;
5428
- const callback = makeSponsoredTokenCallback({
3088
+ const callback = makeSponsoredDepositCallback({
5429
3089
  apiKey: this.apiKey,
5430
3090
  baseUrl: this.routingApiBaseUrl,
5431
3091
  ownerAddress: owner,
@@ -5434,33 +3094,35 @@ var OwneySDK = class {
5434
3094
  // Casts work around viem's chain-narrowed Client vs the generic
5435
3095
  // PublicClient/WalletClient param types — structurally identical at
5436
3096
  // runtime, but the two share a name TS treats as unrelated.
5437
- getPublicClient: (cid) => this.getPaidRpcClient(cid),
5438
- getWalletChainClient: (cid) => (0, import_viem12.createPublicClient)({
3097
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
5439
3098
  chain: VIEM_CHAIN2[cid],
5440
- transport: (0, import_viem12.custom)(provider)
3099
+ transport: (0, import_viem6.custom)(provider)
5441
3100
  }),
5442
- getWalletClient: (cid) => (0, import_viem12.createWalletClient)({
3101
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
5443
3102
  account: owner,
5444
3103
  chain: VIEM_CHAIN2[cid],
5445
- transport: (0, import_viem12.custom)(provider)
3104
+ transport: (0, import_viem6.custom)(provider)
5446
3105
  })
5447
3106
  });
5448
3107
  if (!onApproved) this.cachedSponsoredCallback = callback;
5449
3108
  return callback;
5450
3109
  }
5451
- /** Builds the wallet-native sponsored calls callback for compatible paymasters. */
3110
+ /**
3111
+ * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
3112
+ * callback used when the caller omits `depositCallback` for a WETH
3113
+ * deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
3114
+ * `PermitTransferFrom` instead of an EIP-3009 authorization.
3115
+ */
5452
3116
  getDefaultSponsoredCallsCallback(asset, onApproved) {
5453
3117
  const cached = this.cachedSponsoredCallsCallbacks.get(asset);
5454
3118
  if (!onApproved && cached) return cached;
5455
3119
  const provider = this.requireConnectedProvider();
5456
3120
  const callback = makeSponsoredCallsCallback({
5457
- apiKey: this.apiKey,
5458
- routingApiBaseUrl: this.routingApiBaseUrl,
5459
3121
  provider,
5460
3122
  ownerAddress: this.state.walletAddress,
5461
3123
  paymasterServiceUrl: this.paymasterServiceUrl,
5462
3124
  onApproved,
5463
- tokenAddressByChain: sponsoredTokensFor(asset)
3125
+ tokenAddressByChain: asset === "WETH" ? SPONSORED_WETH_BY_CHAIN : SPONSORED_USDC_BY_CHAIN
5464
3126
  });
5465
3127
  if (!onApproved) this.cachedSponsoredCallsCallbacks.set(asset, callback);
5466
3128
  return callback;
@@ -5469,14 +3131,14 @@ var OwneySDK = class {
5469
3131
  * Lazily builds (and caches) the default Permit2 sponsored WETH deposit
5470
3132
  * callback used when the caller omits `depositCallback` for a WETH deposit.
5471
3133
  * Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
5472
- * single-use batch authorization instead of an EIP-3009 authorization.
3134
+ * `PermitTransferFrom` instead of an EIP-3009 authorization.
5473
3135
  */
5474
3136
  getDefaultWethSponsoredCallback(onApproved) {
5475
3137
  if (!onApproved && this.cachedWethSponsoredCallback)
5476
3138
  return this.cachedWethSponsoredCallback;
5477
3139
  const provider = this.requireConnectedProvider();
5478
3140
  const owner = this.state.walletAddress;
5479
- const callback = makeSponsoredTokenCallback({
3141
+ const callback = makeSponsoredWethCallback({
5480
3142
  apiKey: this.apiKey,
5481
3143
  baseUrl: this.routingApiBaseUrl,
5482
3144
  ownerAddress: owner,
@@ -5485,15 +3147,14 @@ var OwneySDK = class {
5485
3147
  // Casts work around viem's chain-narrowed Client vs the generic
5486
3148
  // PublicClient/WalletClient param types — structurally identical at
5487
3149
  // runtime, but the two share a name TS treats as unrelated.
5488
- getPublicClient: (cid) => this.getPaidRpcClient(cid),
5489
- getWalletChainClient: (cid) => (0, import_viem12.createPublicClient)({
3150
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
5490
3151
  chain: VIEM_CHAIN2[cid],
5491
- transport: (0, import_viem12.custom)(provider)
3152
+ transport: (0, import_viem6.custom)(provider)
5492
3153
  }),
5493
- getWalletClient: (cid) => (0, import_viem12.createWalletClient)({
3154
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
5494
3155
  account: owner,
5495
3156
  chain: VIEM_CHAIN2[cid],
5496
- transport: (0, import_viem12.custom)(provider)
3157
+ transport: (0, import_viem6.custom)(provider)
5497
3158
  })
5498
3159
  });
5499
3160
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -5524,10 +3185,12 @@ var OwneySDK = class {
5524
3185
  this.orgAgentConfigPromise = fetchOrgAgentConfig(
5525
3186
  this.apiKey,
5526
3187
  this.routingApiBaseUrl
5527
- ).then((config) => {
5528
- this.orgAgentConfig = config;
5529
- return config;
5530
- });
3188
+ ).then(
3189
+ (config) => {
3190
+ this.orgAgentConfig = config;
3191
+ return config;
3192
+ }
3193
+ );
5531
3194
  }
5532
3195
  return this.orgAgentConfigPromise;
5533
3196
  }
@@ -5567,14 +3230,7 @@ var OwneySDK = class {
5567
3230
  this.routingApiBaseUrl
5568
3231
  );
5569
3232
  this.disabledAgents.clear();
5570
- for (const {
5571
- key: key2,
5572
- agent_type,
5573
- is_enabled,
5574
- is_configured
5575
- } of agentKeys) {
5576
- const configured = is_configured ?? Boolean(key2);
5577
- if (!configured) continue;
3233
+ for (const { key: key2, agent_type, is_enabled } of agentKeys) {
5578
3234
  const agent = this.createAgent(agent_type, key2);
5579
3235
  if (!agent) continue;
5580
3236
  this.agents.set(agent_type, agent);
@@ -5598,23 +3254,7 @@ var OwneySDK = class {
5598
3254
  }
5599
3255
  createAgent(agentId, key2) {
5600
3256
  if (agentId === "zyfai") {
5601
- if (!key2) return null;
5602
- return new ZyfaiAgent(
5603
- key2,
5604
- this.zyfaiRpcUrls ? resolveRpcUrls(
5605
- this.zyfaiRpcUrls,
5606
- this.apiKey,
5607
- this.routingApiBaseUrl
5608
- ) : this.rpcUrls,
5609
- this.referralSource
5610
- );
5611
- }
5612
- if (agentId === "yieldseeker") {
5613
- return new YieldseekerAgent(this.apiKey, {
5614
- auth: { origin: this.yieldseekerSiweOrigin },
5615
- baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl),
5616
- rpcUrls: this.rpcUrls
5617
- });
3257
+ return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
5618
3258
  }
5619
3259
  return null;
5620
3260
  }
@@ -5660,10 +3300,9 @@ var OwneySDK = class {
5660
3300
  * If provided, ALL specified agents must support the chainId or the call
5661
3301
  * throws before activating any agent.
5662
3302
  */
5663
- async activateAgent(chainId, agentId, asset) {
3303
+ async activateAgent(chainId, agentId) {
5664
3304
  const state = this.requireState();
5665
3305
  await this.ensureAgentsInitialized();
5666
- this.assertActivationSession(state);
5667
3306
  if (agentId !== void 0) {
5668
3307
  if (agentId.length === 0) {
5669
3308
  throw new OwneyError(
@@ -5697,7 +3336,7 @@ var OwneySDK = class {
5697
3336
  this.activeAgents.add(id);
5698
3337
  }
5699
3338
  state.chainId = chainId;
5700
- await this.activateAgentsInTurn(agents, state, chainId, asset);
3339
+ await this.activateAgentsInTurn(agents, state, chainId);
5701
3340
  return;
5702
3341
  }
5703
3342
  const compatible = [...this.agents.values()].filter(
@@ -5718,12 +3357,7 @@ var OwneySDK = class {
5718
3357
  const enabledCompatible = compatible.filter(
5719
3358
  (agent) => !this.isAgentDisabled(agent.id)
5720
3359
  );
5721
- await this.activateAgentsInTurn(enabledCompatible, state, chainId, asset);
5722
- }
5723
- assertActivationSession(state) {
5724
- if (this.state !== state) {
5725
- throw new OwneyError("NOT_CONNECTED", "Wallet connection changed. Please try again.");
5726
- }
3360
+ await this.activateAgentsInTurn(enabledCompatible, state, chainId);
5727
3361
  }
5728
3362
  /**
5729
3363
  * Activate agents ONE AT A TIME, each followed by its org policy.
@@ -5738,51 +3372,26 @@ var OwneySDK = class {
5738
3372
  * Serializing costs no real wall-clock: the user can only approve one prompt
5739
3373
  * at a time anyway.
5740
3374
  *
5741
- * Stop at the first failure so a canceled sign-in does not open another
5742
- * agent's wallet prompt. Report any earlier successes for diagnostics; the
5743
- * app discards the session when the complete sign-in does not succeed.
3375
+ * Every agent is attempted even if an earlier one fails, so one declined
3376
+ * signature can't deny the remaining agents their turn. The first failure is
3377
+ * rethrown (matching the previous `Promise.all` rejection) once all agents
3378
+ * have had a chance to activate.
5744
3379
  */
5745
- async activateAgentsInTurn(agents, state, chainId, asset) {
3380
+ async activateAgentsInTurn(agents, state, chainId) {
5746
3381
  let firstError = null;
5747
- const activatedAgentIds = [];
5748
- const failedAgents = [];
5749
3382
  for (const agent of agents) {
5750
- this.assertActivationSession(state);
5751
3383
  try {
5752
- await agent.activateAgent(state, chainId, asset);
5753
- this.assertActivationSession(state);
3384
+ await agent.activateAgent(state, chainId);
5754
3385
  await this.applyOrgPolicyTo(agent, state, chainId);
5755
- this.assertActivationSession(state);
5756
- activatedAgentIds.push(agent.id);
5757
3386
  } catch (error) {
5758
- this.assertActivationSession(state);
5759
- 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.";
5760
- failedAgents.push({
5761
- agentId: agent.id,
5762
- code: error instanceof OwneyError ? error.code : void 0,
5763
- message,
5764
- ...error instanceof OwneyError && error.details ? { details: error.details } : {}
5765
- });
5766
3387
  if (firstError === null) {
5767
3388
  firstError = error;
5768
3389
  } else {
5769
3390
  console.error(`activateAgent(${agent.id}) failed:`, error);
5770
3391
  }
5771
- break;
5772
3392
  }
5773
3393
  }
5774
- if (firstError === null) return;
5775
- if (activatedAgentIds.length === 0) throw firstError;
5776
- const failedAgentIds = failedAgents.map(({ agentId }) => agentId);
5777
- const activeNames = activatedAgentIds.map(this.formatAgentName).join(", ");
5778
- const failureMessages = failedAgents.map(
5779
- ({ agentId, message }) => `${this.formatAgentName(agentId)} activation failed: ${message}`
5780
- ).join(" ");
5781
- throw new OwneyError(
5782
- "AGENT_ACTIVATION_PARTIAL_FAILURE",
5783
- `${activeNames} activated. ${failureMessages}`,
5784
- { activatedAgentIds, failedAgentIds, failures: failedAgents }
5785
- );
3394
+ if (firstError !== null) throw firstError;
5786
3395
  }
5787
3396
  /**
5788
3397
  * Deposit into a specific agent, or distribute across all eligible agents.
@@ -5792,8 +3401,7 @@ var OwneySDK = class {
5792
3401
  * @param options.asset - Asset symbol to deposit (e.g. "USDC")
5793
3402
  * @param options.depositCallback - Callback that performs the token transfer and returns a tx hash.
5794
3403
  * When agentId is omitted, this callback is invoked once per eligible agent with that agent's
5795
- * split amount and smart wallet address. Default sponsored deposits batch
5796
- * all shares into one signature; custom callbacks still run once per agent.
3404
+ * split amount and smart wallet address — expect multiple wallet prompts.
5797
3405
  * @param options.agentId - Optional explicit target. Otherwise split equally,
5798
3406
  * or fund remaining agents when a recovery deposit cannot meet every minimum.
5799
3407
  * @returns {OwneyDepositResult} for a single agent, or {OwneyMultiDepositResult} with per-agent results
@@ -5878,40 +3486,6 @@ var OwneySDK = class {
5878
3486
  }
5879
3487
  );
5880
3488
  }
5881
- const batchTransfer = getDepositBatchTransfer(effectiveCallback);
5882
- if (!depositCallback && batchTransfer) {
5883
- return runAgentDepositBatch(
5884
- chainId,
5885
- agentAmounts.map(({ agent, amount: amount2 }) => ({
5886
- id: agent.id,
5887
- amount: amount2,
5888
- run: (callback) => withFailureReporting(
5889
- this.apiKey,
5890
- agent.id,
5891
- () => agent.deposit(state, chainId, amount2, asset, callback),
5892
- this.routingApiBaseUrl
5893
- )
5894
- })),
5895
- async (cid, transfers) => {
5896
- try {
5897
- return await batchTransfer(cid, transfers);
5898
- } catch (error) {
5899
- if (!(error instanceof OwneyError) || error.code !== "PERMIT2_APPROVAL_REQUIRED")
5900
- throw error;
5901
- const requiredAmount = transfers.reduce(
5902
- (sum, transfer) => sum + BigInt(transfer.amount),
5903
- 0n
5904
- );
5905
- await this.approvePermit2(
5906
- asset,
5907
- requiredAmount,
5908
- cid
5909
- );
5910
- return batchTransfer(cid, transfers);
5911
- }
5912
- }
5913
- );
5914
- }
5915
3489
  const agentResults = {};
5916
3490
  for (const [
5917
3491
  index,
@@ -5949,12 +3523,10 @@ var OwneySDK = class {
5949
3523
  * Invokes `agent.deposit` with the resolved sponsored callback, composing
5950
3524
  * two independent auto-recovery mechanisms:
5951
3525
  *
5952
- * 1. Missing Permit2 allowance outside the atomic Base-USDC path: when the
5953
- * app did not supply its own callback and the attempt fails with
5954
- * `PERMIT2_APPROVAL_REQUIRED`, this is the wallet's first Permit2 deposit
5955
- * for that token. Base USDC bundles a gasless ERC-2612 approval inside
5956
- * its sponsored deposit and never reaches this branch. Other tokens send
5957
- * the one-time user-paid Permit2 approval via `approvePermit2()` and
3526
+ * 1. Missing Permit2 allowance: when the app did not supply its own
3527
+ * callback and the attempt fails with `PERMIT2_APPROVAL_REQUIRED` on a
3528
+ * WETH deposit, this is the wallet's first gasless WETH deposit. We send
3529
+ * the one-time (user-paid) Permit2 approval via `approvePermit2()` and
5958
3530
  * retry the SAME sponsored attempt once. Bounded to one approval attempt
5959
3531
  * per call so a wallet/agent that keeps reporting the allowance as
5960
3532
  * missing can't loop forever. If `approvePermit2()` itself throws (e.g.
@@ -5990,16 +3562,12 @@ var OwneySDK = class {
5990
3562
  try {
5991
3563
  return await attempt(effectiveCallback);
5992
3564
  } catch (error) {
5993
- if (!approvalAttempted && appCallback === void 0 && (asset === "WETH" || asset === "USDC") && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
3565
+ if (!approvalAttempted && appCallback === void 0 && asset === "WETH" && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
5994
3566
  approvalAttempted = true;
5995
3567
  console.warn(
5996
- "[owney-sdk] First token deposit: sending one-time Permit2 approval..."
5997
- );
5998
- await this.approvePermit2(
5999
- asset,
6000
- BigInt(amount),
6001
- chainId
3568
+ "[owney-sdk] First WETH deposit: sending one-time Permit2 approval..."
6002
3569
  );
3570
+ await this.approvePermit2();
6003
3571
  continue;
6004
3572
  }
6005
3573
  if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
@@ -6037,10 +3605,10 @@ var OwneySDK = class {
6037
3605
  agent,
6038
3606
  amount: i === agents.length - 1 ? perAgent + remainder : perAgent
6039
3607
  }));
6040
- const valid2 = splits.filter(
3608
+ const valid = splits.filter(
6041
3609
  (s) => s.amount > 0n && (exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset))
6042
3610
  );
6043
- if (valid2.length === agents.length) {
3611
+ if (valid.length === agents.length) {
6044
3612
  return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
6045
3613
  }
6046
3614
  const targets = agentsRequiringActivation.length > 0 ? agentsRequiringActivation : agents;
@@ -6059,11 +3627,6 @@ var OwneySDK = class {
6059
3627
  )
6060
3628
  }));
6061
3629
  }
6062
- formatAgentName(agentId) {
6063
- if (agentId === "zyfai") return "Zyfai";
6064
- if (agentId === "yieldseeker") return "Yieldseeker";
6065
- return agentId;
6066
- }
6067
3630
  async validateMinDepositAmount(agent, state, chainId, asset, amount) {
6068
3631
  const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
6069
3632
  const parsedAmount = BigInt(amount);
@@ -6095,12 +3658,12 @@ var OwneySDK = class {
6095
3658
  (t) => t.chainId === chainId && t.asset.toLowerCase() === target
6096
3659
  );
6097
3660
  const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
6098
- const position2 = (balance.positions ?? []).find((p) => {
3661
+ const position = (balance.positions ?? []).find((p) => {
6099
3662
  const positionChain = p.chain.trim().toUpperCase();
6100
3663
  const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
6101
3664
  return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
6102
3665
  });
6103
- return !!token && Number(token.amount) > 0 || !!position2;
3666
+ return !!token && Number(token.amount) > 0 || !!position;
6104
3667
  } catch (error) {
6105
3668
  if (requireReliableRead) {
6106
3669
  throw new OwneyError(
@@ -6145,32 +3708,6 @@ var OwneySDK = class {
6145
3708
  }
6146
3709
  return eligible;
6147
3710
  }
6148
- /**
6149
- * Run owner-approved withdrawals before relayer-only withdrawals. Wallet
6150
- * approval is the only point at which the user can cancel the aggregate
6151
- * operation, so no relayer leg should commit before it has completed.
6152
- */
6153
- orderAgentsForWithdrawal(agents) {
6154
- return agents.map((agent, index) => ({ agent, index })).sort((left, right) => {
6155
- const approvalOrder = Number(Boolean(right.agent.withdrawalRequiresWalletApproval)) - Number(Boolean(left.agent.withdrawalRequiresWalletApproval));
6156
- return approvalOrder || left.index - right.index;
6157
- }).map(({ agent }) => agent);
6158
- }
6159
- isUserRejectedWithdrawal(error) {
6160
- let current = error;
6161
- const seen = /* @__PURE__ */ new Set();
6162
- while (current && typeof current === "object" && !seen.has(current)) {
6163
- seen.add(current);
6164
- const candidate = current;
6165
- if (candidate.code === 4001 || candidate.code === "4001") return true;
6166
- const message = [candidate.message, candidate.shortMessage].filter((value) => typeof value === "string").join(" ");
6167
- if (/user (?:rejected|denied)|rejected by user/i.test(message)) {
6168
- return true;
6169
- }
6170
- current = candidate.cause;
6171
- }
6172
- return false;
6173
- }
6174
3711
  // --- Fund operations ---
6175
3712
  /**
6176
3713
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
@@ -6182,14 +3719,7 @@ var OwneySDK = class {
6182
3719
  * @returns {AgentWithdrawResult} for a single agent, or {OwneyWithdrawResult} with per-agent results
6183
3720
  */
6184
3721
  async withdraw(options) {
6185
- const { asset, amount, agentId, onAgentResult } = options;
6186
- const notifyAgentResult = (id, result) => {
6187
- try {
6188
- onAgentResult?.(id, result);
6189
- } catch (error) {
6190
- console.warn("Withdrawal result observer failed:", error);
6191
- }
6192
- };
3722
+ const { asset, amount, agentId } = options;
6193
3723
  const state = this.requireState();
6194
3724
  const chainId = this.requireChainId();
6195
3725
  const token = asset;
@@ -6205,26 +3735,21 @@ var OwneySDK = class {
6205
3735
  if (agentId) {
6206
3736
  const agent = this.getAgent(agentId);
6207
3737
  this.validateAssetSupport(agent, chainId, asset);
6208
- const result = await withFailureReporting(
3738
+ return withFailureReporting(
6209
3739
  this.apiKey,
6210
3740
  agent.id,
6211
3741
  () => agent.withdraw(state, chainId, token, amount),
6212
3742
  this.routingApiBaseUrl
6213
3743
  );
6214
- notifyAgentResult(agent.id, result);
6215
- return result;
6216
3744
  }
6217
3745
  const eligibleAgents = this.getEligibleAgents(chainId, asset);
6218
- const withdrawalAgents = this.orderAgentsForWithdrawal(eligibleAgents);
6219
3746
  if (!amount) {
6220
3747
  const results2 = {};
6221
3748
  const agentErrors2 = {};
6222
- for (const agent of withdrawalAgents) {
3749
+ for (const agent of eligibleAgents) {
6223
3750
  try {
6224
3751
  results2[agent.id] = await agent.withdraw(state, chainId, token);
6225
- notifyAgentResult(agent.id, results2[agent.id]);
6226
3752
  } catch (err) {
6227
- if (this.isUserRejectedWithdrawal(err)) throw err;
6228
3753
  console.error(`withdraw failed for agent "${agent.id}":`, err);
6229
3754
  agentErrors2[agent.id] = err instanceof Error ? err.message : String(err);
6230
3755
  const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
@@ -6253,10 +3778,6 @@ var OwneySDK = class {
6253
3778
  }
6254
3779
  const requested = BigInt(amount);
6255
3780
  const aggregated = await this.getBalances();
6256
- const unavailableAgents = eligibleAgents.filter(
6257
- (agent) => !(agent.id in aggregated.agentBalances)
6258
- );
6259
- const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
6260
3781
  const balances = projectAgentBalancesForAsset(
6261
3782
  eligibleAgents,
6262
3783
  aggregated.agentBalances,
@@ -6265,18 +3786,7 @@ var OwneySDK = class {
6265
3786
  assetInfo.decimals
6266
3787
  );
6267
3788
  const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
6268
- if (totalAvailable === 0n && unavailableAgents.length > 0) {
6269
- throw new OwneyError(
6270
- "WITHDRAW_BALANCE_UNAVAILABLE",
6271
- `Cannot safely plan the withdrawal because balance data is unavailable for: ${unavailableAgentIds.join(", ")}.`,
6272
- {
6273
- asset,
6274
- unavailableAgents: unavailableAgentIds,
6275
- agentErrors: aggregated.agentErrors
6276
- }
6277
- );
6278
- }
6279
- if (totalAvailable < requested && unavailableAgents.length === 0) {
3789
+ if (totalAvailable < requested) {
6280
3790
  throw new OwneyError(
6281
3791
  "WITHDRAW_INSUFFICIENT_BALANCE",
6282
3792
  `Requested withdrawal "${amount}" exceeds available balance "${totalAvailable.toString()}" for asset "${asset}".`,
@@ -6287,7 +3797,6 @@ var OwneySDK = class {
6287
3797
  }
6288
3798
  );
6289
3799
  }
6290
- const plannedTarget = totalAvailable < requested ? totalAvailable : requested;
6291
3800
  const disabledBalances = balances.filter(
6292
3801
  (b) => this.isAgentDisabled(b.agent.id)
6293
3802
  );
@@ -6296,7 +3805,7 @@ var OwneySDK = class {
6296
3805
  );
6297
3806
  const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
6298
3807
  disabledBalances,
6299
- plannedTarget
3808
+ requested
6300
3809
  );
6301
3810
  const enabledTotal = enabledBalances.reduce((s, b) => s + b.balance, 0n);
6302
3811
  const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
@@ -6305,13 +3814,10 @@ var OwneySDK = class {
6305
3814
  planned: 0n
6306
3815
  }));
6307
3816
  const plans = [...disabledPlans, ...enabledPlans];
6308
- const orderedPlans = this.orderAgentsForWithdrawal(plans.map((p) => p.agent)).map((agent) => plans.find((plan) => plan.agent === agent));
6309
3817
  const results = {};
6310
- const agentErrors = {
6311
- ...aggregated.agentErrors ?? {}
6312
- };
6313
- for (let i = 0; i < orderedPlans.length; i++) {
6314
- const p = orderedPlans[i];
3818
+ const agentErrors = {};
3819
+ for (let i = 0; i < plans.length; i++) {
3820
+ const p = plans[i];
6315
3821
  if (p.planned === 0n) continue;
6316
3822
  try {
6317
3823
  results[p.agent.id] = await p.agent.withdraw(
@@ -6320,9 +3826,7 @@ var OwneySDK = class {
6320
3826
  token,
6321
3827
  p.planned.toString()
6322
3828
  );
6323
- notifyAgentResult(p.agent.id, results[p.agent.id]);
6324
3829
  } catch (err) {
6325
- if (this.isUserRejectedWithdrawal(err)) throw err;
6326
3830
  console.error(`withdraw failed for agent "${p.agent.id}":`, err);
6327
3831
  agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
6328
3832
  const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
@@ -6334,7 +3838,7 @@ var OwneySDK = class {
6334
3838
  );
6335
3839
  const failedAmount = p.planned;
6336
3840
  p.planned = 0n;
6337
- redistributeShare(orderedPlans, i, failedAmount);
3841
+ redistributeShare(plans, i, failedAmount);
6338
3842
  }
6339
3843
  }
6340
3844
  if (Object.keys(results).length === 0) {
@@ -6358,8 +3862,7 @@ var OwneySDK = class {
6358
3862
  requested: amount,
6359
3863
  withdrawn: withdrawn.toString(),
6360
3864
  partialResults: results,
6361
- agentErrors,
6362
- ...unavailableAgentIds.length > 0 ? { unavailableAgents: unavailableAgentIds } : {}
3865
+ agentErrors
6363
3866
  }
6364
3867
  );
6365
3868
  }
@@ -6377,10 +3880,7 @@ var OwneySDK = class {
6377
3880
  if (agentId) {
6378
3881
  const agent = this.getAgent(agentId);
6379
3882
  const result = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
6380
- return {
6381
- ...result,
6382
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
6383
- };
3883
+ return result;
6384
3884
  }
6385
3885
  let totalBalance = 0;
6386
3886
  const results = {};
@@ -6388,13 +3888,7 @@ var OwneySDK = class {
6388
3888
  const balanceResults = await Promise.allSettled(
6389
3889
  entries.map(async ([id, agent]) => {
6390
3890
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
6391
- return [
6392
- id,
6393
- {
6394
- ...b,
6395
- balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
6396
- }
6397
- ];
3891
+ return [id, b];
6398
3892
  })
6399
3893
  );
6400
3894
  let successCount = 0;
@@ -6416,7 +3910,6 @@ var OwneySDK = class {
6416
3910
  const retryDelay = rateLimitDelay(reason);
6417
3911
  if (retryDelay !== void 0) agentRetryAt[agentId2] = Date.now() + retryDelay;
6418
3912
  agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
6419
- console.error(`[owney-sdk] Balance fetch failed for agent "${agentId2}":`, reason);
6420
3913
  }
6421
3914
  if (successCount === 0) {
6422
3915
  throw new OwneyError(
@@ -6595,10 +4088,7 @@ var OwneySDK = class {
6595
4088
  Promise.all(
6596
4089
  entries.map(async ([id, agent]) => {
6597
4090
  const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
6598
- return [
6599
- id,
6600
- balanceForApyScope(b, chainId, tokenSymbol)
6601
- ];
4091
+ return [id, balanceForApyScope(b, chainId, tokenSymbol)];
6602
4092
  })
6603
4093
  )
6604
4094
  ]);
@@ -6759,95 +4249,51 @@ var OwneySDK = class {
6759
4249
  return pending;
6760
4250
  }
6761
4251
  /**
6762
- * User-paid approval of Permit2 on the selected token for the active chain.
6763
- * Grants the maximum ERC20 allowance so later deposits do not require another
6764
- * approval. Resolves after one confirmation so the subsequent deposit attempt
6765
- * sees the new allowance. Deposit retries pass their captured chain id so a
6766
- * concurrent activation cannot redirect the approval to another network.
6767
- *
6768
- * @param requiredAmount Raw base-unit amount the pending deposit must cover.
6769
- * @param expectedChainId Chain captured by the deposit that requested approval.
4252
+ * One-time, user-paid approval of Permit2 on the sponsored WETH token for
4253
+ * the active chain. Required once per wallet per chain before gasless WETH
4254
+ * deposits; afterwards deposit() is signature-only. Resolves only after the
4255
+ * approval transaction is mined (1 confirmation), so a subsequent deposit()
4256
+ * will see the new allowance; throws if the transaction reverted.
6770
4257
  * @returns the approval transaction hash.
6771
4258
  */
6772
- async approvePermit2(asset = "WETH", requiredAmount = 0n, expectedChainId) {
4259
+ async approvePermit2(asset = "WETH") {
4260
+ void asset;
6773
4261
  const state = this.requireState();
6774
- const chainId = expectedChainId ?? this.requireChainId();
6775
- this.getEligibleAgents(chainId, asset, { excludeDisabled: true });
6776
- const token = sponsoredTokensFor(asset)[chainId];
4262
+ const chainId = this.requireChainId();
4263
+ this.validateAssetSupport(this.getAgent("zyfai"), chainId, "WETH");
4264
+ const token = SPONSORED_WETH_BY_CHAIN[chainId];
6777
4265
  if (!token) {
6778
4266
  throw new OwneyError(
6779
4267
  "CHAIN_UNSUPPORTED",
6780
- `No sponsored token on chain ${chainId}`
4268
+ `No sponsored WETH on chain ${chainId}`
6781
4269
  );
6782
4270
  }
6783
4271
  const provider = this.requireConnectedProvider();
6784
- const walletChainClient = (0, import_viem12.createPublicClient)({
6785
- chain: VIEM_CHAIN2[chainId],
6786
- transport: (0, import_viem12.custom)(provider)
6787
- });
6788
- const publicClient = this.getPaidRpcClient(chainId);
6789
- const approvalAmount = permit2ApprovalAmount(requiredAmount);
6790
- const wallet = (0, import_viem12.createWalletClient)({
4272
+ const wallet = (0, import_viem6.createWalletClient)({
6791
4273
  account: state.walletAddress,
6792
4274
  chain: VIEM_CHAIN2[chainId],
6793
- transport: (0, import_viem12.custom)(provider)
4275
+ transport: (0, import_viem6.custom)(provider)
6794
4276
  });
6795
- await ensureWalletOnChain(walletChainClient, wallet, chainId);
6796
4277
  const hash = await wallet.writeContract({
6797
4278
  address: token,
6798
4279
  abi: ERC20_ALLOWANCE_ABI,
6799
4280
  functionName: "approve",
6800
- args: [PERMIT2_ADDRESS, approvalAmount],
4281
+ args: [PERMIT2_ADDRESS, MAX_UINT256],
6801
4282
  account: state.walletAddress,
6802
4283
  chain: VIEM_CHAIN2[chainId]
6803
4284
  });
6804
- const receipt = await withPaidRpcDiagnostics(
6805
- () => publicClient.waitForTransactionReceipt({
6806
- hash,
6807
- confirmations: 1
6808
- }),
6809
- chainId,
6810
- "eth_getTransactionReceipt"
6811
- );
4285
+ const publicClient = (0, import_viem6.createPublicClient)({
4286
+ chain: VIEM_CHAIN2[chainId],
4287
+ transport: (0, import_viem6.custom)(provider)
4288
+ });
4289
+ const receipt = await publicClient.waitForTransactionReceipt({
4290
+ hash,
4291
+ confirmations: 1
4292
+ });
6812
4293
  if (receipt.status !== "success") {
6813
4294
  throw new Error(`Permit2 approval reverted (tx ${hash})`);
6814
4295
  }
6815
- let observedAllowance = 0n;
6816
- let verificationError;
6817
- for (let attempt = 0; attempt < PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS; attempt += 1) {
6818
- try {
6819
- observedAllowance = await readPermit2Allowance(
6820
- publicClient,
6821
- token,
6822
- state.walletAddress,
6823
- attempt === 0 ? receipt.blockNumber : void 0
6824
- );
6825
- verificationError = void 0;
6826
- if (observedAllowance >= requiredAmount) return hash;
6827
- } catch (error) {
6828
- verificationError = error;
6829
- }
6830
- if (attempt + 1 < PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS) {
6831
- await new Promise(
6832
- (resolve) => setTimeout(resolve, PERMIT2_ALLOWANCE_VERIFY_DELAY_MS)
6833
- );
6834
- }
6835
- }
6836
- throw new OwneyError(
6837
- "PERMIT2_APPROVAL_REQUIRED",
6838
- "Permit2 approval was confirmed, but the required token allowance was not observable.",
6839
- {
6840
- approvalConfirmed: true,
6841
- approvalTxHash: hash,
6842
- owner: state.walletAddress,
6843
- token,
6844
- spender: PERMIT2_ADDRESS,
6845
- chainId,
6846
- requiredAmount: requiredAmount.toString(),
6847
- observedAllowance: observedAllowance.toString(),
6848
- ...verificationError instanceof Error ? { verificationError: verificationError.message } : {}
6849
- }
6850
- );
4296
+ return hash;
6851
4297
  }
6852
4298
  // --- Discovery (no wallet required) ---
6853
4299
  /**
@@ -6875,9 +4321,7 @@ var OwneySDK = class {
6875
4321
  return this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
6876
4322
  }
6877
4323
  const results = {};
6878
- const agentEntries = [...this.agents.entries()].filter(
6879
- ([id]) => !this.isAgentDisabled(id)
6880
- );
4324
+ const agentEntries = [...this.agents.entries()];
6881
4325
  const apyResults = await Promise.all(
6882
4326
  agentEntries.map(async ([id, agent]) => {
6883
4327
  const apy = await this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
@@ -6952,13 +4396,13 @@ var OwneySDK = class {
6952
4396
  };
6953
4397
 
6954
4398
  // src/agents/zyfai/zyfai.siwx.ts
6955
- var import_viem13 = require("viem");
6956
- var import_siwe2 = require("siwe");
4399
+ var import_viem7 = require("viem");
4400
+ var import_siwe = require("siwe");
6957
4401
  var import_sdk2 = require("@zyfai/sdk");
6958
4402
 
6959
4403
  // src/agents/zyfai/zyfai.siwx-cache.ts
6960
- var KEY_PREFIX4 = "owney.siwx.session";
6961
- var storage4 = () => {
4404
+ var KEY_PREFIX2 = "owney.siwx.session";
4405
+ var storage2 = () => {
6962
4406
  if (typeof window === "undefined") return null;
6963
4407
  try {
6964
4408
  return window.localStorage;
@@ -6966,8 +4410,8 @@ var storage4 = () => {
6966
4410
  return null;
6967
4411
  }
6968
4412
  };
6969
- var buildKey3 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}`;
6970
- var legacyKeyPrefix2 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}:`;
4413
+ var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
4414
+ var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
6971
4415
  var memorySiwxSessions = /* @__PURE__ */ new Map();
6972
4416
  var readLegacySiwxSession = (store, address) => {
6973
4417
  if (!store) return null;
@@ -6998,17 +4442,17 @@ var readLegacySiwxSession = (store, address) => {
6998
4442
  };
6999
4443
  var readSiwxSession = (address, chainId) => {
7000
4444
  if (typeof window === "undefined") return null;
7001
- const key2 = buildKey3(address);
7002
- const store = storage4();
7003
- let raw2 = null;
4445
+ const key2 = buildKey2(address);
4446
+ const store = storage2();
4447
+ let raw = null;
7004
4448
  try {
7005
- raw2 = store?.getItem(key2) ?? null;
4449
+ raw = store?.getItem(key2) ?? null;
7006
4450
  } catch {
7007
- raw2 = null;
4451
+ raw = null;
7008
4452
  }
7009
- if (raw2) {
4453
+ if (raw) {
7010
4454
  try {
7011
- return JSON.parse(raw2);
4455
+ return JSON.parse(raw);
7012
4456
  } catch {
7013
4457
  memorySiwxSessions.delete(key2);
7014
4458
  try {
@@ -7027,18 +4471,18 @@ var readSiwxSession = (address, chainId) => {
7027
4471
  };
7028
4472
  var writeSiwxSession = (address, _chainId, session) => {
7029
4473
  if (typeof window === "undefined") return;
7030
- const key2 = buildKey3(address);
4474
+ const key2 = buildKey2(address);
7031
4475
  memorySiwxSessions.set(key2, session);
7032
- const store = storage4();
4476
+ const store = storage2();
7033
4477
  try {
7034
4478
  store?.setItem(key2, JSON.stringify(session));
7035
4479
  } catch {
7036
4480
  }
7037
4481
  };
7038
4482
  var clearSiwxSession = (address, _chainId) => {
7039
- const key2 = buildKey3(address);
4483
+ const key2 = buildKey2(address);
7040
4484
  memorySiwxSessions.delete(key2);
7041
- const store = storage4();
4485
+ const store = storage2();
7042
4486
  try {
7043
4487
  store?.removeItem(key2);
7044
4488
  } catch {
@@ -7078,8 +4522,8 @@ function buildSIWXConfig(deps) {
7078
4522
  statement: STATEMENT,
7079
4523
  issuedAt,
7080
4524
  toString() {
7081
- return new import_siwe2.SiweMessage({
7082
- address: (0, import_viem13.getAddress)(accountAddress),
4525
+ return new import_siwe.SiweMessage({
4526
+ address: (0, import_viem7.getAddress)(accountAddress),
7083
4527
  chainId: numericChainId(chainId),
7084
4528
  domain,
7085
4529
  uri,
@@ -7121,7 +4565,7 @@ function buildSIWXConfig(deps) {
7121
4565
  const persistSession = async (session) => {
7122
4566
  const address = session.data.accountAddress;
7123
4567
  const id = numericChainId(session.data.chainId);
7124
- const message = new import_siwe2.SiweMessage(session.message);
4568
+ const message = new import_siwe.SiweMessage(session.message);
7125
4569
  const login = await post("/auth/login", {
7126
4570
  message,
7127
4571
  signature: session.signature,
@@ -7171,7 +4615,6 @@ function createOwneySIWX(config) {
7171
4615
  NotConnectedError,
7172
4616
  OwneyError,
7173
4617
  OwneySDK,
7174
- YieldseekerAgent,
7175
4618
  createOwneySIWX,
7176
4619
  setOwneyDebug
7177
4620
  });