@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 +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 = {
|
|
@@ -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:
|
|
305
|
-
toProtocol:
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
1014
|
-
var
|
|
1128
|
+
var import_viem4 = require("viem");
|
|
1129
|
+
var import_chains2 = require("viem/chains");
|
|
1015
1130
|
|
|
1016
1131
|
// src/lib/transfer-auth.ts
|
|
1017
|
-
var
|
|
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,
|
|
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
|
|
1170
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1056
1171
|
let res;
|
|
1057
1172
|
try {
|
|
1058
|
-
res = await fetch(`${
|
|
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
|
|
1162
|
-
8453:
|
|
1163
|
-
42161:
|
|
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,
|
|
1277
|
-
chain:
|
|
1278
|
-
transport: (0,
|
|
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,
|
|
1395
|
+
getWalletClient: (cid) => (0, import_viem4.createWalletClient)({
|
|
1281
1396
|
account: owner,
|
|
1282
|
-
chain:
|
|
1283
|
-
transport: (0,
|
|
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
|
|
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,
|
|
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
|
|
2428
|
+
const http2 = zyfai.httpClient;
|
|
2314
2429
|
return buildSIWXConfig({
|
|
2315
|
-
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:
|
|
273
|
-
toProtocol:
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
1142
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1028
1143
|
let res;
|
|
1029
1144
|
try {
|
|
1030
|
-
res = await fetch(`${
|
|
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
|
|
1134
|
-
8453:
|
|
1135
|
-
42161:
|
|
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) =>
|
|
1249
|
-
chain:
|
|
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:
|
|
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
|
|
2400
|
+
const http2 = zyfai.httpClient;
|
|
2286
2401
|
return buildSIWXConfig({
|
|
2287
|
-
post: (url, data) =>
|
|
2402
|
+
post: (url, data) => http2.post(url, data),
|
|
2288
2403
|
referralSource: config.referralSource
|
|
2289
2404
|
});
|
|
2290
2405
|
}
|