@owney/sdk 0.5.3 → 0.5.5-beta.0
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 +142 -27
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +133 -18
- package/package.json +1 -1
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 = {
|
|
@@ -268,6 +270,14 @@ function mapApyHistory(raw) {
|
|
|
268
270
|
apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain)
|
|
269
271
|
};
|
|
270
272
|
}
|
|
273
|
+
function splitOpportunity(opportunity) {
|
|
274
|
+
const match = opportunity.match(/^(.*?)\s*\(([^)]*)\)\s*$/);
|
|
275
|
+
if (match) {
|
|
276
|
+
const pool = match[2].trim();
|
|
277
|
+
return { protocol: match[1].trim(), pool: pool || void 0 };
|
|
278
|
+
}
|
|
279
|
+
return { protocol: opportunity.trim() };
|
|
280
|
+
}
|
|
271
281
|
function mapEntries(rawEntries, chainId) {
|
|
272
282
|
const actionMap = {
|
|
273
283
|
"Top up wallet": "Top up",
|
|
@@ -287,21 +297,26 @@ function mapEntries(rawEntries, chainId) {
|
|
|
287
297
|
);
|
|
288
298
|
oldApy = Number(rawLog.oldApy);
|
|
289
299
|
newApy = Number(rawLog.newApy);
|
|
300
|
+
const from = splitOpportunity(rawLog.oldOpportunity);
|
|
301
|
+
const to = splitOpportunity(rawLog.newOpportunity);
|
|
290
302
|
rebalanceLog = [
|
|
291
303
|
{
|
|
292
|
-
fromProtocol:
|
|
293
|
-
toProtocol:
|
|
304
|
+
fromProtocol: from.protocol,
|
|
305
|
+
toProtocol: to.protocol,
|
|
306
|
+
fromPool: from.pool,
|
|
307
|
+
toPool: to.pool,
|
|
294
308
|
tokenSymbol: matched?.token_symbol ?? "",
|
|
295
309
|
amount: matched ? String(hexToDecimal(matched.amount || "0x")) : "",
|
|
296
310
|
status: "success"
|
|
297
311
|
}
|
|
298
312
|
];
|
|
299
313
|
}
|
|
314
|
+
const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
|
|
300
315
|
const rawAmount = entry?.positions?.[0]?.amount;
|
|
301
|
-
const hasAmount = typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
316
|
+
const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
302
317
|
return {
|
|
303
318
|
agent: "zyfai",
|
|
304
|
-
action:
|
|
319
|
+
action: mappedAction,
|
|
305
320
|
date: entry.date || "",
|
|
306
321
|
newApy: newApy === null ? null : String(newApy),
|
|
307
322
|
oldApy: oldApy === null ? null : String(oldApy),
|
|
@@ -393,6 +408,33 @@ function computeAllocationApy(positions) {
|
|
|
393
408
|
return { totalApy, apyByChainAndAsset };
|
|
394
409
|
}
|
|
395
410
|
|
|
411
|
+
// src/agents/zyfai/zyfai.withdraw-amount.ts
|
|
412
|
+
var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
413
|
+
function topicToAddress(topic) {
|
|
414
|
+
return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
|
|
415
|
+
}
|
|
416
|
+
function extractWithdrawnAmount(logs, recipient, token, decimals) {
|
|
417
|
+
const wantRecipient = recipient.toLowerCase();
|
|
418
|
+
const wantToken = token.toLowerCase();
|
|
419
|
+
let total = 0n;
|
|
420
|
+
let matched = false;
|
|
421
|
+
for (const log of logs) {
|
|
422
|
+
if (log.address.toLowerCase() !== wantToken)
|
|
423
|
+
continue;
|
|
424
|
+
if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC)
|
|
425
|
+
continue;
|
|
426
|
+
if (topicToAddress(log.topics[2]) !== wantRecipient)
|
|
427
|
+
continue;
|
|
428
|
+
if (!log.data || log.data === "0x")
|
|
429
|
+
continue;
|
|
430
|
+
total += BigInt(log.data);
|
|
431
|
+
matched = true;
|
|
432
|
+
}
|
|
433
|
+
if (!matched)
|
|
434
|
+
return void 0;
|
|
435
|
+
return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
|
|
436
|
+
}
|
|
437
|
+
|
|
396
438
|
// src/agents/zyfai/zyfai.history-cursor.ts
|
|
397
439
|
var InvalidHistoryCursorError = class extends Error {
|
|
398
440
|
code = "invalid_cursor";
|
|
@@ -491,6 +533,7 @@ var DEFAULT_ZYFAI_RPC_URLS = {
|
|
|
491
533
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
492
534
|
42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
|
|
493
535
|
};
|
|
536
|
+
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
|
|
494
537
|
var ZyfaiAgent = class {
|
|
495
538
|
id = "zyfai";
|
|
496
539
|
supportedChainIds = [8453, 42161];
|
|
@@ -511,13 +554,83 @@ var ZyfaiAgent = class {
|
|
|
511
554
|
connectedChainId = null;
|
|
512
555
|
smartWalletCache = /* @__PURE__ */ new Map();
|
|
513
556
|
connectAuthPromise = null;
|
|
557
|
+
rpcUrls;
|
|
558
|
+
publicClients = /* @__PURE__ */ new Map();
|
|
559
|
+
// txHash -> resolved withdrawn amount. Receipts are immutable, so a
|
|
560
|
+
// successful decode is cached forever; failures are NOT cached so a transient
|
|
561
|
+
// RPC error retries on the next fetch.
|
|
562
|
+
withdrawAmountCache = /* @__PURE__ */ new Map();
|
|
514
563
|
constructor(apiKey, rpcUrls) {
|
|
564
|
+
this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
|
|
515
565
|
this.sdk = new import_sdk.ZyfaiSDK({
|
|
516
566
|
apiKey,
|
|
517
|
-
rpcUrls: rpcUrls
|
|
567
|
+
rpcUrls: this.rpcUrls
|
|
518
568
|
});
|
|
519
569
|
this.installAuthCache();
|
|
520
570
|
}
|
|
571
|
+
getPublicClient(chainId) {
|
|
572
|
+
const cached = this.publicClients.get(chainId);
|
|
573
|
+
if (cached)
|
|
574
|
+
return cached;
|
|
575
|
+
const client = (0, import_viem.createPublicClient)({
|
|
576
|
+
chain: VIEM_CHAIN[chainId],
|
|
577
|
+
transport: (0, import_viem.http)(this.rpcUrls[chainId])
|
|
578
|
+
});
|
|
579
|
+
this.publicClients.set(chainId, client);
|
|
580
|
+
return client;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Fills in the true withdrawn amount for `Withdraw` entries by decoding the
|
|
584
|
+
* USDC `Transfer` that lands in the user's wallet on-chain. The Zyfai history
|
|
585
|
+
* payload only reports the *remaining* position for a partial withdraw (see
|
|
586
|
+
* the note in `mapEntries`), so without this the UI shows the leftover
|
|
587
|
+
* balance instead of the amount withdrawn.
|
|
588
|
+
*
|
|
589
|
+
* Mutates `entries` in place. Runs all lookups concurrently and is tolerant
|
|
590
|
+
* of RPC failures: an entry whose amount can't be resolved keeps
|
|
591
|
+
* `amount: undefined`, which consumers render as a hidden/retryable row
|
|
592
|
+
* rather than a wrong number.
|
|
593
|
+
*/
|
|
594
|
+
async resolveWithdrawnAmounts(entries, chainId, recipient) {
|
|
595
|
+
const asset = SupportedAssets.find(
|
|
596
|
+
(a) => a.chainId === chainId && a.symbol === "USDC"
|
|
597
|
+
);
|
|
598
|
+
if (!asset)
|
|
599
|
+
return;
|
|
600
|
+
const withdrawals = entries.filter(
|
|
601
|
+
(e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
|
|
602
|
+
);
|
|
603
|
+
if (withdrawals.length === 0)
|
|
604
|
+
return;
|
|
605
|
+
const client = this.getPublicClient(chainId);
|
|
606
|
+
await Promise.all(
|
|
607
|
+
withdrawals.map(async (entry) => {
|
|
608
|
+
const tx = entry.transactions[0];
|
|
609
|
+
const txHash = tx.txHashes[0];
|
|
610
|
+
const cached = this.withdrawAmountCache.get(txHash);
|
|
611
|
+
if (cached !== void 0) {
|
|
612
|
+
tx.amount = cached;
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
try {
|
|
616
|
+
const receipt = await client.getTransactionReceipt({
|
|
617
|
+
hash: txHash
|
|
618
|
+
});
|
|
619
|
+
const amount = extractWithdrawnAmount(
|
|
620
|
+
receipt.logs,
|
|
621
|
+
recipient,
|
|
622
|
+
asset.address,
|
|
623
|
+
asset.decimals
|
|
624
|
+
);
|
|
625
|
+
if (amount !== void 0) {
|
|
626
|
+
this.withdrawAmountCache.set(txHash, amount);
|
|
627
|
+
tx.amount = amount;
|
|
628
|
+
}
|
|
629
|
+
} catch {
|
|
630
|
+
}
|
|
631
|
+
})
|
|
632
|
+
);
|
|
633
|
+
}
|
|
521
634
|
/**
|
|
522
635
|
* Patches `sdk.authenticateUser` so a fresh page can reuse the JWT from a
|
|
523
636
|
* prior session instead of triggering a new SIWE prompt. Runs inside
|
|
@@ -768,8 +881,10 @@ var ZyfaiAgent = class {
|
|
|
768
881
|
toDate,
|
|
769
882
|
rawOffset: firstOvershoot ? firstOvershoot.rawIdx : offset
|
|
770
883
|
}) : void 0;
|
|
884
|
+
const data = mapEntries(pageData, validChainId);
|
|
885
|
+
await this.resolveWithdrawnAmounts(data, validChainId, state.walletAddress);
|
|
771
886
|
return {
|
|
772
|
-
data
|
|
887
|
+
data,
|
|
773
888
|
hasMore,
|
|
774
889
|
nextCursor
|
|
775
890
|
};
|
|
@@ -860,7 +975,7 @@ async function withFailureReporting(apiKey, agentType, fn) {
|
|
|
860
975
|
}
|
|
861
976
|
|
|
862
977
|
// src/lib/helpers/withdraw-helper.ts
|
|
863
|
-
var
|
|
978
|
+
var import_viem2 = require("viem");
|
|
864
979
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
865
980
|
const target = asset.toUpperCase();
|
|
866
981
|
return agents.map((agent) => {
|
|
@@ -870,7 +985,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
870
985
|
);
|
|
871
986
|
if (!tokenBalance)
|
|
872
987
|
return { agent, balance: 0n };
|
|
873
|
-
return { agent, balance: (0,
|
|
988
|
+
return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
|
|
874
989
|
});
|
|
875
990
|
}
|
|
876
991
|
function planProportionalShares(balances, requested, totalAvailable) {
|
|
@@ -986,11 +1101,11 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
986
1101
|
}
|
|
987
1102
|
|
|
988
1103
|
// src/client.ts
|
|
989
|
-
var
|
|
990
|
-
var
|
|
1104
|
+
var import_viem4 = require("viem");
|
|
1105
|
+
var import_chains2 = require("viem/chains");
|
|
991
1106
|
|
|
992
1107
|
// src/lib/transfer-auth.ts
|
|
993
|
-
var
|
|
1108
|
+
var import_viem3 = require("viem");
|
|
994
1109
|
var ERC20_META_ABI = [
|
|
995
1110
|
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
996
1111
|
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
@@ -1022,16 +1137,16 @@ async function readTokenMeta(publicClient, token) {
|
|
|
1022
1137
|
function randomAuthNonce() {
|
|
1023
1138
|
const bytes = new Uint8Array(32);
|
|
1024
1139
|
globalThis.crypto.getRandomValues(bytes);
|
|
1025
|
-
return (0,
|
|
1140
|
+
return (0, import_viem3.bytesToHex)(bytes);
|
|
1026
1141
|
}
|
|
1027
1142
|
|
|
1028
1143
|
// src/lib/sponsor-client.ts
|
|
1029
1144
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1030
1145
|
async function postSponsorTransferAuth(input) {
|
|
1031
|
-
const
|
|
1146
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1032
1147
|
let res;
|
|
1033
1148
|
try {
|
|
1034
|
-
res = await fetch(`${
|
|
1149
|
+
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
1035
1150
|
method: "POST",
|
|
1036
1151
|
headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
|
|
1037
1152
|
body: JSON.stringify(input.body)
|
|
@@ -1134,9 +1249,9 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
1134
1249
|
8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
1135
1250
|
42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
|
|
1136
1251
|
};
|
|
1137
|
-
var
|
|
1138
|
-
8453:
|
|
1139
|
-
42161:
|
|
1252
|
+
var VIEM_CHAIN2 = {
|
|
1253
|
+
8453: import_chains2.base,
|
|
1254
|
+
42161: import_chains2.arbitrum
|
|
1140
1255
|
};
|
|
1141
1256
|
var OwneySDK = class {
|
|
1142
1257
|
agents = /* @__PURE__ */ new Map();
|
|
@@ -1249,14 +1364,14 @@ var OwneySDK = class {
|
|
|
1249
1364
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
1250
1365
|
// PublicClient/WalletClient param types — structurally identical at
|
|
1251
1366
|
// runtime, but the two share a name TS treats as unrelated.
|
|
1252
|
-
getPublicClient: (cid) => (0,
|
|
1253
|
-
chain:
|
|
1254
|
-
transport: (0,
|
|
1367
|
+
getPublicClient: (cid) => (0, import_viem4.createPublicClient)({
|
|
1368
|
+
chain: VIEM_CHAIN2[cid],
|
|
1369
|
+
transport: (0, import_viem4.custom)(provider)
|
|
1255
1370
|
}),
|
|
1256
|
-
getWalletClient: (cid) => (0,
|
|
1371
|
+
getWalletClient: (cid) => (0, import_viem4.createWalletClient)({
|
|
1257
1372
|
account: owner,
|
|
1258
|
-
chain:
|
|
1259
|
-
transport: (0,
|
|
1373
|
+
chain: VIEM_CHAIN2[cid],
|
|
1374
|
+
transport: (0, import_viem4.custom)(provider)
|
|
1260
1375
|
})
|
|
1261
1376
|
});
|
|
1262
1377
|
return this.cachedSponsoredCallback;
|
|
@@ -2116,7 +2231,7 @@ var OwneySDK = class {
|
|
|
2116
2231
|
};
|
|
2117
2232
|
|
|
2118
2233
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
2119
|
-
var
|
|
2234
|
+
var import_viem5 = require("viem");
|
|
2120
2235
|
var import_siwe = require("siwe");
|
|
2121
2236
|
var import_sdk2 = require("@zyfai/sdk");
|
|
2122
2237
|
|
|
@@ -2198,7 +2313,7 @@ function buildSIWXConfig(deps) {
|
|
|
2198
2313
|
issuedAt,
|
|
2199
2314
|
toString() {
|
|
2200
2315
|
return new import_siwe.SiweMessage({
|
|
2201
|
-
address: (0,
|
|
2316
|
+
address: (0, import_viem5.getAddress)(accountAddress),
|
|
2202
2317
|
chainId: numericChainId(chainId),
|
|
2203
2318
|
domain,
|
|
2204
2319
|
uri,
|
|
@@ -2274,9 +2389,9 @@ function buildSIWXConfig(deps) {
|
|
|
2274
2389
|
}
|
|
2275
2390
|
function createOwneySIWX(config) {
|
|
2276
2391
|
const zyfai = new import_sdk2.ZyfaiSDK({ apiKey: config.apiKey });
|
|
2277
|
-
const
|
|
2392
|
+
const http2 = zyfai.httpClient;
|
|
2278
2393
|
return buildSIWXConfig({
|
|
2279
|
-
post: (url, data) =>
|
|
2394
|
+
post: (url, data) => http2.post(url, data),
|
|
2280
2395
|
referralSource: config.referralSource
|
|
2281
2396
|
});
|
|
2282
2397
|
}
|
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 = {
|
|
@@ -236,6 +238,14 @@ function mapApyHistory(raw) {
|
|
|
236
238
|
apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain)
|
|
237
239
|
};
|
|
238
240
|
}
|
|
241
|
+
function splitOpportunity(opportunity) {
|
|
242
|
+
const match = opportunity.match(/^(.*?)\s*\(([^)]*)\)\s*$/);
|
|
243
|
+
if (match) {
|
|
244
|
+
const pool = match[2].trim();
|
|
245
|
+
return { protocol: match[1].trim(), pool: pool || void 0 };
|
|
246
|
+
}
|
|
247
|
+
return { protocol: opportunity.trim() };
|
|
248
|
+
}
|
|
239
249
|
function mapEntries(rawEntries, chainId) {
|
|
240
250
|
const actionMap = {
|
|
241
251
|
"Top up wallet": "Top up",
|
|
@@ -255,21 +265,26 @@ function mapEntries(rawEntries, chainId) {
|
|
|
255
265
|
);
|
|
256
266
|
oldApy = Number(rawLog.oldApy);
|
|
257
267
|
newApy = Number(rawLog.newApy);
|
|
268
|
+
const from = splitOpportunity(rawLog.oldOpportunity);
|
|
269
|
+
const to = splitOpportunity(rawLog.newOpportunity);
|
|
258
270
|
rebalanceLog = [
|
|
259
271
|
{
|
|
260
|
-
fromProtocol:
|
|
261
|
-
toProtocol:
|
|
272
|
+
fromProtocol: from.protocol,
|
|
273
|
+
toProtocol: to.protocol,
|
|
274
|
+
fromPool: from.pool,
|
|
275
|
+
toPool: to.pool,
|
|
262
276
|
tokenSymbol: matched?.token_symbol ?? "",
|
|
263
277
|
amount: matched ? String(hexToDecimal(matched.amount || "0x")) : "",
|
|
264
278
|
status: "success"
|
|
265
279
|
}
|
|
266
280
|
];
|
|
267
281
|
}
|
|
282
|
+
const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
|
|
268
283
|
const rawAmount = entry?.positions?.[0]?.amount;
|
|
269
|
-
const hasAmount = typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
284
|
+
const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
270
285
|
return {
|
|
271
286
|
agent: "zyfai",
|
|
272
|
-
action:
|
|
287
|
+
action: mappedAction,
|
|
273
288
|
date: entry.date || "",
|
|
274
289
|
newApy: newApy === null ? null : String(newApy),
|
|
275
290
|
oldApy: oldApy === null ? null : String(oldApy),
|
|
@@ -361,6 +376,33 @@ function computeAllocationApy(positions) {
|
|
|
361
376
|
return { totalApy, apyByChainAndAsset };
|
|
362
377
|
}
|
|
363
378
|
|
|
379
|
+
// src/agents/zyfai/zyfai.withdraw-amount.ts
|
|
380
|
+
var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
381
|
+
function topicToAddress(topic) {
|
|
382
|
+
return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
|
|
383
|
+
}
|
|
384
|
+
function extractWithdrawnAmount(logs, recipient, token, decimals) {
|
|
385
|
+
const wantRecipient = recipient.toLowerCase();
|
|
386
|
+
const wantToken = token.toLowerCase();
|
|
387
|
+
let total = 0n;
|
|
388
|
+
let matched = false;
|
|
389
|
+
for (const log of logs) {
|
|
390
|
+
if (log.address.toLowerCase() !== wantToken)
|
|
391
|
+
continue;
|
|
392
|
+
if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC)
|
|
393
|
+
continue;
|
|
394
|
+
if (topicToAddress(log.topics[2]) !== wantRecipient)
|
|
395
|
+
continue;
|
|
396
|
+
if (!log.data || log.data === "0x")
|
|
397
|
+
continue;
|
|
398
|
+
total += BigInt(log.data);
|
|
399
|
+
matched = true;
|
|
400
|
+
}
|
|
401
|
+
if (!matched)
|
|
402
|
+
return void 0;
|
|
403
|
+
return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
|
|
404
|
+
}
|
|
405
|
+
|
|
364
406
|
// src/agents/zyfai/zyfai.history-cursor.ts
|
|
365
407
|
var InvalidHistoryCursorError = class extends Error {
|
|
366
408
|
code = "invalid_cursor";
|
|
@@ -459,6 +501,7 @@ var DEFAULT_ZYFAI_RPC_URLS = {
|
|
|
459
501
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
460
502
|
42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
|
|
461
503
|
};
|
|
504
|
+
var VIEM_CHAIN = { 8453: base, 42161: arbitrum };
|
|
462
505
|
var ZyfaiAgent = class {
|
|
463
506
|
id = "zyfai";
|
|
464
507
|
supportedChainIds = [8453, 42161];
|
|
@@ -479,13 +522,83 @@ var ZyfaiAgent = class {
|
|
|
479
522
|
connectedChainId = null;
|
|
480
523
|
smartWalletCache = /* @__PURE__ */ new Map();
|
|
481
524
|
connectAuthPromise = null;
|
|
525
|
+
rpcUrls;
|
|
526
|
+
publicClients = /* @__PURE__ */ new Map();
|
|
527
|
+
// txHash -> resolved withdrawn amount. Receipts are immutable, so a
|
|
528
|
+
// successful decode is cached forever; failures are NOT cached so a transient
|
|
529
|
+
// RPC error retries on the next fetch.
|
|
530
|
+
withdrawAmountCache = /* @__PURE__ */ new Map();
|
|
482
531
|
constructor(apiKey, rpcUrls) {
|
|
532
|
+
this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
|
|
483
533
|
this.sdk = new ZyfaiSDK({
|
|
484
534
|
apiKey,
|
|
485
|
-
rpcUrls: rpcUrls
|
|
535
|
+
rpcUrls: this.rpcUrls
|
|
486
536
|
});
|
|
487
537
|
this.installAuthCache();
|
|
488
538
|
}
|
|
539
|
+
getPublicClient(chainId) {
|
|
540
|
+
const cached = this.publicClients.get(chainId);
|
|
541
|
+
if (cached)
|
|
542
|
+
return cached;
|
|
543
|
+
const client = createPublicClient({
|
|
544
|
+
chain: VIEM_CHAIN[chainId],
|
|
545
|
+
transport: http(this.rpcUrls[chainId])
|
|
546
|
+
});
|
|
547
|
+
this.publicClients.set(chainId, client);
|
|
548
|
+
return client;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Fills in the true withdrawn amount for `Withdraw` entries by decoding the
|
|
552
|
+
* USDC `Transfer` that lands in the user's wallet on-chain. The Zyfai history
|
|
553
|
+
* payload only reports the *remaining* position for a partial withdraw (see
|
|
554
|
+
* the note in `mapEntries`), so without this the UI shows the leftover
|
|
555
|
+
* balance instead of the amount withdrawn.
|
|
556
|
+
*
|
|
557
|
+
* Mutates `entries` in place. Runs all lookups concurrently and is tolerant
|
|
558
|
+
* of RPC failures: an entry whose amount can't be resolved keeps
|
|
559
|
+
* `amount: undefined`, which consumers render as a hidden/retryable row
|
|
560
|
+
* rather than a wrong number.
|
|
561
|
+
*/
|
|
562
|
+
async resolveWithdrawnAmounts(entries, chainId, recipient) {
|
|
563
|
+
const asset = SupportedAssets.find(
|
|
564
|
+
(a) => a.chainId === chainId && a.symbol === "USDC"
|
|
565
|
+
);
|
|
566
|
+
if (!asset)
|
|
567
|
+
return;
|
|
568
|
+
const withdrawals = entries.filter(
|
|
569
|
+
(e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
|
|
570
|
+
);
|
|
571
|
+
if (withdrawals.length === 0)
|
|
572
|
+
return;
|
|
573
|
+
const client = this.getPublicClient(chainId);
|
|
574
|
+
await Promise.all(
|
|
575
|
+
withdrawals.map(async (entry) => {
|
|
576
|
+
const tx = entry.transactions[0];
|
|
577
|
+
const txHash = tx.txHashes[0];
|
|
578
|
+
const cached = this.withdrawAmountCache.get(txHash);
|
|
579
|
+
if (cached !== void 0) {
|
|
580
|
+
tx.amount = cached;
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
try {
|
|
584
|
+
const receipt = await client.getTransactionReceipt({
|
|
585
|
+
hash: txHash
|
|
586
|
+
});
|
|
587
|
+
const amount = extractWithdrawnAmount(
|
|
588
|
+
receipt.logs,
|
|
589
|
+
recipient,
|
|
590
|
+
asset.address,
|
|
591
|
+
asset.decimals
|
|
592
|
+
);
|
|
593
|
+
if (amount !== void 0) {
|
|
594
|
+
this.withdrawAmountCache.set(txHash, amount);
|
|
595
|
+
tx.amount = amount;
|
|
596
|
+
}
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
})
|
|
600
|
+
);
|
|
601
|
+
}
|
|
489
602
|
/**
|
|
490
603
|
* Patches `sdk.authenticateUser` so a fresh page can reuse the JWT from a
|
|
491
604
|
* prior session instead of triggering a new SIWE prompt. Runs inside
|
|
@@ -736,8 +849,10 @@ var ZyfaiAgent = class {
|
|
|
736
849
|
toDate,
|
|
737
850
|
rawOffset: firstOvershoot ? firstOvershoot.rawIdx : offset
|
|
738
851
|
}) : void 0;
|
|
852
|
+
const data = mapEntries(pageData, validChainId);
|
|
853
|
+
await this.resolveWithdrawnAmounts(data, validChainId, state.walletAddress);
|
|
739
854
|
return {
|
|
740
|
-
data
|
|
855
|
+
data,
|
|
741
856
|
hasMore,
|
|
742
857
|
nextCursor
|
|
743
858
|
};
|
|
@@ -955,11 +1070,11 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
955
1070
|
|
|
956
1071
|
// src/client.ts
|
|
957
1072
|
import {
|
|
958
|
-
createPublicClient,
|
|
1073
|
+
createPublicClient as createPublicClient2,
|
|
959
1074
|
createWalletClient,
|
|
960
1075
|
custom
|
|
961
1076
|
} from "viem";
|
|
962
|
-
import { base, arbitrum } from "viem/chains";
|
|
1077
|
+
import { base as base2, arbitrum as arbitrum2 } from "viem/chains";
|
|
963
1078
|
|
|
964
1079
|
// src/lib/transfer-auth.ts
|
|
965
1080
|
import { bytesToHex } from "viem";
|
|
@@ -1000,10 +1115,10 @@ function randomAuthNonce() {
|
|
|
1000
1115
|
// src/lib/sponsor-client.ts
|
|
1001
1116
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1002
1117
|
async function postSponsorTransferAuth(input) {
|
|
1003
|
-
const
|
|
1118
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1004
1119
|
let res;
|
|
1005
1120
|
try {
|
|
1006
|
-
res = await fetch(`${
|
|
1121
|
+
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
1007
1122
|
method: "POST",
|
|
1008
1123
|
headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
|
|
1009
1124
|
body: JSON.stringify(input.body)
|
|
@@ -1106,9 +1221,9 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
1106
1221
|
8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
1107
1222
|
42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
|
|
1108
1223
|
};
|
|
1109
|
-
var
|
|
1110
|
-
8453:
|
|
1111
|
-
42161:
|
|
1224
|
+
var VIEM_CHAIN2 = {
|
|
1225
|
+
8453: base2,
|
|
1226
|
+
42161: arbitrum2
|
|
1112
1227
|
};
|
|
1113
1228
|
var OwneySDK = class {
|
|
1114
1229
|
agents = /* @__PURE__ */ new Map();
|
|
@@ -1221,13 +1336,13 @@ var OwneySDK = class {
|
|
|
1221
1336
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
1222
1337
|
// PublicClient/WalletClient param types — structurally identical at
|
|
1223
1338
|
// runtime, but the two share a name TS treats as unrelated.
|
|
1224
|
-
getPublicClient: (cid) =>
|
|
1225
|
-
chain:
|
|
1339
|
+
getPublicClient: (cid) => createPublicClient2({
|
|
1340
|
+
chain: VIEM_CHAIN2[cid],
|
|
1226
1341
|
transport: custom(provider)
|
|
1227
1342
|
}),
|
|
1228
1343
|
getWalletClient: (cid) => createWalletClient({
|
|
1229
1344
|
account: owner,
|
|
1230
|
-
chain:
|
|
1345
|
+
chain: VIEM_CHAIN2[cid],
|
|
1231
1346
|
transport: custom(provider)
|
|
1232
1347
|
})
|
|
1233
1348
|
});
|
|
@@ -2246,9 +2361,9 @@ function buildSIWXConfig(deps) {
|
|
|
2246
2361
|
}
|
|
2247
2362
|
function createOwneySIWX(config) {
|
|
2248
2363
|
const zyfai = new ZyfaiSDK2({ apiKey: config.apiKey });
|
|
2249
|
-
const
|
|
2364
|
+
const http2 = zyfai.httpClient;
|
|
2250
2365
|
return buildSIWXConfig({
|
|
2251
|
-
post: (url, data) =>
|
|
2366
|
+
post: (url, data) => http2.post(url, data),
|
|
2252
2367
|
referralSource: config.referralSource
|
|
2253
2368
|
});
|
|
2254
2369
|
}
|