@owney/sdk 0.6.0-beta.1 → 0.6.0-beta.2

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
@@ -32,6 +32,8 @@ module.exports = __toCommonJS(src_exports);
32
32
 
33
33
  // src/agents/zyfai/zyfai.agent.ts
34
34
  var import_sdk = require("@zyfai/sdk");
35
+ var import_viem = require("viem");
36
+ var import_chains = require("viem/chains");
35
37
 
36
38
  // src/types/config.ts
37
39
  var P_SUPPORTED_CHAINS = {
@@ -280,6 +282,14 @@ function mapApyHistory(raw) {
280
282
  apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain)
281
283
  };
282
284
  }
285
+ function splitOpportunity(opportunity) {
286
+ const match = opportunity.match(/^(.*?)\s*\(([^)]*)\)\s*$/);
287
+ if (match) {
288
+ const pool = match[2].trim();
289
+ return { protocol: match[1].trim(), pool: pool || void 0 };
290
+ }
291
+ return { protocol: opportunity.trim() };
292
+ }
283
293
  function mapEntries(rawEntries, chainId) {
284
294
  const actionMap = {
285
295
  "Top up wallet": "Top up",
@@ -299,21 +309,26 @@ function mapEntries(rawEntries, chainId) {
299
309
  );
300
310
  oldApy = Number(rawLog.oldApy);
301
311
  newApy = Number(rawLog.newApy);
312
+ const from = splitOpportunity(rawLog.oldOpportunity);
313
+ const to = splitOpportunity(rawLog.newOpportunity);
302
314
  rebalanceLog = [
303
315
  {
304
- fromProtocol: rawLog.oldOpportunity.replace(/\s*\(.*?\)/g, "").trim(),
305
- toProtocol: rawLog.newOpportunity.replace(/\s*\(.*?\)/g, "").trim(),
316
+ fromProtocol: from.protocol,
317
+ toProtocol: to.protocol,
318
+ fromPool: from.pool,
319
+ toPool: to.pool,
306
320
  tokenSymbol: matched?.token_symbol ?? "",
307
321
  amount: matched ? String(hexToDecimal(matched.amount || "0x")) : "",
308
322
  status: "success"
309
323
  }
310
324
  ];
311
325
  }
326
+ const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
312
327
  const rawAmount = entry?.positions?.[0]?.amount;
313
- const hasAmount = typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
328
+ const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
314
329
  return {
315
330
  agent: "zyfai",
316
- action: (entry.action ? actionMap[entry.action] : void 0) ?? entry.action,
331
+ action: mappedAction,
317
332
  date: entry.date || "",
318
333
  newApy: newApy === null ? null : String(newApy),
319
334
  oldApy: oldApy === null ? null : String(oldApy),
@@ -405,6 +420,33 @@ function computeAllocationApy(positions) {
405
420
  return { totalApy, apyByChainAndAsset };
406
421
  }
407
422
 
423
+ // src/agents/zyfai/zyfai.withdraw-amount.ts
424
+ var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
425
+ function topicToAddress(topic) {
426
+ return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
427
+ }
428
+ function extractWithdrawnAmount(logs, recipient, token, decimals) {
429
+ const wantRecipient = recipient.toLowerCase();
430
+ const wantToken = token.toLowerCase();
431
+ let total = 0n;
432
+ let matched = false;
433
+ for (const log of logs) {
434
+ if (log.address.toLowerCase() !== wantToken)
435
+ continue;
436
+ if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC)
437
+ continue;
438
+ if (topicToAddress(log.topics[2]) !== wantRecipient)
439
+ continue;
440
+ if (!log.data || log.data === "0x")
441
+ continue;
442
+ total += BigInt(log.data);
443
+ matched = true;
444
+ }
445
+ if (!matched)
446
+ return void 0;
447
+ return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
448
+ }
449
+
408
450
  // src/agents/zyfai/zyfai.history-cursor.ts
409
451
  var InvalidHistoryCursorError = class extends Error {
410
452
  code = "invalid_cursor";
@@ -507,6 +549,7 @@ var WETH_ADDRESS_BY_CHAIN = {
507
549
  8453: "0x4200000000000000000000000000000000000006",
508
550
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
509
551
  };
552
+ var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
510
553
  var ZyfaiAgent = class {
511
554
  id = "zyfai";
512
555
  supportedChainIds = [8453, 42161];
@@ -533,13 +576,83 @@ var ZyfaiAgent = class {
533
576
  connectedChainId = null;
534
577
  smartWalletCache = /* @__PURE__ */ new Map();
535
578
  connectAuthPromise = null;
579
+ rpcUrls;
580
+ publicClients = /* @__PURE__ */ new Map();
581
+ // txHash -> resolved withdrawn amount. Receipts are immutable, so a
582
+ // successful decode is cached forever; failures are NOT cached so a transient
583
+ // RPC error retries on the next fetch.
584
+ withdrawAmountCache = /* @__PURE__ */ new Map();
536
585
  constructor(apiKey, rpcUrls) {
586
+ this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
537
587
  this.sdk = new import_sdk.ZyfaiSDK({
538
588
  apiKey,
539
- rpcUrls: rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS
589
+ rpcUrls: this.rpcUrls
540
590
  });
541
591
  this.installAuthCache();
542
592
  }
593
+ getPublicClient(chainId) {
594
+ const cached = this.publicClients.get(chainId);
595
+ if (cached)
596
+ return cached;
597
+ const client = (0, import_viem.createPublicClient)({
598
+ chain: VIEM_CHAIN[chainId],
599
+ transport: (0, import_viem.http)(this.rpcUrls[chainId])
600
+ });
601
+ this.publicClients.set(chainId, client);
602
+ return client;
603
+ }
604
+ /**
605
+ * Fills in the true withdrawn amount for `Withdraw` entries by decoding the
606
+ * USDC `Transfer` that lands in the user's wallet on-chain. The Zyfai history
607
+ * payload only reports the *remaining* position for a partial withdraw (see
608
+ * the note in `mapEntries`), so without this the UI shows the leftover
609
+ * balance instead of the amount withdrawn.
610
+ *
611
+ * Mutates `entries` in place. Runs all lookups concurrently and is tolerant
612
+ * of RPC failures: an entry whose amount can't be resolved keeps
613
+ * `amount: undefined`, which consumers render as a hidden/retryable row
614
+ * rather than a wrong number.
615
+ */
616
+ async resolveWithdrawnAmounts(entries, chainId, recipient) {
617
+ const asset = SupportedAssets.find(
618
+ (a) => a.chainId === chainId && a.symbol === "USDC"
619
+ );
620
+ if (!asset)
621
+ return;
622
+ const withdrawals = entries.filter(
623
+ (e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
624
+ );
625
+ if (withdrawals.length === 0)
626
+ return;
627
+ const client = this.getPublicClient(chainId);
628
+ await Promise.all(
629
+ withdrawals.map(async (entry) => {
630
+ const tx = entry.transactions[0];
631
+ const txHash = tx.txHashes[0];
632
+ const cached = this.withdrawAmountCache.get(txHash);
633
+ if (cached !== void 0) {
634
+ tx.amount = cached;
635
+ return;
636
+ }
637
+ try {
638
+ const receipt = await client.getTransactionReceipt({
639
+ hash: txHash
640
+ });
641
+ const amount = extractWithdrawnAmount(
642
+ receipt.logs,
643
+ recipient,
644
+ asset.address,
645
+ asset.decimals
646
+ );
647
+ if (amount !== void 0) {
648
+ this.withdrawAmountCache.set(txHash, amount);
649
+ tx.amount = amount;
650
+ }
651
+ } catch {
652
+ }
653
+ })
654
+ );
655
+ }
543
656
  /**
544
657
  * Patches `sdk.authenticateUser` so a fresh page can reuse the JWT from a
545
658
  * prior session instead of triggering a new SIWE prompt. Runs inside
@@ -792,8 +905,10 @@ var ZyfaiAgent = class {
792
905
  toDate,
793
906
  rawOffset: firstOvershoot ? firstOvershoot.rawIdx : offset
794
907
  }) : void 0;
908
+ const data = mapEntries(pageData, validChainId);
909
+ await this.resolveWithdrawnAmounts(data, validChainId, state.walletAddress);
795
910
  return {
796
- data: mapEntries(pageData, validChainId),
911
+ data,
797
912
  hasMore,
798
913
  nextCursor
799
914
  };
@@ -884,7 +999,7 @@ async function withFailureReporting(apiKey, agentType, fn) {
884
999
  }
885
1000
 
886
1001
  // src/lib/helpers/withdraw-helper.ts
887
- var import_viem = require("viem");
1002
+ var import_viem2 = require("viem");
888
1003
  function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
889
1004
  const target = asset.toUpperCase();
890
1005
  return agents.map((agent) => {
@@ -894,7 +1009,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
894
1009
  );
895
1010
  if (!tokenBalance)
896
1011
  return { agent, balance: 0n };
897
- return { agent, balance: (0, import_viem.parseUnits)(tokenBalance.amount, decimals) };
1012
+ return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
898
1013
  });
899
1014
  }
900
1015
  function planProportionalShares(balances, requested, totalAvailable) {
@@ -1010,11 +1125,11 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
1010
1125
  }
1011
1126
 
1012
1127
  // src/client.ts
1013
- var import_viem3 = require("viem");
1014
- var import_chains = require("viem/chains");
1128
+ var import_viem4 = require("viem");
1129
+ var import_chains2 = require("viem/chains");
1015
1130
 
1016
1131
  // src/lib/transfer-auth.ts
1017
- var import_viem2 = require("viem");
1132
+ var import_viem3 = require("viem");
1018
1133
  var ERC20_META_ABI = [
1019
1134
  { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
1020
1135
  { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
@@ -1046,16 +1161,16 @@ async function readTokenMeta(publicClient, token) {
1046
1161
  function randomAuthNonce() {
1047
1162
  const bytes = new Uint8Array(32);
1048
1163
  globalThis.crypto.getRandomValues(bytes);
1049
- return (0, import_viem2.bytesToHex)(bytes);
1164
+ return (0, import_viem3.bytesToHex)(bytes);
1050
1165
  }
1051
1166
 
1052
1167
  // src/lib/sponsor-client.ts
1053
1168
  var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
1054
1169
  async function postSponsorTransferAuth(input) {
1055
- const base2 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1170
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1056
1171
  let res;
1057
1172
  try {
1058
- res = await fetch(`${base2}/api/v1/sponsor/erc20-transfer-auth`, {
1173
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
1059
1174
  method: "POST",
1060
1175
  headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
1061
1176
  body: JSON.stringify(input.body)
@@ -1158,9 +1273,9 @@ var SPONSORED_USDC_BY_CHAIN = {
1158
1273
  8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1159
1274
  42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
1160
1275
  };
1161
- var VIEM_CHAIN = {
1162
- 8453: import_chains.base,
1163
- 42161: import_chains.arbitrum
1276
+ var VIEM_CHAIN2 = {
1277
+ 8453: import_chains2.base,
1278
+ 42161: import_chains2.arbitrum
1164
1279
  };
1165
1280
  var OwneySDK = class {
1166
1281
  agents = /* @__PURE__ */ new Map();
@@ -1273,14 +1388,14 @@ var OwneySDK = class {
1273
1388
  // Casts work around viem's chain-narrowed Client vs the generic
1274
1389
  // PublicClient/WalletClient param types — structurally identical at
1275
1390
  // runtime, but the two share a name TS treats as unrelated.
1276
- getPublicClient: (cid) => (0, import_viem3.createPublicClient)({
1277
- chain: VIEM_CHAIN[cid],
1278
- transport: (0, import_viem3.custom)(provider)
1391
+ getPublicClient: (cid) => (0, import_viem4.createPublicClient)({
1392
+ chain: VIEM_CHAIN2[cid],
1393
+ transport: (0, import_viem4.custom)(provider)
1279
1394
  }),
1280
- getWalletClient: (cid) => (0, import_viem3.createWalletClient)({
1395
+ getWalletClient: (cid) => (0, import_viem4.createWalletClient)({
1281
1396
  account: owner,
1282
- chain: VIEM_CHAIN[cid],
1283
- transport: (0, import_viem3.custom)(provider)
1397
+ chain: VIEM_CHAIN2[cid],
1398
+ transport: (0, import_viem4.custom)(provider)
1284
1399
  })
1285
1400
  });
1286
1401
  return this.cachedSponsoredCallback;
@@ -2152,7 +2267,7 @@ var OwneySDK = class {
2152
2267
  };
2153
2268
 
2154
2269
  // src/agents/zyfai/zyfai.siwx.ts
2155
- var import_viem4 = require("viem");
2270
+ var import_viem5 = require("viem");
2156
2271
  var import_siwe = require("siwe");
2157
2272
  var import_sdk2 = require("@zyfai/sdk");
2158
2273
 
@@ -2234,7 +2349,7 @@ function buildSIWXConfig(deps) {
2234
2349
  issuedAt,
2235
2350
  toString() {
2236
2351
  return new import_siwe.SiweMessage({
2237
- address: (0, import_viem4.getAddress)(accountAddress),
2352
+ address: (0, import_viem5.getAddress)(accountAddress),
2238
2353
  chainId: numericChainId(chainId),
2239
2354
  domain,
2240
2355
  uri,
@@ -2310,9 +2425,9 @@ function buildSIWXConfig(deps) {
2310
2425
  }
2311
2426
  function createOwneySIWX(config) {
2312
2427
  const zyfai = new import_sdk2.ZyfaiSDK({ apiKey: config.apiKey });
2313
- const http = zyfai.httpClient;
2428
+ const http2 = zyfai.httpClient;
2314
2429
  return buildSIWXConfig({
2315
- post: (url, data) => http.post(url, data),
2430
+ post: (url, data) => http2.post(url, data),
2316
2431
  referralSource: config.referralSource
2317
2432
  });
2318
2433
  }
package/dist/index.d.cts CHANGED
@@ -114,6 +114,15 @@ interface HistoryTransaction {
114
114
  interface RebalanceLog {
115
115
  fromProtocol: string;
116
116
  toProtocol: string;
117
+ /**
118
+ * Pool/vault sub-label for the source position (e.g. "USDC Core"), when the
119
+ * agent exposes one. Lets consumers disambiguate moves within the same
120
+ * protocol ("Morpho · USDC Core → Morpho · Spark USDC"). Absent when the
121
+ * agent only reports a bare protocol name.
122
+ */
123
+ fromPool?: string;
124
+ /** Pool/vault sub-label for the destination position. See {@link fromPool}. */
125
+ toPool?: string;
117
126
  tokenSymbol: string;
118
127
  amount: string;
119
128
  status: "success" | "failed";
package/dist/index.d.ts CHANGED
@@ -114,6 +114,15 @@ interface HistoryTransaction {
114
114
  interface RebalanceLog {
115
115
  fromProtocol: string;
116
116
  toProtocol: string;
117
+ /**
118
+ * Pool/vault sub-label for the source position (e.g. "USDC Core"), when the
119
+ * agent exposes one. Lets consumers disambiguate moves within the same
120
+ * protocol ("Morpho · USDC Core → Morpho · Spark USDC"). Absent when the
121
+ * agent only reports a bare protocol name.
122
+ */
123
+ fromPool?: string;
124
+ /** Pool/vault sub-label for the destination position. See {@link fromPool}. */
125
+ toPool?: string;
117
126
  tokenSymbol: string;
118
127
  amount: string;
119
128
  status: "success" | "failed";
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  // src/agents/zyfai/zyfai.agent.ts
2
2
  import { ZyfaiSDK } from "@zyfai/sdk";
3
+ import { createPublicClient, http } from "viem";
4
+ import { base, arbitrum } from "viem/chains";
3
5
 
4
6
  // src/types/config.ts
5
7
  var P_SUPPORTED_CHAINS = {
@@ -248,6 +250,14 @@ function mapApyHistory(raw) {
248
250
  apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain)
249
251
  };
250
252
  }
253
+ function splitOpportunity(opportunity) {
254
+ const match = opportunity.match(/^(.*?)\s*\(([^)]*)\)\s*$/);
255
+ if (match) {
256
+ const pool = match[2].trim();
257
+ return { protocol: match[1].trim(), pool: pool || void 0 };
258
+ }
259
+ return { protocol: opportunity.trim() };
260
+ }
251
261
  function mapEntries(rawEntries, chainId) {
252
262
  const actionMap = {
253
263
  "Top up wallet": "Top up",
@@ -267,21 +277,26 @@ function mapEntries(rawEntries, chainId) {
267
277
  );
268
278
  oldApy = Number(rawLog.oldApy);
269
279
  newApy = Number(rawLog.newApy);
280
+ const from = splitOpportunity(rawLog.oldOpportunity);
281
+ const to = splitOpportunity(rawLog.newOpportunity);
270
282
  rebalanceLog = [
271
283
  {
272
- fromProtocol: rawLog.oldOpportunity.replace(/\s*\(.*?\)/g, "").trim(),
273
- toProtocol: rawLog.newOpportunity.replace(/\s*\(.*?\)/g, "").trim(),
284
+ fromProtocol: from.protocol,
285
+ toProtocol: to.protocol,
286
+ fromPool: from.pool,
287
+ toPool: to.pool,
274
288
  tokenSymbol: matched?.token_symbol ?? "",
275
289
  amount: matched ? String(hexToDecimal(matched.amount || "0x")) : "",
276
290
  status: "success"
277
291
  }
278
292
  ];
279
293
  }
294
+ const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
280
295
  const rawAmount = entry?.positions?.[0]?.amount;
281
- const hasAmount = typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
296
+ const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
282
297
  return {
283
298
  agent: "zyfai",
284
- action: (entry.action ? actionMap[entry.action] : void 0) ?? entry.action,
299
+ action: mappedAction,
285
300
  date: entry.date || "",
286
301
  newApy: newApy === null ? null : String(newApy),
287
302
  oldApy: oldApy === null ? null : String(oldApy),
@@ -373,6 +388,33 @@ function computeAllocationApy(positions) {
373
388
  return { totalApy, apyByChainAndAsset };
374
389
  }
375
390
 
391
+ // src/agents/zyfai/zyfai.withdraw-amount.ts
392
+ var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
393
+ function topicToAddress(topic) {
394
+ return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
395
+ }
396
+ function extractWithdrawnAmount(logs, recipient, token, decimals) {
397
+ const wantRecipient = recipient.toLowerCase();
398
+ const wantToken = token.toLowerCase();
399
+ let total = 0n;
400
+ let matched = false;
401
+ for (const log of logs) {
402
+ if (log.address.toLowerCase() !== wantToken)
403
+ continue;
404
+ if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC)
405
+ continue;
406
+ if (topicToAddress(log.topics[2]) !== wantRecipient)
407
+ continue;
408
+ if (!log.data || log.data === "0x")
409
+ continue;
410
+ total += BigInt(log.data);
411
+ matched = true;
412
+ }
413
+ if (!matched)
414
+ return void 0;
415
+ return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
416
+ }
417
+
376
418
  // src/agents/zyfai/zyfai.history-cursor.ts
377
419
  var InvalidHistoryCursorError = class extends Error {
378
420
  code = "invalid_cursor";
@@ -475,6 +517,7 @@ var WETH_ADDRESS_BY_CHAIN = {
475
517
  8453: "0x4200000000000000000000000000000000000006",
476
518
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
477
519
  };
520
+ var VIEM_CHAIN = { 8453: base, 42161: arbitrum };
478
521
  var ZyfaiAgent = class {
479
522
  id = "zyfai";
480
523
  supportedChainIds = [8453, 42161];
@@ -501,13 +544,83 @@ var ZyfaiAgent = class {
501
544
  connectedChainId = null;
502
545
  smartWalletCache = /* @__PURE__ */ new Map();
503
546
  connectAuthPromise = null;
547
+ rpcUrls;
548
+ publicClients = /* @__PURE__ */ new Map();
549
+ // txHash -> resolved withdrawn amount. Receipts are immutable, so a
550
+ // successful decode is cached forever; failures are NOT cached so a transient
551
+ // RPC error retries on the next fetch.
552
+ withdrawAmountCache = /* @__PURE__ */ new Map();
504
553
  constructor(apiKey, rpcUrls) {
554
+ this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
505
555
  this.sdk = new ZyfaiSDK({
506
556
  apiKey,
507
- rpcUrls: rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS
557
+ rpcUrls: this.rpcUrls
508
558
  });
509
559
  this.installAuthCache();
510
560
  }
561
+ getPublicClient(chainId) {
562
+ const cached = this.publicClients.get(chainId);
563
+ if (cached)
564
+ return cached;
565
+ const client = createPublicClient({
566
+ chain: VIEM_CHAIN[chainId],
567
+ transport: http(this.rpcUrls[chainId])
568
+ });
569
+ this.publicClients.set(chainId, client);
570
+ return client;
571
+ }
572
+ /**
573
+ * Fills in the true withdrawn amount for `Withdraw` entries by decoding the
574
+ * USDC `Transfer` that lands in the user's wallet on-chain. The Zyfai history
575
+ * payload only reports the *remaining* position for a partial withdraw (see
576
+ * the note in `mapEntries`), so without this the UI shows the leftover
577
+ * balance instead of the amount withdrawn.
578
+ *
579
+ * Mutates `entries` in place. Runs all lookups concurrently and is tolerant
580
+ * of RPC failures: an entry whose amount can't be resolved keeps
581
+ * `amount: undefined`, which consumers render as a hidden/retryable row
582
+ * rather than a wrong number.
583
+ */
584
+ async resolveWithdrawnAmounts(entries, chainId, recipient) {
585
+ const asset = SupportedAssets.find(
586
+ (a) => a.chainId === chainId && a.symbol === "USDC"
587
+ );
588
+ if (!asset)
589
+ return;
590
+ const withdrawals = entries.filter(
591
+ (e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
592
+ );
593
+ if (withdrawals.length === 0)
594
+ return;
595
+ const client = this.getPublicClient(chainId);
596
+ await Promise.all(
597
+ withdrawals.map(async (entry) => {
598
+ const tx = entry.transactions[0];
599
+ const txHash = tx.txHashes[0];
600
+ const cached = this.withdrawAmountCache.get(txHash);
601
+ if (cached !== void 0) {
602
+ tx.amount = cached;
603
+ return;
604
+ }
605
+ try {
606
+ const receipt = await client.getTransactionReceipt({
607
+ hash: txHash
608
+ });
609
+ const amount = extractWithdrawnAmount(
610
+ receipt.logs,
611
+ recipient,
612
+ asset.address,
613
+ asset.decimals
614
+ );
615
+ if (amount !== void 0) {
616
+ this.withdrawAmountCache.set(txHash, amount);
617
+ tx.amount = amount;
618
+ }
619
+ } catch {
620
+ }
621
+ })
622
+ );
623
+ }
511
624
  /**
512
625
  * Patches `sdk.authenticateUser` so a fresh page can reuse the JWT from a
513
626
  * prior session instead of triggering a new SIWE prompt. Runs inside
@@ -760,8 +873,10 @@ var ZyfaiAgent = class {
760
873
  toDate,
761
874
  rawOffset: firstOvershoot ? firstOvershoot.rawIdx : offset
762
875
  }) : void 0;
876
+ const data = mapEntries(pageData, validChainId);
877
+ await this.resolveWithdrawnAmounts(data, validChainId, state.walletAddress);
763
878
  return {
764
- data: mapEntries(pageData, validChainId),
879
+ data,
765
880
  hasMore,
766
881
  nextCursor
767
882
  };
@@ -979,11 +1094,11 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
979
1094
 
980
1095
  // src/client.ts
981
1096
  import {
982
- createPublicClient,
1097
+ createPublicClient as createPublicClient2,
983
1098
  createWalletClient,
984
1099
  custom
985
1100
  } from "viem";
986
- import { base, arbitrum } from "viem/chains";
1101
+ import { base as base2, arbitrum as arbitrum2 } from "viem/chains";
987
1102
 
988
1103
  // src/lib/transfer-auth.ts
989
1104
  import { bytesToHex } from "viem";
@@ -1024,10 +1139,10 @@ function randomAuthNonce() {
1024
1139
  // src/lib/sponsor-client.ts
1025
1140
  var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
1026
1141
  async function postSponsorTransferAuth(input) {
1027
- const base2 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1142
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1028
1143
  let res;
1029
1144
  try {
1030
- res = await fetch(`${base2}/api/v1/sponsor/erc20-transfer-auth`, {
1145
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
1031
1146
  method: "POST",
1032
1147
  headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
1033
1148
  body: JSON.stringify(input.body)
@@ -1130,9 +1245,9 @@ var SPONSORED_USDC_BY_CHAIN = {
1130
1245
  8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1131
1246
  42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
1132
1247
  };
1133
- var VIEM_CHAIN = {
1134
- 8453: base,
1135
- 42161: arbitrum
1248
+ var VIEM_CHAIN2 = {
1249
+ 8453: base2,
1250
+ 42161: arbitrum2
1136
1251
  };
1137
1252
  var OwneySDK = class {
1138
1253
  agents = /* @__PURE__ */ new Map();
@@ -1245,13 +1360,13 @@ var OwneySDK = class {
1245
1360
  // Casts work around viem's chain-narrowed Client vs the generic
1246
1361
  // PublicClient/WalletClient param types — structurally identical at
1247
1362
  // runtime, but the two share a name TS treats as unrelated.
1248
- getPublicClient: (cid) => createPublicClient({
1249
- chain: VIEM_CHAIN[cid],
1363
+ getPublicClient: (cid) => createPublicClient2({
1364
+ chain: VIEM_CHAIN2[cid],
1250
1365
  transport: custom(provider)
1251
1366
  }),
1252
1367
  getWalletClient: (cid) => createWalletClient({
1253
1368
  account: owner,
1254
- chain: VIEM_CHAIN[cid],
1369
+ chain: VIEM_CHAIN2[cid],
1255
1370
  transport: custom(provider)
1256
1371
  })
1257
1372
  });
@@ -2282,9 +2397,9 @@ function buildSIWXConfig(deps) {
2282
2397
  }
2283
2398
  function createOwneySIWX(config) {
2284
2399
  const zyfai = new ZyfaiSDK2({ apiKey: config.apiKey });
2285
- const http = zyfai.httpClient;
2400
+ const http2 = zyfai.httpClient;
2286
2401
  return buildSIWXConfig({
2287
- post: (url, data) => http.post(url, data),
2402
+ post: (url, data) => http2.post(url, data),
2288
2403
  referralSource: config.referralSource
2289
2404
  });
2290
2405
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.6.0-beta.1",
3
+ "version": "0.6.0-beta.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",