@owney/sdk 0.7.25-beta.3 → 0.7.25-beta.6

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
@@ -159,6 +159,34 @@ function rateLimitDelay(error, now = Date.now()) {
159
159
  }
160
160
 
161
161
  // 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
+ }
162
190
  var AgentReads = class {
163
191
  inFlight = /* @__PURE__ */ new Map();
164
192
  cooldowns = /* @__PURE__ */ new Map();
@@ -166,14 +194,15 @@ var AgentReads = class {
166
194
  clearInFlight() {
167
195
  this.inFlight.clear();
168
196
  }
169
- limited(agentId, until) {
197
+ limited(agentId, until, diagnostics) {
170
198
  return new OwneyError(
171
199
  "AGENT_RATE_LIMITED",
172
200
  "Too many requests. Please wait before trying again.",
173
201
  {
174
202
  statusCode: 429,
175
203
  retryAt: until,
176
- retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3))
204
+ retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3)),
205
+ ...diagnostics
177
206
  },
178
207
  agentId
179
208
  );
@@ -181,7 +210,9 @@ var AgentReads = class {
181
210
  run(agentId, key2, fetch2) {
182
211
  const cooldown = this.cooldowns.get(agentId);
183
212
  if (cooldown && cooldown.until > Date.now()) {
184
- return Promise.reject(this.limited(agentId, cooldown.until));
213
+ return Promise.reject(
214
+ this.limited(agentId, cooldown.until, cooldown.diagnostics)
215
+ );
185
216
  }
186
217
  const requestKey = JSON.stringify([agentId, key2]);
187
218
  const existing = this.inFlight.get(requestKey);
@@ -202,8 +233,9 @@ var AgentReads = class {
202
233
  Math.min(3e4 * 2 ** (failures - 1), 3e5)
203
234
  );
204
235
  const until = Math.max(previous?.until ?? 0, Date.now() + delay);
205
- this.cooldowns.set(agentId, { until, failures });
206
- throw this.limited(agentId, until);
236
+ const diagnostics = rateLimitDiagnostics(error);
237
+ this.cooldowns.set(agentId, { until, failures, diagnostics });
238
+ throw this.limited(agentId, until, diagnostics);
207
239
  }
208
240
  ).finally(() => {
209
241
  if (this.inFlight.get(requestKey) === promise)
@@ -216,7 +248,7 @@ var AgentReads = class {
216
248
 
217
249
  // src/agents/zyfai/zyfai.agent.ts
218
250
  var import_sdk = require("@zyfai/sdk");
219
- var import_viem = require("viem");
251
+ var import_viem2 = require("viem");
220
252
  var import_chains = require("viem/chains");
221
253
 
222
254
  // src/types/config.ts
@@ -1097,15 +1129,128 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
1097
1129
  return !protocolListsEqual(current.protocols, desiredProtocols);
1098
1130
  }
1099
1131
 
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
+ var DEFAULT_RPC_URLS = {
1137
+ 1: "https://eth-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
1138
+ 8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
1139
+ 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
1140
+ };
1141
+ function resolveRpcUrl(rpcUrls, chainId) {
1142
+ const url = rpcUrls?.[chainId]?.trim();
1143
+ if (url) return url;
1144
+ return DEFAULT_RPC_URLS[chainId];
1145
+ }
1146
+ function resolveRpcUrls(rpcUrls) {
1147
+ return {
1148
+ 1: resolveRpcUrl(rpcUrls, 1),
1149
+ 8453: resolveRpcUrl(rpcUrls, 8453),
1150
+ 42161: resolveRpcUrl(rpcUrls, 42161)
1151
+ };
1152
+ }
1153
+ function createPaidRpcClient(chain, rpcUrls) {
1154
+ const url = resolveRpcUrl(
1155
+ rpcUrls,
1156
+ chain.id
1157
+ );
1158
+ return (0, import_viem.createPublicClient)({
1159
+ chain,
1160
+ transport: (0, import_viem.http)(url, {
1161
+ retryCount: PAID_RPC_RETRY_COUNT,
1162
+ retryDelay: PAID_RPC_RETRY_DELAY_MS
1163
+ })
1164
+ });
1165
+ }
1166
+ function headerValue(error, name) {
1167
+ const seen = /* @__PURE__ */ new Set();
1168
+ let value;
1169
+ function visit(candidate, depth = 0) {
1170
+ if (value || depth > 6 || !candidate || typeof candidate !== "object")
1171
+ return;
1172
+ if (seen.has(candidate)) return;
1173
+ seen.add(candidate);
1174
+ const record = candidate;
1175
+ const headers = record.headers;
1176
+ const found = typeof headers?.get === "function" ? headers.get(name) : headers?.[name] ?? headers?.[name.toLowerCase()];
1177
+ if (typeof found === "string" && found) {
1178
+ value = found;
1179
+ return;
1180
+ }
1181
+ for (const key2 of ["cause", "details", "response", "error"])
1182
+ visit(record[key2], depth + 1);
1183
+ }
1184
+ visit(error);
1185
+ return value;
1186
+ }
1187
+ function statusCode(error) {
1188
+ const seen = /* @__PURE__ */ new Set();
1189
+ let status;
1190
+ function visit(candidate, depth = 0) {
1191
+ if (status || depth > 6 || !candidate || typeof candidate !== "object")
1192
+ return;
1193
+ if (seen.has(candidate)) return;
1194
+ seen.add(candidate);
1195
+ const record = candidate;
1196
+ for (const key2 of ["status", "statusCode"]) {
1197
+ const parsed = Number(record[key2]);
1198
+ if (Number.isInteger(parsed) && parsed >= 100 && parsed <= 599) {
1199
+ status = parsed;
1200
+ return;
1201
+ }
1202
+ }
1203
+ for (const key2 of ["cause", "details", "response", "error"])
1204
+ visit(record[key2], depth + 1);
1205
+ }
1206
+ visit(error);
1207
+ return status;
1208
+ }
1209
+ function paidRpcError(error, chainId, rpcMethod, agentId) {
1210
+ const delay = rateLimitDelay(error);
1211
+ const providerRequestId = headerValue(error, "x-alchemy-request-id") ?? headerValue(error, "x-request-id");
1212
+ if (delay === void 0) {
1213
+ return new OwneyError(
1214
+ "AGENT_API_ERROR",
1215
+ "The blockchain RPC request failed.",
1216
+ {
1217
+ rpcSource: "paid-rpc",
1218
+ chainId,
1219
+ rpcMethod,
1220
+ ...statusCode(error) ? { statusCode: statusCode(error) } : {},
1221
+ ...providerRequestId ? { providerRequestId } : {}
1222
+ },
1223
+ agentId
1224
+ );
1225
+ }
1226
+ const retryAt = Date.now() + delay;
1227
+ return new OwneyError(
1228
+ "AGENT_RATE_LIMITED",
1229
+ "The blockchain RPC is rate limited. Please wait before trying again.",
1230
+ {
1231
+ rpcSource: "paid-rpc",
1232
+ chainId,
1233
+ rpcMethod,
1234
+ statusCode: 429,
1235
+ retryAt,
1236
+ retryAfterSeconds: Math.max(0, Math.ceil(delay / 1e3)),
1237
+ ...providerRequestId ? { providerRequestId } : {}
1238
+ },
1239
+ agentId
1240
+ );
1241
+ }
1242
+ async function withPaidRpcDiagnostics(operation, chainId, rpcMethod, agentId) {
1243
+ try {
1244
+ return await operation();
1245
+ } catch (error) {
1246
+ throw paidRpcError(error, chainId, rpcMethod, agentId);
1247
+ }
1248
+ }
1249
+
1100
1250
  // src/agents/zyfai/zyfai.agent.ts
1101
- var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem.parseAbi)([
1251
+ var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem2.parseAbi)([
1102
1252
  "function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
1103
1253
  ]);
1104
- var DEFAULT_ZYFAI_RPC_URLS = {
1105
- 8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
1106
- 42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
1107
- 1: "https://eth-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
1108
- };
1109
1254
  var WETH_ADDRESS_BY_CHAIN = {
1110
1255
  8453: "0x4200000000000000000000000000000000000006",
1111
1256
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
@@ -1171,7 +1316,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1171
1316
  earningsSnapshot = null;
1172
1317
  earningsGeneration = 0;
1173
1318
  constructor(apiKey, rpcUrls, referralSource) {
1174
- this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
1319
+ this.rpcUrls = resolveRpcUrls(rpcUrls);
1175
1320
  this.sdk = new import_sdk.ZyfaiSDK({
1176
1321
  apiKey,
1177
1322
  rpcUrls: this.rpcUrls,
@@ -1185,10 +1330,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
1185
1330
  getPublicClient(chainId) {
1186
1331
  const cached = this.publicClients.get(chainId);
1187
1332
  if (cached) return cached;
1188
- const client = (0, import_viem.createPublicClient)({
1189
- chain: VIEM_CHAIN[chainId],
1190
- transport: (0, import_viem.http)(this.rpcUrls[chainId])
1191
- });
1333
+ const client = createPaidRpcClient(
1334
+ VIEM_CHAIN[chainId],
1335
+ this.rpcUrls
1336
+ );
1192
1337
  this.publicClients.set(chainId, client);
1193
1338
  return client;
1194
1339
  }
@@ -2156,7 +2301,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2156
2301
  };
2157
2302
 
2158
2303
  // src/agents/yieldseeker/yieldseeker.agent.ts
2159
- var import_viem6 = require("viem");
2304
+ var import_viem7 = require("viem");
2160
2305
  var import_chains3 = require("viem/chains");
2161
2306
 
2162
2307
  // src/lib/chain-guard.ts
@@ -2195,7 +2340,7 @@ async function ensureWalletOnChain(pub, wallet, expected) {
2195
2340
  }
2196
2341
 
2197
2342
  // src/lib/transfer-auth.ts
2198
- var import_viem2 = require("viem");
2343
+ var import_viem3 = require("viem");
2199
2344
 
2200
2345
  // src/lib/sponsor-client.ts
2201
2346
  var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
@@ -2311,7 +2456,7 @@ async function postSponsorBatchTransfer(input) {
2311
2456
  }
2312
2457
 
2313
2458
  // src/lib/permit2.ts
2314
- var import_viem3 = require("viem");
2459
+ var import_viem4 = require("viem");
2315
2460
  var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2316
2461
  var MAX_UINT256 = 2n ** 256n - 1n;
2317
2462
  function permit2ApprovalAmount(requiredAmount) {
@@ -2352,14 +2497,15 @@ var ERC20_ALLOWANCE_ABI = [
2352
2497
  function randomPermit2Nonce() {
2353
2498
  const bytes = new Uint8Array(32);
2354
2499
  globalThis.crypto.getRandomValues(bytes);
2355
- return BigInt((0, import_viem3.bytesToHex)(bytes));
2500
+ return BigInt((0, import_viem4.bytesToHex)(bytes));
2356
2501
  }
2357
- async function readPermit2Allowance(publicClient, token, owner) {
2502
+ async function readPermit2Allowance(publicClient, token, owner, blockNumber) {
2358
2503
  return publicClient.readContract({
2359
2504
  address: token,
2360
2505
  abi: ERC20_ALLOWANCE_ABI,
2361
2506
  functionName: "allowance",
2362
- args: [owner, PERMIT2_ADDRESS]
2507
+ args: [owner, PERMIT2_ADDRESS],
2508
+ ...blockNumber === void 0 ? {} : { blockNumber }
2363
2509
  });
2364
2510
  }
2365
2511
  async function readErc20Balance(publicClient, token, owner) {
@@ -2394,7 +2540,7 @@ function makeVerificationAwareDepositCallback(implementation) {
2394
2540
 
2395
2541
  // src/agents/yieldseeker/yieldseeker.auth.ts
2396
2542
  var import_siwe = require("siwe");
2397
- var import_viem4 = require("viem");
2543
+ var import_viem5 = require("viem");
2398
2544
  var import_chains2 = require("viem/chains");
2399
2545
 
2400
2546
  // src/agents/yieldseeker/yieldseeker.auth-cache.ts
@@ -2507,7 +2653,7 @@ function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
2507
2653
  return new import_siwe.SiweMessage({
2508
2654
  scheme: url.protocol.slice(0, -1),
2509
2655
  domain: url.host,
2510
- address: (0, import_viem4.getAddress)(address),
2656
+ address: (0, import_viem5.getAddress)(address),
2511
2657
  uri: url.origin,
2512
2658
  version: "1",
2513
2659
  chainId,
@@ -2593,15 +2739,15 @@ var YieldseekerAuth = class {
2593
2739
  clearYieldseekerSession(state.walletAddress, chainId);
2594
2740
  }
2595
2741
  async sign(state, chainId) {
2596
- const account = (0, import_viem4.getAddress)(state.walletAddress);
2597
- const publicClient = (0, import_viem4.createPublicClient)({
2742
+ const account = (0, import_viem5.getAddress)(state.walletAddress);
2743
+ const publicClient = (0, import_viem5.createPublicClient)({
2598
2744
  chain: import_chains2.base,
2599
- transport: (0, import_viem4.custom)(state.provider)
2745
+ transport: (0, import_viem5.custom)(state.provider)
2600
2746
  });
2601
- const walletClient = (0, import_viem4.createWalletClient)({
2747
+ const walletClient = (0, import_viem5.createWalletClient)({
2602
2748
  account,
2603
2749
  chain: import_chains2.base,
2604
- transport: (0, import_viem4.custom)(state.provider)
2750
+ transport: (0, import_viem5.custom)(state.provider)
2605
2751
  });
2606
2752
  await ensureWalletOnChain(
2607
2753
  publicClient,
@@ -2767,7 +2913,7 @@ var YieldseekerApiClient = class {
2767
2913
  };
2768
2914
 
2769
2915
  // src/agents/yieldseeker/yieldseeker.mapper.ts
2770
- var import_viem5 = require("viem");
2916
+ var import_viem6 = require("viem");
2771
2917
 
2772
2918
  // src/lib/helpers/snapshot-apy.ts
2773
2919
  var DAY_MS = 864e5;
@@ -2834,10 +2980,10 @@ function raw(value, endpoint) {
2834
2980
  return BigInt(value);
2835
2981
  }
2836
2982
  function decimal(value, decimals, endpoint) {
2837
- return (0, import_viem5.formatUnits)(raw(value, endpoint), decimals);
2983
+ return (0, import_viem6.formatUnits)(raw(value, endpoint), decimals);
2838
2984
  }
2839
2985
  function usd(rawAmount, decimals, price) {
2840
- return Number((0, import_viem5.formatUnits)(rawAmount, decimals)) * price;
2986
+ return Number((0, import_viem6.formatUnits)(rawAmount, decimals)) * price;
2841
2987
  }
2842
2988
  function percent(value) {
2843
2989
  const result = Number(value);
@@ -2863,7 +3009,7 @@ function assetAddressValue(record, address) {
2863
3009
  }
2864
3010
  function position(value, asset, baseAssetDecimals) {
2865
3011
  const option = value?.yieldOption;
2866
- if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem5.isAddress)(option.address)) {
3012
+ if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem6.isAddress)(option.address)) {
2867
3013
  return invalid("yield positions", "missing vault metadata");
2868
3014
  }
2869
3015
  return {
@@ -2944,7 +3090,7 @@ function mapYieldseekerEarnings(contexts) {
2944
3090
  chain: "BASE",
2945
3091
  chainId: 8453,
2946
3092
  asset: context.asset,
2947
- amount: (0, import_viem5.formatUnits)(amount, context.snapshot.baseAssetDecimals)
3093
+ amount: (0, import_viem6.formatUnits)(amount, context.snapshot.baseAssetDecimals)
2948
3094
  });
2949
3095
  lifetimeEarnings += usd(
2950
3096
  amount,
@@ -3211,6 +3357,9 @@ var YIELDSEEKER_USERNAME_PREFIX = "owney_";
3211
3357
  var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
3212
3358
  var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
3213
3359
  var YIELDSEEKER_YIELD_OPTIONS_CACHE_MS = 6e4;
3360
+ var YIELDSEEKER_AGENT_LIST_CACHE_MS = 6e4;
3361
+ var YIELDSEEKER_PORTFOLIO_CACHE_MS = 3e4;
3362
+ var YIELDSEEKER_ACTIVITY_CACHE_MS = 6e4;
3214
3363
  function generateYieldseekerUsername() {
3215
3364
  const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
3216
3365
  return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
@@ -3254,6 +3403,7 @@ function query(params) {
3254
3403
  var YieldseekerAgent = class {
3255
3404
  id = "yieldseeker";
3256
3405
  balanceComposition = "tokens-plus-positions";
3406
+ withdrawalRequiresWalletApproval = true;
3257
3407
  supportedChainIds = [8453];
3258
3408
  supportedAssets = [
3259
3409
  {
@@ -3267,11 +3417,17 @@ var YieldseekerAgent = class {
3267
3417
  ];
3268
3418
  api;
3269
3419
  auth;
3420
+ rpcUrls;
3421
+ receiptClient;
3270
3422
  transactionExecutor;
3271
3423
  unwindReceiptWaiter;
3272
3424
  agentContexts = /* @__PURE__ */ new Map();
3273
3425
  users = /* @__PURE__ */ new Map();
3274
3426
  pendingAgents = /* @__PURE__ */ new Map();
3427
+ pendingWalletContexts = /* @__PURE__ */ new Map();
3428
+ readCache = /* @__PURE__ */ new Map();
3429
+ pendingReads = /* @__PURE__ */ new Map();
3430
+ readGeneration = 0;
3275
3431
  yieldOptions = /* @__PURE__ */ new Map();
3276
3432
  pendingYieldOptions = /* @__PURE__ */ new Map();
3277
3433
  constructor(owneyApiKey, options = {}) {
@@ -3281,10 +3437,16 @@ var YieldseekerAgent = class {
3281
3437
  options.fetchFn
3282
3438
  );
3283
3439
  this.auth = new YieldseekerAuth(options.auth);
3440
+ this.rpcUrls = options.rpcUrls;
3284
3441
  this.transactionExecutor = options.transactionExecutor;
3285
3442
  this.unwindReceiptWaiter = options.unwindReceiptWaiter;
3286
3443
  }
3444
+ getReceiptClient() {
3445
+ this.receiptClient ??= createPaidRpcClient(import_chains3.base, this.rpcUrls);
3446
+ return this.receiptClient;
3447
+ }
3287
3448
  async disconnect() {
3449
+ this.readGeneration += 1;
3288
3450
  this.auth.clear();
3289
3451
  for (const key2 of this.users.keys()) {
3290
3452
  const [walletAddress, chainId] = key2.split(":");
@@ -3293,6 +3455,9 @@ var YieldseekerAgent = class {
3293
3455
  this.users.clear();
3294
3456
  this.agentContexts.clear();
3295
3457
  this.pendingAgents.clear();
3458
+ this.pendingWalletContexts.clear();
3459
+ this.readCache.clear();
3460
+ this.pendingReads.clear();
3296
3461
  }
3297
3462
  async activateAgent(state, chainId, asset) {
3298
3463
  this.assertChain(chainId);
@@ -3329,12 +3494,12 @@ var YieldseekerAgent = class {
3329
3494
  await this.waitForReceipt(state, chainId, txHash);
3330
3495
  } else {
3331
3496
  txHash = await this.submitTransaction(state, chainId, {
3332
- from: (0, import_viem6.getAddress)(state.walletAddress),
3497
+ from: (0, import_viem7.getAddress)(state.walletAddress),
3333
3498
  to: YIELDSEEKER_ASSET_METADATA[asset].address,
3334
- data: (0, import_viem6.encodeFunctionData)({
3335
- abi: import_viem6.erc20Abi,
3499
+ data: (0, import_viem7.encodeFunctionData)({
3500
+ abi: import_viem7.erc20Abi,
3336
3501
  functionName: "transfer",
3337
- args: [(0, import_viem6.getAddress)(context.wallet.walletAddress), BigInt(amount)]
3502
+ args: [(0, import_viem7.getAddress)(context.wallet.walletAddress), BigInt(amount)]
3338
3503
  }),
3339
3504
  value: "0",
3340
3505
  chainId
@@ -3434,15 +3599,15 @@ var YieldseekerAgent = class {
3434
3599
  remaining: remaining.toString()
3435
3600
  });
3436
3601
  }
3437
- const account = (0, import_viem6.getAddress)(state.walletAddress);
3602
+ const account = (0, import_viem7.getAddress)(state.walletAddress);
3438
3603
  const txHash = await this.submitTransaction(state, chainId, {
3439
3604
  from: account,
3440
- to: (0, import_viem6.getAddress)(context.wallet.walletAddress),
3441
- data: amount === void 0 ? (0, import_viem6.encodeFunctionData)({
3605
+ to: (0, import_viem7.getAddress)(context.wallet.walletAddress),
3606
+ data: amount === void 0 ? (0, import_viem7.encodeFunctionData)({
3442
3607
  abi: YIELDSEEKER_AGENT_WALLET_ABI,
3443
3608
  functionName: "withdrawAllAssetToUser",
3444
3609
  args: [account, metadata.address]
3445
- }) : (0, import_viem6.encodeFunctionData)({
3610
+ }) : (0, import_viem7.encodeFunctionData)({
3446
3611
  abi: YIELDSEEKER_AGENT_WALLET_ABI,
3447
3612
  functionName: "withdrawAssetToUser",
3448
3613
  args: [account, metadata.address, requested]
@@ -3498,7 +3663,7 @@ var YieldseekerAgent = class {
3498
3663
  );
3499
3664
  const vaultAddresses = new Set(
3500
3665
  catalog.flat().filter(
3501
- (yieldOption) => yieldOption.chainId === chainId && (0, import_viem6.isAddress)(yieldOption.address)
3666
+ (yieldOption) => yieldOption.chainId === chainId && (0, import_viem7.isAddress)(yieldOption.address)
3502
3667
  ).map((yieldOption) => yieldOption.address.toLowerCase())
3503
3668
  );
3504
3669
  return mapYieldseekerHistory(contexts, {
@@ -3555,6 +3720,86 @@ var YieldseekerAgent = class {
3555
3720
  contextKey(state, chainId, asset) {
3556
3721
  return `${this.userKey(state, chainId)}:${asset}`;
3557
3722
  }
3723
+ cachedRead(key2, ttlMs, read2) {
3724
+ const cached = this.readCache.get(key2);
3725
+ if (cached && cached.expiresAt > Date.now()) {
3726
+ return Promise.resolve(cached.value);
3727
+ }
3728
+ const pending = this.pendingReads.get(key2);
3729
+ if (pending) return pending;
3730
+ const generation = this.readGeneration;
3731
+ const request = Promise.resolve().then(read2).then((value) => {
3732
+ if (this.readGeneration === generation) {
3733
+ this.readCache.set(key2, {
3734
+ expiresAt: Date.now() + ttlMs,
3735
+ value
3736
+ });
3737
+ }
3738
+ return value;
3739
+ }).finally(() => {
3740
+ if (this.pendingReads.get(key2) === request) {
3741
+ this.pendingReads.delete(key2);
3742
+ }
3743
+ });
3744
+ this.pendingReads.set(key2, request);
3745
+ return request;
3746
+ }
3747
+ agentListKey(state, chainId) {
3748
+ return `agents:${this.userKey(state, chainId)}`;
3749
+ }
3750
+ async listAgents(state, chainId, user) {
3751
+ const response = await this.cachedRead(
3752
+ this.agentListKey(state, chainId),
3753
+ YIELDSEEKER_AGENT_LIST_CACHE_MS,
3754
+ async () => {
3755
+ const response2 = await this.walletRequest(
3756
+ state,
3757
+ chainId,
3758
+ `/users/${user.userId}/agents`
3759
+ );
3760
+ if (!Array.isArray(response2?.agents)) {
3761
+ throw this.invalidResponse("agent list");
3762
+ }
3763
+ return response2;
3764
+ }
3765
+ );
3766
+ return response.agents;
3767
+ }
3768
+ async contextForAgent(state, chainId, user, agent, asset) {
3769
+ const key2 = this.contextKey(state, chainId, asset);
3770
+ const cached = this.agentContexts.get(key2);
3771
+ if (cached?.agent.agentId === agent.agentId) return cached;
3772
+ const pending = this.pendingWalletContexts.get(key2);
3773
+ if (pending) return pending;
3774
+ const generation = this.readGeneration;
3775
+ const request = this.walletRequest(
3776
+ state,
3777
+ chainId,
3778
+ `/users/${user.userId}/agents/${agent.agentId}/wallet`
3779
+ ).then((walletResponse) => {
3780
+ if (!walletResponse?.agentWallet || !(0, import_viem7.isAddress)(walletResponse.agentWallet.walletAddress)) {
3781
+ throw this.invalidResponse("agent wallet");
3782
+ }
3783
+ const context = {
3784
+ user,
3785
+ agent,
3786
+ wallet: walletResponse.agentWallet,
3787
+ asset
3788
+ };
3789
+ if (this.readGeneration === generation) {
3790
+ this.agentContexts.set(key2, context);
3791
+ }
3792
+ return context;
3793
+ });
3794
+ this.pendingWalletContexts.set(key2, request);
3795
+ try {
3796
+ return await request;
3797
+ } finally {
3798
+ if (this.pendingWalletContexts.get(key2) === request) {
3799
+ this.pendingWalletContexts.delete(key2);
3800
+ }
3801
+ }
3802
+ }
3558
3803
  async resolveUser(state, chainId) {
3559
3804
  const key2 = this.userKey(state, chainId);
3560
3805
  const inMemory = this.users.get(key2);
@@ -3564,7 +3809,7 @@ var YieldseekerAgent = class {
3564
3809
  this.users.set(key2, persisted);
3565
3810
  return persisted;
3566
3811
  }
3567
- const walletAddress = (0, import_viem6.getAddress)(state.walletAddress);
3812
+ const walletAddress = (0, import_viem7.getAddress)(state.walletAddress);
3568
3813
  let user = null;
3569
3814
  try {
3570
3815
  const login = await this.providerRequest(
@@ -3651,16 +3896,9 @@ var YieldseekerAgent = class {
3651
3896
  }
3652
3897
  async resolveAgent(state, chainId, asset, createIfMissing) {
3653
3898
  const user = await this.resolveUser(state, chainId);
3654
- const response = await this.walletRequest(
3655
- state,
3656
- chainId,
3657
- `/users/${user.userId}/agents`
3658
- );
3659
- if (!Array.isArray(response?.agents)) {
3660
- throw this.invalidResponse("agent list");
3661
- }
3899
+ const agents = await this.listAgents(state, chainId, user);
3662
3900
  const metadata = YIELDSEEKER_ASSET_METADATA[asset];
3663
- let agent = response.agents.find(
3901
+ let agent = agents.find(
3664
3902
  (candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
3665
3903
  );
3666
3904
  if (!agent && createIfMissing) {
@@ -3681,83 +3919,91 @@ var YieldseekerAgent = class {
3681
3919
  }
3682
3920
  );
3683
3921
  agent = created?.agent;
3922
+ if (agent) {
3923
+ this.readCache.set(this.agentListKey(state, chainId), {
3924
+ expiresAt: Date.now() + YIELDSEEKER_AGENT_LIST_CACHE_MS,
3925
+ value: {
3926
+ agents: [...agents, agent]
3927
+ }
3928
+ });
3929
+ }
3684
3930
  }
3685
3931
  if (!agent) return null;
3686
3932
  this.assertAgent(agent);
3687
- const walletResponse = await this.walletRequest(
3688
- state,
3689
- chainId,
3690
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3691
- );
3692
- if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
3693
- throw this.invalidResponse("agent wallet");
3694
- }
3695
- return { user, agent, wallet: walletResponse.agentWallet, asset };
3933
+ return this.contextForAgent(state, chainId, user, agent, asset);
3696
3934
  }
3697
3935
  async loadPortfolio(state, chainId, options) {
3698
3936
  const user = await this.resolveUser(state, chainId);
3699
- const response = await this.walletRequest(
3700
- state,
3701
- chainId,
3702
- `/users/${user.userId}/agents`
3703
- );
3704
- if (!Array.isArray(response?.agents)) {
3705
- throw this.invalidResponse("agent list");
3706
- }
3937
+ const agents = await this.listAgents(state, chainId, user);
3707
3938
  const contexts = [];
3708
- for (const agent of response.agents) {
3939
+ for (const agent of agents) {
3709
3940
  const asset = this.assetForAgent(agent);
3710
3941
  if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
3711
3942
  continue;
3712
3943
  }
3713
3944
  this.assertAgent(agent);
3714
- const walletResponse = await this.walletRequest(
3715
- state,
3716
- chainId,
3717
- `/users/${user.userId}/agents/${agent.agentId}/wallet`
3718
- );
3719
- if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
3720
- throw this.invalidResponse("agent wallet");
3721
- }
3722
- const context = {
3723
- user,
3724
- agent,
3725
- wallet: walletResponse.agentWallet,
3726
- asset
3727
- };
3728
- this.agentContexts.set(this.contextKey(state, chainId, asset), context);
3729
- contexts.push(context);
3945
+ contexts.push(this.contextForAgent(state, chainId, user, agent, asset));
3730
3946
  }
3947
+ const resolvedContexts = await Promise.all(contexts);
3731
3948
  return Promise.all(
3732
- contexts.map(
3949
+ resolvedContexts.map(
3733
3950
  (context) => this.loadPortfolioContext(state, chainId, context, options)
3734
3951
  )
3735
3952
  );
3736
3953
  }
3737
3954
  async loadPortfolioContext(state, chainId, context, options = {}) {
3955
+ const contextKey = this.contextKey(state, chainId, context.asset);
3738
3956
  const [snapshot, positions, historic, actions] = await Promise.all([
3739
- this.walletRequest(
3740
- state,
3741
- chainId,
3742
- `${this.agentPath(context, "snapshot")}${query({
3743
- shouldOnlyUseRecentValue: true,
3744
- shouldAllowStaleOnError: true
3745
- })}`
3957
+ this.cachedRead(
3958
+ `snapshot:${contextKey}`,
3959
+ YIELDSEEKER_PORTFOLIO_CACHE_MS,
3960
+ async () => {
3961
+ const response = await this.walletRequest(
3962
+ state,
3963
+ chainId,
3964
+ `${this.agentPath(context, "snapshot")}${query({
3965
+ shouldOnlyUseRecentValue: true,
3966
+ shouldAllowStaleOnError: true
3967
+ })}`
3968
+ );
3969
+ if (!response?.agentSnapshot) {
3970
+ throw this.invalidResponse("agent snapshot");
3971
+ }
3972
+ return response;
3973
+ }
3746
3974
  ),
3747
- this.walletRequest(
3748
- state,
3749
- chainId,
3750
- this.agentPath(context, "yield-positions")
3975
+ this.cachedRead(
3976
+ `positions:${contextKey}`,
3977
+ YIELDSEEKER_PORTFOLIO_CACHE_MS,
3978
+ async () => {
3979
+ const response = await this.walletRequest(
3980
+ state,
3981
+ chainId,
3982
+ this.agentPath(context, "yield-positions")
3983
+ );
3984
+ if (!Array.isArray(response?.yieldPositions)) {
3985
+ throw this.invalidResponse("yield positions");
3986
+ }
3987
+ return response;
3988
+ }
3751
3989
  ),
3752
- options.historic ? this.walletRequest(
3753
- state,
3754
- chainId,
3755
- this.agentPath(context, "wallet/historic-position")
3990
+ options.historic ? this.cachedRead(
3991
+ `historic:${contextKey}`,
3992
+ YIELDSEEKER_ACTIVITY_CACHE_MS,
3993
+ () => this.walletRequest(
3994
+ state,
3995
+ chainId,
3996
+ this.agentPath(context, "wallet/historic-position")
3997
+ )
3756
3998
  ) : Promise.resolve(void 0),
3757
- options.actions ? this.walletRequest(
3758
- state,
3759
- chainId,
3760
- this.agentPath(context, "actions")
3999
+ options.actions ? this.cachedRead(
4000
+ `actions:${contextKey}`,
4001
+ YIELDSEEKER_ACTIVITY_CACHE_MS,
4002
+ () => this.walletRequest(
4003
+ state,
4004
+ chainId,
4005
+ this.agentPath(context, "actions")
4006
+ )
3761
4007
  ) : Promise.resolve(void 0)
3762
4008
  ]);
3763
4009
  if (!snapshot?.agentSnapshot) {
@@ -3783,7 +4029,7 @@ var YieldseekerAgent = class {
3783
4029
  this.agentPath(context, "deploy"),
3784
4030
  { method: "POST", body: {} }
3785
4031
  );
3786
- if (!deployed?.agentWallet || !(0, import_viem6.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
4032
+ if (!deployed?.agentWallet || !(0, import_viem7.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
3787
4033
  throw this.invalidResponse("agent deployment", {
3788
4034
  reason: "Deploy did not return the expected Agent Wallet."
3789
4035
  });
@@ -3791,6 +4037,13 @@ var YieldseekerAgent = class {
3791
4037
  context.wallet = deployed.agentWallet;
3792
4038
  }
3793
4039
  async refreshSnapshotAfterMovement(state, chainId, context, movement) {
4040
+ const contextKey = this.contextKey(state, chainId, context.asset);
4041
+ const invalidatePortfolio = () => {
4042
+ for (const kind of ["snapshot", "positions", "historic", "actions"]) {
4043
+ this.readCache.delete(`${kind}:${contextKey}`);
4044
+ }
4045
+ };
4046
+ invalidatePortfolio();
3794
4047
  try {
3795
4048
  const response = await this.walletRequest(
3796
4049
  state,
@@ -3807,6 +4060,8 @@ var YieldseekerAgent = class {
3807
4060
  `[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
3808
4061
  error
3809
4062
  );
4063
+ } finally {
4064
+ invalidatePortfolio();
3810
4065
  }
3811
4066
  }
3812
4067
  agentPath(context, suffix) {
@@ -3857,6 +4112,7 @@ var YieldseekerAgent = class {
3857
4112
  code,
3858
4113
  `Yieldseeker request failed: ${error.providerCode}.`,
3859
4114
  {
4115
+ rpcSource: "agent-api",
3860
4116
  statusCode: error.status,
3861
4117
  providerCode: error.providerCode,
3862
4118
  ...error.responseFields ? { fields: error.responseFields } : {}
@@ -3869,32 +4125,37 @@ var YieldseekerAgent = class {
3869
4125
  return this.transactionExecutor(state, chainId, transaction);
3870
4126
  }
3871
4127
  this.assertTransaction(transaction, state, chainId);
3872
- const account = (0, import_viem6.getAddress)(state.walletAddress);
3873
- const walletClient = (0, import_viem6.createWalletClient)({
4128
+ const account = (0, import_viem7.getAddress)(state.walletAddress);
4129
+ const walletClient = (0, import_viem7.createWalletClient)({
3874
4130
  account,
3875
4131
  chain: import_chains3.base,
3876
- transport: (0, import_viem6.custom)(state.provider)
4132
+ transport: (0, import_viem7.custom)(state.provider)
3877
4133
  });
3878
- const publicClient = (0, import_viem6.createPublicClient)({
4134
+ const walletChainClient = (0, import_viem7.createPublicClient)({
3879
4135
  chain: import_chains3.base,
3880
- transport: (0, import_viem6.custom)(state.provider)
4136
+ transport: (0, import_viem7.custom)(state.provider)
3881
4137
  });
3882
4138
  await ensureWalletOnChain(
3883
- publicClient,
4139
+ walletChainClient,
3884
4140
  walletClient,
3885
4141
  8453
3886
4142
  );
3887
4143
  const hash = await walletClient.sendTransaction({
3888
4144
  account,
3889
4145
  chain: import_chains3.base,
3890
- to: (0, import_viem6.getAddress)(transaction.to),
4146
+ to: (0, import_viem7.getAddress)(transaction.to),
3891
4147
  data: transaction.data,
3892
4148
  value: BigInt(transaction.value)
3893
4149
  });
3894
- const receipt = await publicClient.waitForTransactionReceipt({
3895
- hash,
3896
- confirmations: 1
3897
- });
4150
+ const receipt = await withPaidRpcDiagnostics(
4151
+ () => this.getReceiptClient().waitForTransactionReceipt({
4152
+ hash,
4153
+ confirmations: 1
4154
+ }),
4155
+ 8453,
4156
+ "eth_getTransactionReceipt",
4157
+ this.id
4158
+ );
3898
4159
  if (receipt.status !== "success") {
3899
4160
  throw new OwneyError(
3900
4161
  "AGENT_TRANSACTION_REVERTED",
@@ -3910,14 +4171,15 @@ var YieldseekerAgent = class {
3910
4171
  await this.unwindReceiptWaiter(state, chainId, transactionHash);
3911
4172
  return;
3912
4173
  }
3913
- const publicClient = (0, import_viem6.createPublicClient)({
3914
- chain: import_chains3.base,
3915
- transport: (0, import_viem6.custom)(state.provider)
3916
- });
3917
- const receipt = await publicClient.waitForTransactionReceipt({
3918
- hash: transactionHash,
3919
- confirmations: 1
3920
- });
4174
+ const receipt = await withPaidRpcDiagnostics(
4175
+ () => this.getReceiptClient().waitForTransactionReceipt({
4176
+ hash: transactionHash,
4177
+ confirmations: 1
4178
+ }),
4179
+ 8453,
4180
+ "eth_getTransactionReceipt",
4181
+ this.id
4182
+ );
3921
4183
  if (receipt.status !== "success") {
3922
4184
  throw new OwneyError(
3923
4185
  "AGENT_TRANSACTION_REVERTED",
@@ -3928,12 +4190,12 @@ var YieldseekerAgent = class {
3928
4190
  }
3929
4191
  }
3930
4192
  assertTransaction(transaction, state, chainId) {
3931
- if (!transaction || typeof transaction.from !== "string" || !(0, import_viem6.isAddress)(transaction.from) || typeof transaction.to !== "string" || !(0, import_viem6.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_viem6.getAddress)(transaction.from) !== (0, import_viem6.getAddress)(state.walletAddress)) {
4193
+ 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)) {
3932
4194
  throw this.invalidResponse("transaction");
3933
4195
  }
3934
4196
  }
3935
4197
  assertAgent(agent) {
3936
- if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem6.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
4198
+ if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem7.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
3937
4199
  throw this.invalidResponse("agent");
3938
4200
  }
3939
4201
  }
@@ -4086,7 +4348,7 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
4086
4348
  }
4087
4349
 
4088
4350
  // src/lib/helpers/withdraw-helper.ts
4089
- var import_viem7 = require("viem");
4351
+ var import_viem8 = require("viem");
4090
4352
  function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
4091
4353
  const target = asset.toUpperCase();
4092
4354
  return agents.map((agent) => {
@@ -4094,7 +4356,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
4094
4356
  const tokenBalance = agentBalance?.tokens.find(
4095
4357
  (t) => t.chainId === chainId && t.asset.toUpperCase() === target
4096
4358
  );
4097
- let balance = tokenBalance ? (0, import_viem7.parseUnits)(tokenBalance.amount, decimals) : 0n;
4359
+ let balance = tokenBalance ? (0, import_viem8.parseUnits)(tokenBalance.amount, decimals) : 0n;
4098
4360
  if (agent.balanceComposition === "tokens-plus-positions") {
4099
4361
  const chainNameById = {
4100
4362
  1: "ETHEREUM",
@@ -4113,7 +4375,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
4113
4375
  } catch {
4114
4376
  }
4115
4377
  }
4116
- balance += (0, import_viem7.parseUnits)(position2.amount, decimals);
4378
+ balance += (0, import_viem8.parseUnits)(position2.amount, decimals);
4117
4379
  }
4118
4380
  }
4119
4381
  return { agent, balance };
@@ -4272,15 +4534,50 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
4272
4534
  }
4273
4535
 
4274
4536
  // src/client.ts
4275
- var import_viem11 = require("viem");
4537
+ var import_viem12 = require("viem");
4276
4538
  var import_chains4 = require("viem/chains");
4277
4539
 
4278
4540
  // src/lib/sponsored-token-batch.ts
4279
- var import_viem9 = require("viem");
4541
+ var import_viem10 = require("viem");
4280
4542
 
4281
4543
  // src/lib/permit2-batch.ts
4282
- var import_viem8 = require("viem");
4544
+ var import_viem9 = require("viem");
4283
4545
  var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
4546
+ var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
4547
+ var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
4548
+ var ERC2612_PERMIT_TYPES = {
4549
+ Permit: [
4550
+ { name: "owner", type: "address" },
4551
+ { name: "spender", type: "address" },
4552
+ { name: "value", type: "uint256" },
4553
+ { name: "nonce", type: "uint256" },
4554
+ { name: "deadline", type: "uint256" }
4555
+ ]
4556
+ };
4557
+ var ERC2612_READ_ABI = (0, import_viem9.parseAbi)([
4558
+ "function name() view returns (string)",
4559
+ "function version() view returns (string)",
4560
+ "function nonces(address owner) view returns (uint256)"
4561
+ ]);
4562
+ function erc2612TypedData(input) {
4563
+ return {
4564
+ domain: {
4565
+ name: input.permit.tokenName,
4566
+ version: input.permit.tokenVersion,
4567
+ chainId: input.chainId,
4568
+ verifyingContract: input.token
4569
+ },
4570
+ types: ERC2612_PERMIT_TYPES,
4571
+ primaryType: "Permit",
4572
+ message: {
4573
+ owner: input.owner,
4574
+ spender: BATCH_PERMIT2_ADDRESS,
4575
+ value: BigInt(input.permit.value),
4576
+ nonce: BigInt(input.permit.nonce),
4577
+ deadline: BigInt(input.permit.deadline)
4578
+ }
4579
+ };
4580
+ }
4284
4581
  var PERMIT_BATCH_TYPES = {
4285
4582
  PermitBatchWitnessTransferFrom: [
4286
4583
  { name: "permitted", type: "TokenPermissions[]" },
@@ -4295,7 +4592,7 @@ var PERMIT_BATCH_TYPES = {
4295
4592
  { name: "amount", type: "uint256" }
4296
4593
  ]
4297
4594
  };
4298
- var PERMIT2_BATCH_ABI = (0, import_viem8.parseAbi)([
4595
+ var PERMIT2_BATCH_ABI = (0, import_viem9.parseAbi)([
4299
4596
  "struct TokenPermissions { address token; uint256 amount; }",
4300
4597
  "struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
4301
4598
  "struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
@@ -4354,7 +4651,7 @@ function clear(key2) {
4354
4651
  else window.localStorage.removeItem(key2);
4355
4652
  }
4356
4653
  function sponsorTokenBatch(i) {
4357
- const key2 = `owney.token-batch.v1:${(0, import_viem9.keccak256)((0, import_viem9.toBytes)(i.apiKey))}:${i.baseUrl ?? "default"}:${i.chainId}:${i.owner.toLowerCase()}:${i.token.toLowerCase()}`;
4654
+ 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()}`;
4358
4655
  const plan = planOf(i.transfers);
4359
4656
  const active = inflight.get(key2);
4360
4657
  if (active) {
@@ -4385,7 +4682,7 @@ async function execute(i, key2, plan) {
4385
4682
  baseUrl: i.baseUrl,
4386
4683
  body
4387
4684
  });
4388
- if (!prepared.serializedTransaction || (0, import_viem9.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
4685
+ if (!prepared.serializedTransaction || (0, import_viem10.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
4389
4686
  throw new Error(
4390
4687
  "Sponsorship API did not return a valid prepared transaction."
4391
4688
  );
@@ -4400,7 +4697,7 @@ async function execute(i, key2, plan) {
4400
4697
  baseUrl: i.baseUrl,
4401
4698
  body
4402
4699
  });
4403
- if (result.txHash !== (0, import_viem9.keccak256)(body.serializedTransaction))
4700
+ if (result.txHash !== (0, import_viem10.keccak256)(body.serializedTransaction))
4404
4701
  throw new Error(
4405
4702
  "Sponsorship receipt does not match the pending transaction."
4406
4703
  );
@@ -4415,7 +4712,7 @@ async function execute(i, key2, plan) {
4415
4712
  const saved = read(key2);
4416
4713
  if (saved) {
4417
4714
  const previous = JSON.parse(saved);
4418
- if (previous.chainId !== i.chainId || !(0, import_viem9.isAddressEqual)(previous.from, i.owner) || !(0, import_viem9.isAddressEqual)(previous.token, i.token) || planOf(previous.transfers) !== plan)
4715
+ 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)
4419
4716
  throw new Error(
4420
4717
  "Retry the previous token deposit and agent split first to reconcile its status."
4421
4718
  );
@@ -4432,28 +4729,67 @@ async function execute(i, key2, plan) {
4432
4729
  "DEPOSIT_INSUFFICIENT_BALANCE",
4433
4730
  "Insufficient token balance for this deposit."
4434
4731
  );
4435
- if (allowance < total)
4732
+ if (allowance < total && (i.chainId !== 8453 || !(0, import_viem10.isAddressEqual)(i.token, BASE_USDC_ADDRESS)))
4436
4733
  throw new OwneyError(
4437
4734
  "PERMIT2_APPROVAL_REQUIRED",
4438
4735
  "token deposits need a one-time Permit2 approval."
4439
4736
  );
4440
- const relayer = await getSponsorRelayerAddress({
4737
+ const now = (await i.pub.getBlock()).timestamp;
4738
+ let erc2612Permit;
4739
+ if (allowance < total) {
4740
+ const [tokenName, tokenVersion, permitNonce] = await Promise.all([
4741
+ i.pub.readContract({
4742
+ address: i.token,
4743
+ abi: ERC2612_READ_ABI,
4744
+ functionName: "name"
4745
+ }),
4746
+ i.pub.readContract({
4747
+ address: i.token,
4748
+ abi: ERC2612_READ_ABI,
4749
+ functionName: "version"
4750
+ }),
4751
+ i.pub.readContract({
4752
+ address: i.token,
4753
+ abi: ERC2612_READ_ABI,
4754
+ functionName: "nonces",
4755
+ args: [i.owner]
4756
+ })
4757
+ ]);
4758
+ const unsignedPermit = {
4759
+ value: MAX_UINT256.toString(),
4760
+ nonce: permitNonce.toString(),
4761
+ deadline: (now + 900n).toString(),
4762
+ tokenName,
4763
+ tokenVersion
4764
+ };
4765
+ const signature2 = await i.wallet.signTypedData({
4766
+ account: i.owner,
4767
+ ...erc2612TypedData({
4768
+ chainId: 8453,
4769
+ token: i.token,
4770
+ owner: i.owner,
4771
+ permit: unsignedPermit
4772
+ })
4773
+ });
4774
+ erc2612Permit = { ...unsignedPermit, signature: signature2 };
4775
+ }
4776
+ const spender = erc2612Permit ? MULTICALL3_ADDRESS : await getSponsorRelayerAddress({
4441
4777
  apiKey: i.apiKey,
4442
4778
  baseUrl: i.baseUrl,
4443
4779
  chainId: i.chainId
4444
4780
  });
4445
- const now = (await i.pub.getBlock()).timestamp;
4446
4781
  const unsigned = {
4447
4782
  chainId: i.chainId,
4448
4783
  token: i.token,
4449
4784
  from: i.owner,
4450
4785
  transfers: i.transfers,
4451
4786
  nonce: randomPermit2Nonce().toString(),
4452
- deadline: (now + 900n).toString()
4787
+ deadline: (now + 900n).toString(),
4788
+ ...erc2612Permit ? { erc2612Permit } : {}
4453
4789
  };
4454
4790
  const signature = await i.wallet.signTypedData({
4455
4791
  account: i.owner,
4456
- ...batchTypedData(unsigned, relayer)
4792
+ ...batchTypedData(unsigned, spender)
4457
4793
  });
4458
4794
  i.onApproved?.();
4459
4795
  return send({ ...unsigned, signature });
@@ -4473,8 +4809,8 @@ function makeSponsoredTokenCallback(deps) {
4473
4809
  "CHAIN_UNSUPPORTED",
4474
4810
  `No sponsored token configured for chain ${chainId}`
4475
4811
  );
4476
- const pub = deps.getPublicClient(chainId), wallet = deps.getWalletClient(chainId);
4477
- await ensureWalletOnChain(pub, wallet, chainId);
4812
+ const pub = deps.getPublicClient(chainId), walletChain = deps.getWalletChainClient?.(chainId) ?? pub, wallet = deps.getWalletClient(chainId);
4813
+ await ensureWalletOnChain(walletChain, wallet, chainId);
4478
4814
  return sponsorTokenBatch({
4479
4815
  apiKey: deps.apiKey,
4480
4816
  baseUrl: deps.baseUrl,
@@ -4570,7 +4906,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
4570
4906
  }
4571
4907
 
4572
4908
  // src/lib/sponsored-calls-deposit.ts
4573
- var import_viem10 = require("viem");
4909
+ var import_viem11 = require("viem");
4574
4910
  var DEFAULT_POLL_INTERVAL_MS = 1500;
4575
4911
  var DEFAULT_MAX_POLLS = 30;
4576
4912
  async function paymasterSupported(provider, owner, chainId) {
@@ -4578,7 +4914,7 @@ async function paymasterSupported(provider, owner, chainId) {
4578
4914
  method: "wallet_getCapabilities",
4579
4915
  params: [owner]
4580
4916
  });
4581
- const forChain = caps?.[(0, import_viem10.toHex)(chainId)] ?? caps?.[String(chainId)];
4917
+ const forChain = caps?.[(0, import_viem11.toHex)(chainId)] ?? caps?.[String(chainId)];
4582
4918
  return Boolean(forChain?.paymasterService?.supported);
4583
4919
  }
4584
4920
  function makeSponsoredCallsCallback(deps) {
@@ -4615,8 +4951,8 @@ function makeSponsoredCallsCallback(deps) {
4615
4951
  const calls = transfers.map((transfer) => ({
4616
4952
  to: token,
4617
4953
  value: "0x0",
4618
- data: (0, import_viem10.encodeFunctionData)({
4619
- abi: import_viem10.erc20Abi,
4954
+ data: (0, import_viem11.encodeFunctionData)({
4955
+ abi: import_viem11.erc20Abi,
4620
4956
  functionName: "transfer",
4621
4957
  args: [transfer.to, BigInt(transfer.amount)]
4622
4958
  })
@@ -4654,7 +4990,7 @@ function makeSponsoredCallsCallback(deps) {
4654
4990
  {
4655
4991
  version: "2.0.0",
4656
4992
  from: deps.ownerAddress,
4657
- chainId: (0, import_viem10.toHex)(chainId),
4993
+ chainId: (0, import_viem11.toHex)(chainId),
4658
4994
  atomicRequired: transfers.length > 1,
4659
4995
  calls,
4660
4996
  capabilities: {
@@ -4714,6 +5050,8 @@ function makeSponsoredCallsCallback(deps) {
4714
5050
  }
4715
5051
 
4716
5052
  // src/client.ts
5053
+ var PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS = 6;
5054
+ var PERMIT2_ALLOWANCE_VERIFY_DELAY_MS = 250;
4717
5055
  function encodeMultiAgentCursor(map) {
4718
5056
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
4719
5057
  }
@@ -4774,6 +5112,7 @@ var OwneySDK = class {
4774
5112
  // leave every user's agent profile alone.
4775
5113
  orgAgentConfig;
4776
5114
  orgAgentConfigPromise = null;
5115
+ rpcUrls;
4777
5116
  zyfaiRpcUrls;
4778
5117
  yieldseekerApiBaseUrl;
4779
5118
  yieldseekerSiweOrigin;
@@ -4798,6 +5137,7 @@ var OwneySDK = class {
4798
5137
  constructor(config) {
4799
5138
  this.apiKey = config.apiKey;
4800
5139
  if (config.debug) setOwneyDebug(true);
5140
+ this.rpcUrls = config.rpcUrls;
4801
5141
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
4802
5142
  this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
4803
5143
  this.yieldseekerSiweOrigin = config.yieldseekerSiweOrigin;
@@ -4888,6 +5228,9 @@ var OwneySDK = class {
4888
5228
  }
4889
5229
  return this.state.provider;
4890
5230
  }
5231
+ getPaidRpcClient(chainId) {
5232
+ return createPaidRpcClient(VIEM_CHAIN2[chainId], this.rpcUrls);
5233
+ }
4891
5234
  /** Builds the default USDC batch callback for the connected wallet. */
4892
5235
  getDefaultSponsoredCallback(onApproved) {
4893
5236
  if (!onApproved && this.cachedSponsoredCallback)
@@ -4903,14 +5246,15 @@ var OwneySDK = class {
4903
5246
  // Casts work around viem's chain-narrowed Client vs the generic
4904
5247
  // PublicClient/WalletClient param types — structurally identical at
4905
5248
  // runtime, but the two share a name TS treats as unrelated.
4906
- getPublicClient: (cid) => (0, import_viem11.createPublicClient)({
5249
+ getPublicClient: (cid) => this.getPaidRpcClient(cid),
5250
+ getWalletChainClient: (cid) => (0, import_viem12.createPublicClient)({
4907
5251
  chain: VIEM_CHAIN2[cid],
4908
- transport: (0, import_viem11.custom)(provider)
5252
+ transport: (0, import_viem12.custom)(provider)
4909
5253
  }),
4910
- getWalletClient: (cid) => (0, import_viem11.createWalletClient)({
5254
+ getWalletClient: (cid) => (0, import_viem12.createWalletClient)({
4911
5255
  account: owner,
4912
5256
  chain: VIEM_CHAIN2[cid],
4913
- transport: (0, import_viem11.custom)(provider)
5257
+ transport: (0, import_viem12.custom)(provider)
4914
5258
  })
4915
5259
  });
4916
5260
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -4953,14 +5297,15 @@ var OwneySDK = class {
4953
5297
  // Casts work around viem's chain-narrowed Client vs the generic
4954
5298
  // PublicClient/WalletClient param types — structurally identical at
4955
5299
  // runtime, but the two share a name TS treats as unrelated.
4956
- getPublicClient: (cid) => (0, import_viem11.createPublicClient)({
5300
+ getPublicClient: (cid) => this.getPaidRpcClient(cid),
5301
+ getWalletChainClient: (cid) => (0, import_viem12.createPublicClient)({
4957
5302
  chain: VIEM_CHAIN2[cid],
4958
- transport: (0, import_viem11.custom)(provider)
5303
+ transport: (0, import_viem12.custom)(provider)
4959
5304
  }),
4960
- getWalletClient: (cid) => (0, import_viem11.createWalletClient)({
5305
+ getWalletClient: (cid) => (0, import_viem12.createWalletClient)({
4961
5306
  account: owner,
4962
5307
  chain: VIEM_CHAIN2[cid],
4963
- transport: (0, import_viem11.custom)(provider)
5308
+ transport: (0, import_viem12.custom)(provider)
4964
5309
  })
4965
5310
  });
4966
5311
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -5066,12 +5411,17 @@ var OwneySDK = class {
5066
5411
  createAgent(agentId, key2) {
5067
5412
  if (agentId === "zyfai") {
5068
5413
  if (!key2) return null;
5069
- return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
5414
+ return new ZyfaiAgent(
5415
+ key2,
5416
+ this.rpcUrls ?? this.zyfaiRpcUrls,
5417
+ this.referralSource
5418
+ );
5070
5419
  }
5071
5420
  if (agentId === "yieldseeker") {
5072
5421
  return new YieldseekerAgent(this.apiKey, {
5073
5422
  auth: { origin: this.yieldseekerSiweOrigin },
5074
- baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl)
5423
+ baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl),
5424
+ rpcUrls: this.rpcUrls
5075
5425
  });
5076
5426
  }
5077
5427
  return null;
@@ -5362,7 +5712,8 @@ var OwneySDK = class {
5362
5712
  );
5363
5713
  await this.approvePermit2(
5364
5714
  asset,
5365
- requiredAmount
5715
+ requiredAmount,
5716
+ cid
5366
5717
  );
5367
5718
  return batchTransfer(cid, transfers);
5368
5719
  }
@@ -5406,10 +5757,12 @@ var OwneySDK = class {
5406
5757
  * Invokes `agent.deposit` with the resolved sponsored callback, composing
5407
5758
  * two independent auto-recovery mechanisms:
5408
5759
  *
5409
- * 1. Missing Permit2 allowance: when the app did not supply its own
5410
- * callback and the attempt fails with `PERMIT2_APPROVAL_REQUIRED` on a
5411
- * token deposit, this is the wallet's first Permit2 deposit for that token. We send
5412
- * the one-time (user-paid) Permit2 approval via `approvePermit2()` and
5760
+ * 1. Missing Permit2 allowance outside the atomic Base-USDC path: when the
5761
+ * app did not supply its own callback and the attempt fails with
5762
+ * `PERMIT2_APPROVAL_REQUIRED`, this is the wallet's first Permit2 deposit
5763
+ * for that token. Base USDC bundles a gasless ERC-2612 approval inside
5764
+ * its sponsored deposit and never reaches this branch. Other tokens send
5765
+ * the one-time user-paid Permit2 approval via `approvePermit2()` and
5413
5766
  * retry the SAME sponsored attempt once. Bounded to one approval attempt
5414
5767
  * per call so a wallet/agent that keeps reporting the allowance as
5415
5768
  * missing can't loop forever. If `approvePermit2()` itself throws (e.g.
@@ -5452,7 +5805,8 @@ var OwneySDK = class {
5452
5805
  );
5453
5806
  await this.approvePermit2(
5454
5807
  asset,
5455
- BigInt(amount)
5808
+ BigInt(amount),
5809
+ chainId
5456
5810
  );
5457
5811
  continue;
5458
5812
  }
@@ -5599,6 +5953,32 @@ var OwneySDK = class {
5599
5953
  }
5600
5954
  return eligible;
5601
5955
  }
5956
+ /**
5957
+ * Run owner-approved withdrawals before relayer-only withdrawals. Wallet
5958
+ * approval is the only point at which the user can cancel the aggregate
5959
+ * operation, so no relayer leg should commit before it has completed.
5960
+ */
5961
+ orderAgentsForWithdrawal(agents) {
5962
+ return agents.map((agent, index) => ({ agent, index })).sort((left, right) => {
5963
+ const approvalOrder = Number(Boolean(right.agent.withdrawalRequiresWalletApproval)) - Number(Boolean(left.agent.withdrawalRequiresWalletApproval));
5964
+ return approvalOrder || left.index - right.index;
5965
+ }).map(({ agent }) => agent);
5966
+ }
5967
+ isUserRejectedWithdrawal(error) {
5968
+ let current = error;
5969
+ const seen = /* @__PURE__ */ new Set();
5970
+ while (current && typeof current === "object" && !seen.has(current)) {
5971
+ seen.add(current);
5972
+ const candidate = current;
5973
+ if (candidate.code === 4001 || candidate.code === "4001") return true;
5974
+ const message = [candidate.message, candidate.shortMessage].filter((value) => typeof value === "string").join(" ");
5975
+ if (/user (?:rejected|denied)|rejected by user/i.test(message)) {
5976
+ return true;
5977
+ }
5978
+ current = candidate.cause;
5979
+ }
5980
+ return false;
5981
+ }
5602
5982
  // --- Fund operations ---
5603
5983
  /**
5604
5984
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
@@ -5634,13 +6014,15 @@ var OwneySDK = class {
5634
6014
  );
5635
6015
  }
5636
6016
  const eligibleAgents = this.getEligibleAgents(chainId, asset);
6017
+ const withdrawalAgents = this.orderAgentsForWithdrawal(eligibleAgents);
5637
6018
  if (!amount) {
5638
6019
  const results2 = {};
5639
6020
  const agentErrors2 = {};
5640
- for (const agent of eligibleAgents) {
6021
+ for (const agent of withdrawalAgents) {
5641
6022
  try {
5642
6023
  results2[agent.id] = await agent.withdraw(state, chainId, token);
5643
6024
  } catch (err) {
6025
+ if (this.isUserRejectedWithdrawal(err)) throw err;
5644
6026
  console.error(`withdraw failed for agent "${agent.id}":`, err);
5645
6027
  agentErrors2[agent.id] = err instanceof Error ? err.message : String(err);
5646
6028
  const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
@@ -5721,12 +6103,13 @@ var OwneySDK = class {
5721
6103
  planned: 0n
5722
6104
  }));
5723
6105
  const plans = [...disabledPlans, ...enabledPlans];
6106
+ const orderedPlans = this.orderAgentsForWithdrawal(plans.map((p) => p.agent)).map((agent) => plans.find((plan) => plan.agent === agent));
5724
6107
  const results = {};
5725
6108
  const agentErrors = {
5726
6109
  ...aggregated.agentErrors ?? {}
5727
6110
  };
5728
- for (let i = 0; i < plans.length; i++) {
5729
- const p = plans[i];
6111
+ for (let i = 0; i < orderedPlans.length; i++) {
6112
+ const p = orderedPlans[i];
5730
6113
  if (p.planned === 0n) continue;
5731
6114
  try {
5732
6115
  results[p.agent.id] = await p.agent.withdraw(
@@ -5736,6 +6119,7 @@ var OwneySDK = class {
5736
6119
  p.planned.toString()
5737
6120
  );
5738
6121
  } catch (err) {
6122
+ if (this.isUserRejectedWithdrawal(err)) throw err;
5739
6123
  console.error(`withdraw failed for agent "${p.agent.id}":`, err);
5740
6124
  agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
5741
6125
  const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
@@ -5747,7 +6131,7 @@ var OwneySDK = class {
5747
6131
  );
5748
6132
  const failedAmount = p.planned;
5749
6133
  p.planned = 0n;
5750
- redistributeShare(plans, i, failedAmount);
6134
+ redistributeShare(orderedPlans, i, failedAmount);
5751
6135
  }
5752
6136
  }
5753
6137
  if (Object.keys(results).length === 0) {
@@ -6175,14 +6559,16 @@ var OwneySDK = class {
6175
6559
  * User-paid approval of Permit2 on the selected token for the active chain.
6176
6560
  * Grants the maximum ERC20 allowance so later deposits do not require another
6177
6561
  * approval. Resolves after one confirmation so the subsequent deposit attempt
6178
- * sees the new allowance.
6562
+ * sees the new allowance. Deposit retries pass their captured chain id so a
6563
+ * concurrent activation cannot redirect the approval to another network.
6179
6564
  *
6180
6565
  * @param requiredAmount Raw base-unit amount the pending deposit must cover.
6566
+ * @param expectedChainId Chain captured by the deposit that requested approval.
6181
6567
  * @returns the approval transaction hash.
6182
6568
  */
6183
- async approvePermit2(asset = "WETH", requiredAmount = 0n) {
6569
+ async approvePermit2(asset = "WETH", requiredAmount = 0n, expectedChainId) {
6184
6570
  const state = this.requireState();
6185
- const chainId = this.requireChainId();
6571
+ const chainId = expectedChainId ?? this.requireChainId();
6186
6572
  this.getEligibleAgents(chainId, asset, { excludeDisabled: true });
6187
6573
  const token = sponsoredTokensFor(asset)[chainId];
6188
6574
  if (!token) {
@@ -6192,16 +6578,18 @@ var OwneySDK = class {
6192
6578
  );
6193
6579
  }
6194
6580
  const provider = this.requireConnectedProvider();
6195
- const publicClient = (0, import_viem11.createPublicClient)({
6581
+ const walletChainClient = (0, import_viem12.createPublicClient)({
6196
6582
  chain: VIEM_CHAIN2[chainId],
6197
- transport: (0, import_viem11.custom)(provider)
6583
+ transport: (0, import_viem12.custom)(provider)
6198
6584
  });
6585
+ const publicClient = this.getPaidRpcClient(chainId);
6199
6586
  const approvalAmount = permit2ApprovalAmount(requiredAmount);
6200
- const wallet = (0, import_viem11.createWalletClient)({
6587
+ const wallet = (0, import_viem12.createWalletClient)({
6201
6588
  account: state.walletAddress,
6202
6589
  chain: VIEM_CHAIN2[chainId],
6203
- transport: (0, import_viem11.custom)(provider)
6590
+ transport: (0, import_viem12.custom)(provider)
6204
6591
  });
6592
+ await ensureWalletOnChain(walletChainClient, wallet, chainId);
6205
6593
  const hash = await wallet.writeContract({
6206
6594
  address: token,
6207
6595
  abi: ERC20_ALLOWANCE_ABI,
@@ -6210,14 +6598,53 @@ var OwneySDK = class {
6210
6598
  account: state.walletAddress,
6211
6599
  chain: VIEM_CHAIN2[chainId]
6212
6600
  });
6213
- const receipt = await publicClient.waitForTransactionReceipt({
6214
- hash,
6215
- confirmations: 1
6216
- });
6601
+ const receipt = await withPaidRpcDiagnostics(
6602
+ () => publicClient.waitForTransactionReceipt({
6603
+ hash,
6604
+ confirmations: 1
6605
+ }),
6606
+ chainId,
6607
+ "eth_getTransactionReceipt"
6608
+ );
6217
6609
  if (receipt.status !== "success") {
6218
6610
  throw new Error(`Permit2 approval reverted (tx ${hash})`);
6219
6611
  }
6220
- return hash;
6612
+ let observedAllowance = 0n;
6613
+ let verificationError;
6614
+ for (let attempt = 0; attempt < PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS; attempt += 1) {
6615
+ try {
6616
+ observedAllowance = await readPermit2Allowance(
6617
+ publicClient,
6618
+ token,
6619
+ state.walletAddress,
6620
+ attempt === 0 ? receipt.blockNumber : void 0
6621
+ );
6622
+ verificationError = void 0;
6623
+ if (observedAllowance >= requiredAmount) return hash;
6624
+ } catch (error) {
6625
+ verificationError = error;
6626
+ }
6627
+ if (attempt + 1 < PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS) {
6628
+ await new Promise(
6629
+ (resolve) => setTimeout(resolve, PERMIT2_ALLOWANCE_VERIFY_DELAY_MS)
6630
+ );
6631
+ }
6632
+ }
6633
+ throw new OwneyError(
6634
+ "PERMIT2_APPROVAL_REQUIRED",
6635
+ "Permit2 approval was confirmed, but the required token allowance was not observable.",
6636
+ {
6637
+ approvalConfirmed: true,
6638
+ approvalTxHash: hash,
6639
+ owner: state.walletAddress,
6640
+ token,
6641
+ spender: PERMIT2_ADDRESS,
6642
+ chainId,
6643
+ requiredAmount: requiredAmount.toString(),
6644
+ observedAllowance: observedAllowance.toString(),
6645
+ ...verificationError instanceof Error ? { verificationError: verificationError.message } : {}
6646
+ }
6647
+ );
6221
6648
  }
6222
6649
  // --- Discovery (no wallet required) ---
6223
6650
  /**
@@ -6322,7 +6749,7 @@ var OwneySDK = class {
6322
6749
  };
6323
6750
 
6324
6751
  // src/agents/zyfai/zyfai.siwx.ts
6325
- var import_viem12 = require("viem");
6752
+ var import_viem13 = require("viem");
6326
6753
  var import_siwe2 = require("siwe");
6327
6754
  var import_sdk2 = require("@zyfai/sdk");
6328
6755
 
@@ -6449,7 +6876,7 @@ function buildSIWXConfig(deps) {
6449
6876
  issuedAt,
6450
6877
  toString() {
6451
6878
  return new import_siwe2.SiweMessage({
6452
- address: (0, import_viem12.getAddress)(accountAddress),
6879
+ address: (0, import_viem13.getAddress)(accountAddress),
6453
6880
  chainId: numericChainId(chainId),
6454
6881
  domain,
6455
6882
  uri,