@owney/sdk 0.7.25-beta.10 → 0.7.25-beta.11
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 +901 -242
- package/dist/index.d.cts +317 -225
- package/dist/index.d.ts +317 -225
- package/dist/index.js +840 -181
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,96 @@ __export(index_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(index_exports);
|
|
34
34
|
|
|
35
|
+
// src/lib/funding-evidence.ts
|
|
36
|
+
var import_viem = require("viem");
|
|
37
|
+
function notifyFunding(callback, evidence) {
|
|
38
|
+
try {
|
|
39
|
+
void Promise.resolve(callback?.({ ...evidence })).catch(() => {
|
|
40
|
+
});
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
var fullWithdrawalAbi = (0, import_viem.parseAbi)(["function withdrawAllAssetToUser(address recipient, address asset)"]);
|
|
45
|
+
var withdrawalEventAbi = (0, import_viem.parseAbi)(["event WithdrewTokenToUser(address indexed owner, address indexed recipient, address indexed token, uint256 amount)"]);
|
|
46
|
+
function isFullYieldseekerWithdrawal(transaction, evidence, tokenAddress) {
|
|
47
|
+
if (evidence.agentId !== "yieldseeker" || transaction.chainId !== evidence.chainId || transaction.hash.toLowerCase() !== evidence.txHash?.toLowerCase() || transaction.to?.toLowerCase() !== evidence.agentWallet?.toLowerCase() || transaction.from.toLowerCase() !== evidence.walletAddress.toLowerCase()) return false;
|
|
48
|
+
try {
|
|
49
|
+
const decoded = (0, import_viem.decodeFunctionData)({ abi: fullWithdrawalAbi, data: transaction.input });
|
|
50
|
+
return decoded.args[0].toLowerCase() === evidence.walletAddress.toLowerCase() && decoded.args[1].toLowerCase() === tokenAddress.toLowerCase();
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function inspectFundingReceipt(receipt, evidence, tokenAddress, direction) {
|
|
56
|
+
if (receipt.status !== "success") return { ...evidence, transfer: "failed", delivery: "failed" };
|
|
57
|
+
let amount = 0n;
|
|
58
|
+
const seen = /* @__PURE__ */ new Set();
|
|
59
|
+
const attributed = /* @__PURE__ */ new Map();
|
|
60
|
+
const agent = evidence.agentWallet?.toLowerCase();
|
|
61
|
+
const owner = evidence.walletAddress.toLowerCase();
|
|
62
|
+
const logIndexes = [];
|
|
63
|
+
const transferLogs = [];
|
|
64
|
+
const zeroTransferLogs = [];
|
|
65
|
+
for (const log of [...receipt.logs].sort((a, b) => a.logIndex - b.logIndex)) {
|
|
66
|
+
if (log.address.toLowerCase() !== tokenAddress.toLowerCase()) continue;
|
|
67
|
+
if (seen.has(log.logIndex)) continue;
|
|
68
|
+
seen.add(log.logIndex);
|
|
69
|
+
try {
|
|
70
|
+
const event = (0, import_viem.decodeEventLog)({ abi: import_viem.erc20Abi, data: log.data, topics: log.topics });
|
|
71
|
+
if (event.eventName !== "Transfer") continue;
|
|
72
|
+
const { from, to, value } = event.args;
|
|
73
|
+
if (direction === "withdraw" && value === 0n && from.toLowerCase() === agent && to.toLowerCase() === owner)
|
|
74
|
+
zeroTransferLogs.push(log.logIndex);
|
|
75
|
+
let matched = 0n;
|
|
76
|
+
if (direction === "deposit") {
|
|
77
|
+
if (to.toLowerCase() === agent) matched = value;
|
|
78
|
+
} else {
|
|
79
|
+
const sender = from.toLowerCase();
|
|
80
|
+
const recipient = to.toLowerCase();
|
|
81
|
+
const available = sender === agent ? value : attributed.get(sender) ?? 0n;
|
|
82
|
+
const carried = available < value ? available : value;
|
|
83
|
+
if (sender !== agent) attributed.set(sender, available - carried);
|
|
84
|
+
if (recipient === owner) matched = carried;
|
|
85
|
+
else if (recipient !== agent) attributed.set(recipient, (attributed.get(recipient) ?? 0n) + carried);
|
|
86
|
+
}
|
|
87
|
+
if (matched === 0n) continue;
|
|
88
|
+
amount += matched;
|
|
89
|
+
transferLogs.push({ logIndex: log.logIndex, amountRaw: matched.toString() });
|
|
90
|
+
logIndexes.push(log.logIndex);
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const expected = /^\d+$/.test(evidence.intendedAmount) ? BigInt(evidence.intendedAmount) : void 0;
|
|
95
|
+
const emptyPayout = direction === "withdraw" && evidence.agentId === "yieldseeker" && amount === 0n && zeroTransferLogs.length > 0 && receipt.logs.some((log) => {
|
|
96
|
+
if (log.address.toLowerCase() !== agent) return false;
|
|
97
|
+
try {
|
|
98
|
+
const { args } = (0, import_viem.decodeEventLog)({ abi: withdrawalEventAbi, data: log.data, topics: log.topics });
|
|
99
|
+
return args.owner.toLowerCase() === owner && args.recipient.toLowerCase() === owner && args.token.toLowerCase() === tokenAddress.toLowerCase() && args.amount === 0n;
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
if (emptyPayout) return {
|
|
105
|
+
...evidence,
|
|
106
|
+
blockNumber: receipt.blockNumber.toString(),
|
|
107
|
+
confirmedAmount: "0",
|
|
108
|
+
logIndexes: zeroTransferLogs,
|
|
109
|
+
transferLogs: zeroTransferLogs.map((logIndex) => ({ logIndex, amountRaw: "0" })),
|
|
110
|
+
transfer: "failed",
|
|
111
|
+
delivery: "failed"
|
|
112
|
+
};
|
|
113
|
+
const delivered = amount > 0n && (expected === void 0 || amount >= expected);
|
|
114
|
+
return {
|
|
115
|
+
...evidence,
|
|
116
|
+
blockNumber: receipt.blockNumber.toString(),
|
|
117
|
+
logIndexes,
|
|
118
|
+
transferLogs,
|
|
119
|
+
...amount > 0n ? { confirmedAmount: amount.toString() } : {},
|
|
120
|
+
transfer: delivered ? "confirmed" : "unknown",
|
|
121
|
+
delivery: direction === "withdraw" ? delivered ? "confirmed" : "unknown" : "not-applicable"
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
35
125
|
// src/lib/deposit-batch-callback.ts
|
|
36
126
|
var batchCallbacks = /* @__PURE__ */ new WeakMap();
|
|
37
127
|
var getDepositBatchTransfer = (callback) => callback ? batchCallbacks.get(callback) : void 0;
|
|
@@ -246,9 +336,72 @@ var AgentReads = class {
|
|
|
246
336
|
}
|
|
247
337
|
};
|
|
248
338
|
|
|
339
|
+
// src/agents/zyfai/zyfai.withdraw-submission.ts
|
|
340
|
+
var listenersByClient = /* @__PURE__ */ new WeakMap();
|
|
341
|
+
function observeWithdrawalSubmission(sdk, chainId, token) {
|
|
342
|
+
const client = sdk.httpClient;
|
|
343
|
+
if (!client || typeof client.get !== "function" || typeof client.post !== "function")
|
|
344
|
+
return { attempted: () => void 0, rejected: () => false, request: () => void 0, stop: () => {
|
|
345
|
+
} };
|
|
346
|
+
let listeners = listenersByClient.get(client);
|
|
347
|
+
if (!listeners) {
|
|
348
|
+
listeners = /* @__PURE__ */ new Set();
|
|
349
|
+
listenersByClient.set(client, listeners);
|
|
350
|
+
const observers = listeners;
|
|
351
|
+
for (const method of ["get", "post"]) {
|
|
352
|
+
const original = client[method];
|
|
353
|
+
client[method] = async function(...args) {
|
|
354
|
+
const [url, options] = args;
|
|
355
|
+
const withdrawal = method === "get" && url === "/users/withdraw" || method === "post" && url === "/users/partial-withdraw";
|
|
356
|
+
const payload = method === "get" ? options?.params : options;
|
|
357
|
+
const matching = withdrawal ? [...observers].filter((observer) => observer.chainId === payload?.chainId && observer.token === payload?.tokenSymbol) : [];
|
|
358
|
+
const startedAt = Date.now();
|
|
359
|
+
const request2 = {
|
|
360
|
+
attempted: true,
|
|
361
|
+
method: method === "get" ? "GET" : "POST",
|
|
362
|
+
path: method === "get" ? "/users/withdraw" : "/users/partial-withdraw"
|
|
363
|
+
};
|
|
364
|
+
const notify = (outcome) => {
|
|
365
|
+
if (outcome === "rejected" && matching.length !== 1) return;
|
|
366
|
+
for (const observer of matching) {
|
|
367
|
+
try {
|
|
368
|
+
observer.notify(outcome, { ...request2 });
|
|
369
|
+
} catch {
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
notify("attempted");
|
|
374
|
+
try {
|
|
375
|
+
return await original.apply(this, args);
|
|
376
|
+
} catch (error) {
|
|
377
|
+
const message = error instanceof Error ? error.message : "";
|
|
378
|
+
request2.failure = message === "Unauthorized: Invalid API key" ? "unauthorized" : message === "Forbidden: Access denied" ? "forbidden" : message === "Rate limit exceeded. Please try again later." ? "rate-limited" : message === "Network error: Unable to reach the server" ? "network" : "other";
|
|
379
|
+
if (["unauthorized", "forbidden", "rate-limited"].includes(request2.failure)) notify("rejected");
|
|
380
|
+
throw error;
|
|
381
|
+
} finally {
|
|
382
|
+
request2.elapsedMs = Math.max(0, Date.now() - startedAt);
|
|
383
|
+
notify("finished");
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
let submitted = false;
|
|
389
|
+
let rejected = false;
|
|
390
|
+
let request = { attempted: false };
|
|
391
|
+
const listener = { chainId, token, notify: (outcome, evidence) => {
|
|
392
|
+
request = evidence;
|
|
393
|
+
if (outcome === "attempted") submitted = true;
|
|
394
|
+
else if (outcome === "rejected") rejected = true;
|
|
395
|
+
} };
|
|
396
|
+
listeners.add(listener);
|
|
397
|
+
return { attempted: () => submitted, rejected: () => rejected, request: () => ({ ...request }), stop: () => {
|
|
398
|
+
listeners.delete(listener);
|
|
399
|
+
} };
|
|
400
|
+
}
|
|
401
|
+
|
|
249
402
|
// src/agents/zyfai/zyfai.agent.ts
|
|
250
403
|
var import_sdk = require("@zyfai/sdk");
|
|
251
|
-
var
|
|
404
|
+
var import_viem3 = require("viem");
|
|
252
405
|
var import_chains = require("viem/chains");
|
|
253
406
|
|
|
254
407
|
// src/types/config.ts
|
|
@@ -421,7 +574,11 @@ function mapPendingAllocations(raw2) {
|
|
|
421
574
|
}
|
|
422
575
|
function mapBalances(raw2, _chainId, smartWallet) {
|
|
423
576
|
const portfolio = raw2.portfolio;
|
|
424
|
-
|
|
577
|
+
if (!portfolio?.portfolioByChain || typeof portfolio.portfolioByChain !== "object")
|
|
578
|
+
throw new Error("Zyfai balance snapshot is unavailable.");
|
|
579
|
+
const portfolioByChain = portfolio.portfolioByChain;
|
|
580
|
+
const fetchedAt = Date.now();
|
|
581
|
+
const provenance = portfolio;
|
|
425
582
|
let totalBalance = 0;
|
|
426
583
|
const tokens = [];
|
|
427
584
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
@@ -430,7 +587,8 @@ function mapBalances(raw2, _chainId, smartWallet) {
|
|
|
430
587
|
symbol,
|
|
431
588
|
{ balance, balanceWithFee, decimals }
|
|
432
589
|
] of Object.entries(tokensBySymbol ?? {})) {
|
|
433
|
-
|
|
590
|
+
if (balanceWithFee === void 0 && balance === void 0) throw new Error("Zyfai asset balance is unavailable.");
|
|
591
|
+
const amount = hexToDecimal(balanceWithFee ?? balance, decimals);
|
|
434
592
|
totalBalance += amount;
|
|
435
593
|
tokens.push({
|
|
436
594
|
chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
|
|
@@ -480,6 +638,15 @@ function mapBalances(raw2, _chainId, smartWallet) {
|
|
|
480
638
|
totalBalanceAsset: "usdc",
|
|
481
639
|
tokens,
|
|
482
640
|
positions,
|
|
641
|
+
readMetadata: tokens.map((token) => ({
|
|
642
|
+
chainId: token.chainId,
|
|
643
|
+
asset: token.asset,
|
|
644
|
+
fetchedAt,
|
|
645
|
+
providerUpdatedAt: typeof provenance.updatedAt === "string" ? provenance.updatedAt : void 0,
|
|
646
|
+
snapshotId: provenance.snapshotId === void 0 ? void 0 : String(provenance.snapshotId),
|
|
647
|
+
blockNumber: provenance.blockNumber === void 0 ? void 0 : String(provenance.blockNumber),
|
|
648
|
+
positionsStatus: Array.isArray(portfolio.positions) ? "available" : "unavailable"
|
|
649
|
+
})),
|
|
483
650
|
...pendingAllocations ? { pendingAllocations } : {}
|
|
484
651
|
};
|
|
485
652
|
}
|
|
@@ -820,28 +987,6 @@ function mapDailyEarnings(raw2, chainId, tokenSymbol) {
|
|
|
820
987
|
return { walletAddress: raw2.walletAddress, chainId, assets };
|
|
821
988
|
}
|
|
822
989
|
|
|
823
|
-
// src/agents/zyfai/zyfai.withdraw-amount.ts
|
|
824
|
-
var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
825
|
-
function topicToAddress(topic) {
|
|
826
|
-
return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
|
|
827
|
-
}
|
|
828
|
-
function extractWithdrawnAmount(logs, recipient, token, decimals) {
|
|
829
|
-
const wantRecipient = recipient.toLowerCase();
|
|
830
|
-
const wantToken = token.toLowerCase();
|
|
831
|
-
let total = 0n;
|
|
832
|
-
let matched = false;
|
|
833
|
-
for (const log of logs) {
|
|
834
|
-
if (log.address.toLowerCase() !== wantToken) continue;
|
|
835
|
-
if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC) continue;
|
|
836
|
-
if (topicToAddress(log.topics[2]) !== wantRecipient) continue;
|
|
837
|
-
if (!log.data || log.data === "0x") continue;
|
|
838
|
-
total += BigInt(log.data);
|
|
839
|
-
matched = true;
|
|
840
|
-
}
|
|
841
|
-
if (!matched) return void 0;
|
|
842
|
-
return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
|
|
843
|
-
}
|
|
844
|
-
|
|
845
990
|
// src/agents/zyfai/zyfai.history-cursor.ts
|
|
846
991
|
var InvalidHistoryCursorError = class extends Error {
|
|
847
992
|
code = "invalid_cursor";
|
|
@@ -1130,7 +1275,7 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
|
|
|
1130
1275
|
}
|
|
1131
1276
|
|
|
1132
1277
|
// src/lib/paid-rpc.ts
|
|
1133
|
-
var
|
|
1278
|
+
var import_viem2 = require("viem");
|
|
1134
1279
|
var PAID_RPC_RETRY_COUNT = 3;
|
|
1135
1280
|
var PAID_RPC_RETRY_DELAY_MS = 1e3;
|
|
1136
1281
|
function configuredRpcProxyBaseUrl(baseUrl) {
|
|
@@ -1166,9 +1311,9 @@ function createPaidRpcClient(chain, rpcUrls) {
|
|
|
1166
1311
|
rpcUrls,
|
|
1167
1312
|
chain.id
|
|
1168
1313
|
);
|
|
1169
|
-
return (0,
|
|
1314
|
+
return (0, import_viem2.createPublicClient)({
|
|
1170
1315
|
chain,
|
|
1171
|
-
transport: (0,
|
|
1316
|
+
transport: (0, import_viem2.http)(url, {
|
|
1172
1317
|
retryCount: PAID_RPC_RETRY_COUNT,
|
|
1173
1318
|
retryDelay: PAID_RPC_RETRY_DELAY_MS
|
|
1174
1319
|
})
|
|
@@ -1265,7 +1410,7 @@ async function withPaidRpcDiagnostics(operation, chainId, rpcMethod, agentId) {
|
|
|
1265
1410
|
}
|
|
1266
1411
|
|
|
1267
1412
|
// src/agents/zyfai/zyfai.agent.ts
|
|
1268
|
-
var ERC7579_IS_MODULE_INSTALLED_ABI = (0,
|
|
1413
|
+
var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem3.parseAbi)([
|
|
1269
1414
|
"function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
|
|
1270
1415
|
]);
|
|
1271
1416
|
var WETH_ADDRESS_BY_CHAIN = {
|
|
@@ -1324,10 +1469,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1324
1469
|
connectAuthPromise = null;
|
|
1325
1470
|
rpcUrls;
|
|
1326
1471
|
publicClients = /* @__PURE__ */ new Map();
|
|
1327
|
-
//
|
|
1328
|
-
//
|
|
1329
|
-
|
|
1330
|
-
withdrawAmountCache = /* @__PURE__ */ new Map();
|
|
1472
|
+
// Receipt-derived amounts and log identities, scoped to the owner and asset.
|
|
1473
|
+
// Failures remain retryable; successful immutable evidence has a bounded cache.
|
|
1474
|
+
fundingHistoryCache = /* @__PURE__ */ new Map();
|
|
1331
1475
|
earningsReads = /* @__PURE__ */ new Map();
|
|
1332
1476
|
earningsRefreshes = /* @__PURE__ */ new Map();
|
|
1333
1477
|
earningsSnapshot = null;
|
|
@@ -1355,8 +1499,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1355
1499
|
return client;
|
|
1356
1500
|
}
|
|
1357
1501
|
/**
|
|
1358
|
-
*
|
|
1359
|
-
*
|
|
1502
|
+
* Resolves funding amounts and log identities from token receipts. Withdrawals
|
|
1503
|
+
* must travel from this agent wallet to its owner; top-ups must reach the agent.
|
|
1504
|
+
* The Zyfai history
|
|
1360
1505
|
* payload only reports the *remaining* position for a partial withdraw (see
|
|
1361
1506
|
* the note in `mapEntries`), so without this the UI shows the leftover
|
|
1362
1507
|
* balance instead of the amount withdrawn.
|
|
@@ -1368,48 +1513,62 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1368
1513
|
* Entries with no symbol (older payload shapes) fall back to USDC to
|
|
1369
1514
|
* preserve prior behavior.
|
|
1370
1515
|
*
|
|
1371
|
-
* Mutates `entries` in place
|
|
1372
|
-
*
|
|
1373
|
-
* `amount: undefined`, which consumers render as a hidden/retryable row
|
|
1374
|
-
* rather than a wrong number.
|
|
1516
|
+
* Mutates `entries` in place, sharing receipt requests within the page. RPC
|
|
1517
|
+
* failures leave provider top-ups unchanged and withdrawal amounts unknown.
|
|
1375
1518
|
*/
|
|
1376
|
-
async
|
|
1377
|
-
const
|
|
1378
|
-
(e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
|
|
1519
|
+
async resolveFundingTransfers(entries, chainId, recipient, smartWallet, tokenSymbol) {
|
|
1520
|
+
const movements = entries.filter(
|
|
1521
|
+
(e) => (e.action === "Withdraw" || e.action === "Top up") && e.transactions[0]?.txHashes[0]
|
|
1379
1522
|
);
|
|
1380
|
-
if (
|
|
1523
|
+
if (movements.length === 0) return;
|
|
1381
1524
|
const client = this.getPublicClient(chainId);
|
|
1525
|
+
const receipts = /* @__PURE__ */ new Map();
|
|
1382
1526
|
await Promise.all(
|
|
1383
|
-
|
|
1527
|
+
movements.map(async (entry) => {
|
|
1384
1528
|
const tx = entry.transactions[0];
|
|
1385
1529
|
const txHash = tx.txHashes[0];
|
|
1386
|
-
const rawSymbol = tx.tokenSymbol;
|
|
1530
|
+
const rawSymbol = tx.tokenSymbol ?? tokenSymbol;
|
|
1387
1531
|
const normalizedSymbol = rawSymbol ? rawSymbol.toLowerCase() === "eth" ? "WETH" : rawSymbol.toUpperCase() : "USDC";
|
|
1388
1532
|
const asset = SupportedAssets.find(
|
|
1389
1533
|
(a) => a.chainId === chainId && a.symbol === normalizedSymbol
|
|
1390
|
-
) ?? SupportedAssets.find(
|
|
1391
|
-
(a) => a.chainId === chainId && a.symbol === "USDC"
|
|
1392
1534
|
);
|
|
1393
1535
|
if (!asset) return;
|
|
1394
|
-
|
|
1395
|
-
|
|
1536
|
+
tx.tokenSymbol = asset.symbol;
|
|
1537
|
+
tx.tokenAddress = asset.address;
|
|
1538
|
+
tx.agentWallet = smartWallet;
|
|
1539
|
+
entry.id = `${chainId}:${txHash.toLowerCase()}:${entry.action}:${asset.address.toLowerCase()}:${smartWallet.toLowerCase()}`;
|
|
1540
|
+
if (!/^0x[0-9a-f]{64}$/i.test(txHash)) return;
|
|
1541
|
+
const cacheKey = `${entry.id}:${recipient.toLowerCase()}`;
|
|
1542
|
+
const cached = this.fundingHistoryCache.get(cacheKey);
|
|
1396
1543
|
if (cached !== void 0) {
|
|
1397
|
-
tx
|
|
1544
|
+
Object.assign(tx, cached);
|
|
1398
1545
|
return;
|
|
1399
1546
|
}
|
|
1400
1547
|
try {
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
asset.
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1548
|
+
if (!receipts.has(txHash)) receipts.set(txHash, client.getTransactionReceipt({ hash: txHash }));
|
|
1549
|
+
const receipt = await receipts.get(txHash);
|
|
1550
|
+
const evidence = inspectFundingReceipt(receipt, {
|
|
1551
|
+
agentId: "zyfai",
|
|
1552
|
+
walletAddress: recipient,
|
|
1553
|
+
chainId,
|
|
1554
|
+
token: asset.symbol,
|
|
1555
|
+
agentWallet: smartWallet,
|
|
1556
|
+
intendedAmount: "MAX",
|
|
1557
|
+
txHash,
|
|
1558
|
+
transfer: "unknown",
|
|
1559
|
+
registration: "not-applicable",
|
|
1560
|
+
delivery: "unknown"
|
|
1561
|
+
}, asset.address, entry.action === "Withdraw" ? "withdraw" : "deposit");
|
|
1562
|
+
if (evidence.transfer === "confirmed" && evidence.confirmedAmount) {
|
|
1563
|
+
Object.assign(tx, {
|
|
1564
|
+
amount: (0, import_viem3.formatUnits)(BigInt(evidence.confirmedAmount), asset.decimals),
|
|
1565
|
+
amountRaw: evidence.confirmedAmount,
|
|
1566
|
+
blockNumber: evidence.blockNumber,
|
|
1567
|
+
logIndexes: evidence.logIndexes,
|
|
1568
|
+
transferLogs: evidence.transferLogs
|
|
1569
|
+
});
|
|
1570
|
+
if (this.fundingHistoryCache.size >= 256) this.fundingHistoryCache.delete(this.fundingHistoryCache.keys().next().value);
|
|
1571
|
+
this.fundingHistoryCache.set(cacheKey, { ...tx });
|
|
1413
1572
|
}
|
|
1414
1573
|
} catch {
|
|
1415
1574
|
}
|
|
@@ -1498,7 +1657,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1498
1657
|
* Wraps `sdk.connectAccount` with a one-shot retry on auth errors. If the
|
|
1499
1658
|
* cached JWT is rejected by the backend (revoked, signing-key rotated, etc.)
|
|
1500
1659
|
* we drop the cache and try again — the second attempt has no cache entry,
|
|
1501
|
-
* so it falls through to a real SIWE prompt. Zyfai
|
|
1660
|
+
* so it falls through to a real SIWE prompt. Zyfai labels every HTTP 401 with
|
|
1502
1661
|
* an `"Unauthorized: Invalid API key"` error so we can't distinguish revoked
|
|
1503
1662
|
* JWT from a misconfigured API key; we retry once either way, and if the
|
|
1504
1663
|
* second attempt still fails the original error propagates.
|
|
@@ -1531,6 +1690,17 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1531
1690
|
await this.connectAuth(state, chainId);
|
|
1532
1691
|
}
|
|
1533
1692
|
}
|
|
1693
|
+
/** A rejected execution session must not be reused by the next foreground attempt. */
|
|
1694
|
+
invalidateRejectedWithdrawalSession(error, state, chainId, authToken) {
|
|
1695
|
+
const message = error instanceof Error ? error.message : "";
|
|
1696
|
+
if (!/(?:^|: )Unauthorized: Invalid API key$/.test(message)) return;
|
|
1697
|
+
const internals = this.sdk;
|
|
1698
|
+
if (typeof authToken !== "string" || internals.httpClient.authToken !== authToken || this.connectedAddress?.toLowerCase() !== state.walletAddress.toLowerCase() || this.connectedChainId !== chainId) return;
|
|
1699
|
+
clearSession(state.walletAddress, chainId);
|
|
1700
|
+
internals.httpClient.clearAuthToken();
|
|
1701
|
+
internals.authenticatedUserId = null;
|
|
1702
|
+
this.connectedChainId = null;
|
|
1703
|
+
}
|
|
1534
1704
|
/**
|
|
1535
1705
|
* Sync newly-available protocols onto an existing user's profile at wallet
|
|
1536
1706
|
* connection. Zyfai's own protocol sync (`updateUserProtocols`) runs only when
|
|
@@ -2076,7 +2246,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2076
2246
|
await this.ensureSessionKey(ownerAddress, chainId, redeployed.address);
|
|
2077
2247
|
return redeployed.address;
|
|
2078
2248
|
}
|
|
2079
|
-
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
2249
|
+
async deposit(state, chainId, amount, asset, depositCallback, onProgress) {
|
|
2080
2250
|
try {
|
|
2081
2251
|
const validChainId = isValidChainId(chainId);
|
|
2082
2252
|
await this.ensureConnected(state, validChainId);
|
|
@@ -2085,17 +2255,48 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2085
2255
|
this.getAddress(),
|
|
2086
2256
|
validChainId
|
|
2087
2257
|
);
|
|
2258
|
+
notifyFunding(onProgress, {
|
|
2259
|
+
agentId: this.id,
|
|
2260
|
+
chainId,
|
|
2261
|
+
token: asset,
|
|
2262
|
+
walletAddress: state.walletAddress,
|
|
2263
|
+
agentWallet: smartWallet,
|
|
2264
|
+
intendedAmount: amount,
|
|
2265
|
+
transfer: "pending",
|
|
2266
|
+
registration: "pending",
|
|
2267
|
+
delivery: "not-applicable"
|
|
2268
|
+
});
|
|
2088
2269
|
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
2089
|
-
|
|
2270
|
+
let evidence2 = {
|
|
2271
|
+
agentId: this.id,
|
|
2272
|
+
chainId,
|
|
2273
|
+
token: asset,
|
|
2274
|
+
walletAddress: state.walletAddress,
|
|
2275
|
+
agentWallet: smartWallet,
|
|
2276
|
+
intendedAmount: amount,
|
|
2277
|
+
txHash,
|
|
2278
|
+
transfer: "pending",
|
|
2279
|
+
registration: "pending",
|
|
2280
|
+
delivery: "not-applicable"
|
|
2281
|
+
};
|
|
2282
|
+
notifyFunding(onProgress, evidence2);
|
|
2090
2283
|
try {
|
|
2284
|
+
const receipt = await this.getPublicClient(validChainId).getTransactionReceipt({ hash: txHash });
|
|
2285
|
+
const token = SupportedAssets.find((token2) => token2.chainId === chainId && token2.symbol === asset);
|
|
2286
|
+
evidence2 = inspectFundingReceipt(receipt, evidence2, token.address, "deposit");
|
|
2287
|
+
} catch {
|
|
2288
|
+
evidence2 = { ...evidence2, transfer: "unknown" };
|
|
2289
|
+
}
|
|
2290
|
+
notifyFunding(onProgress, evidence2);
|
|
2291
|
+
try {
|
|
2292
|
+
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
2091
2293
|
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
logError
|
|
2096
|
-
);
|
|
2294
|
+
evidence2 = { ...evidence2, registration: "confirmed" };
|
|
2295
|
+
} catch {
|
|
2296
|
+
evidence2 = { ...evidence2, registration: "unknown" };
|
|
2097
2297
|
}
|
|
2098
|
-
|
|
2298
|
+
notifyFunding(onProgress, evidence2);
|
|
2299
|
+
return { txHash, smartWallet, amount, evidence: evidence2 };
|
|
2099
2300
|
}
|
|
2100
2301
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
2101
2302
|
const raw2 = await this.sdk.depositFunds(
|
|
@@ -2105,22 +2306,88 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2105
2306
|
asset,
|
|
2106
2307
|
"aggressive"
|
|
2107
2308
|
);
|
|
2108
|
-
|
|
2309
|
+
let evidence = {
|
|
2310
|
+
agentId: this.id,
|
|
2311
|
+
chainId,
|
|
2312
|
+
token: asset,
|
|
2313
|
+
walletAddress: state.walletAddress,
|
|
2314
|
+
agentWallet: raw2.smartWallet,
|
|
2315
|
+
intendedAmount: amount,
|
|
2316
|
+
txHash: raw2.txHash,
|
|
2317
|
+
transfer: "unknown",
|
|
2318
|
+
registration: "unknown",
|
|
2319
|
+
delivery: "not-applicable"
|
|
2320
|
+
};
|
|
2321
|
+
notifyFunding(onProgress, evidence);
|
|
2322
|
+
try {
|
|
2323
|
+
const receipt = await this.getPublicClient(validChainId).getTransactionReceipt({ hash: raw2.txHash });
|
|
2324
|
+
const token = SupportedAssets.find((value) => value.chainId === chainId && value.symbol === asset);
|
|
2325
|
+
evidence = inspectFundingReceipt(receipt, evidence, token.address, "deposit");
|
|
2326
|
+
} catch {
|
|
2327
|
+
}
|
|
2328
|
+
notifyFunding(onProgress, evidence);
|
|
2329
|
+
return { ...mapDeposit(raw2), evidence };
|
|
2109
2330
|
} catch (error) {
|
|
2110
2331
|
throw error;
|
|
2111
2332
|
}
|
|
2112
2333
|
}
|
|
2113
2334
|
// --- IAgent: Fund operations ---
|
|
2114
|
-
async withdraw(state, chainId, token, amount) {
|
|
2335
|
+
async withdraw(state, chainId, token, amount, onProgress) {
|
|
2115
2336
|
const validChainId = isValidChainId(chainId);
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2337
|
+
try {
|
|
2338
|
+
await this.ensureConnected(state, validChainId);
|
|
2339
|
+
} catch (error) {
|
|
2340
|
+
notifyFunding(onProgress, {
|
|
2341
|
+
agentId: this.id,
|
|
2342
|
+
chainId,
|
|
2343
|
+
token,
|
|
2344
|
+
walletAddress: state.walletAddress,
|
|
2345
|
+
intendedAmount: amount ?? "MAX",
|
|
2346
|
+
transfer: "failed",
|
|
2347
|
+
registration: "not-applicable",
|
|
2348
|
+
delivery: "failed"
|
|
2349
|
+
});
|
|
2350
|
+
throw error;
|
|
2351
|
+
}
|
|
2352
|
+
const observation = observeWithdrawalSubmission(this.sdk, validChainId, token);
|
|
2353
|
+
const authToken = this.sdk.httpClient?.authToken;
|
|
2354
|
+
let raw2;
|
|
2355
|
+
try {
|
|
2356
|
+
raw2 = await this.sdk.withdrawFunds(this.getAddress(), validChainId, amount, token);
|
|
2357
|
+
} catch (error) {
|
|
2358
|
+
this.invalidateRejectedWithdrawalSession(error, state, validChainId, authToken);
|
|
2359
|
+
if (observation.attempted() !== void 0) {
|
|
2360
|
+
const failed = observation.attempted() === false || observation.rejected();
|
|
2361
|
+
notifyFunding(onProgress, {
|
|
2362
|
+
agentId: this.id,
|
|
2363
|
+
chainId,
|
|
2364
|
+
token,
|
|
2365
|
+
walletAddress: state.walletAddress,
|
|
2366
|
+
intendedAmount: amount ?? "MAX",
|
|
2367
|
+
transfer: failed ? "failed" : "unknown",
|
|
2368
|
+
registration: "not-applicable",
|
|
2369
|
+
delivery: failed ? "failed" : "unknown",
|
|
2370
|
+
withdrawalRequest: observation.request()
|
|
2371
|
+
});
|
|
2372
|
+
}
|
|
2373
|
+
throw error;
|
|
2374
|
+
} finally {
|
|
2375
|
+
observation.stop();
|
|
2376
|
+
}
|
|
2123
2377
|
if (!raw2.success) {
|
|
2378
|
+
const unresolved = !!raw2.txHash || /already|pending|queued|in.progress/i.test(raw2.message ?? "");
|
|
2379
|
+
notifyFunding(onProgress, {
|
|
2380
|
+
agentId: this.id,
|
|
2381
|
+
chainId,
|
|
2382
|
+
token,
|
|
2383
|
+
walletAddress: state.walletAddress,
|
|
2384
|
+
intendedAmount: amount ?? "MAX",
|
|
2385
|
+
txHash: raw2.txHash,
|
|
2386
|
+
transfer: unresolved ? "unknown" : "failed",
|
|
2387
|
+
registration: "not-applicable",
|
|
2388
|
+
delivery: unresolved ? "unknown" : "failed",
|
|
2389
|
+
withdrawalRequest: observation.request()
|
|
2390
|
+
});
|
|
2124
2391
|
throw new OwneyError(
|
|
2125
2392
|
"WITHDRAW_FAILED",
|
|
2126
2393
|
raw2.message || "Zyfai withdraw failed.",
|
|
@@ -2128,13 +2395,45 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2128
2395
|
this.id
|
|
2129
2396
|
);
|
|
2130
2397
|
}
|
|
2131
|
-
|
|
2398
|
+
const evidence = {
|
|
2399
|
+
agentId: this.id,
|
|
2400
|
+
chainId,
|
|
2401
|
+
token,
|
|
2402
|
+
walletAddress: state.walletAddress,
|
|
2403
|
+
intendedAmount: amount ?? "MAX",
|
|
2404
|
+
txHash: raw2.txHash,
|
|
2405
|
+
transfer: "pending",
|
|
2406
|
+
registration: "not-applicable",
|
|
2407
|
+
delivery: "pending",
|
|
2408
|
+
withdrawalRequest: observation.request()
|
|
2409
|
+
};
|
|
2410
|
+
notifyFunding(onProgress, evidence);
|
|
2411
|
+
return { ...mapWithdraw(raw2), evidence };
|
|
2412
|
+
}
|
|
2413
|
+
/** Registration recovery never signs, transfers, activates, or refreshes authentication. */
|
|
2414
|
+
async retryDepositRegistration(state, evidence) {
|
|
2415
|
+
const internals = this.sdk;
|
|
2416
|
+
if (!internals.httpClient.authToken || internals.authenticatedUserId === null || this.connectedAddress?.toLowerCase() !== state.walletAddress.toLowerCase() || this.connectedChainId !== evidence.chainId) {
|
|
2417
|
+
throw new OwneyError("NOT_CONNECTED", "Reconnect the wallet before recovering deposit registration.");
|
|
2418
|
+
}
|
|
2419
|
+
if (evidence.transfer !== "confirmed" || !evidence.txHash) {
|
|
2420
|
+
throw new OwneyError("AGENT_API_ERROR", "Deposit transfer must be verified before registration recovery.");
|
|
2421
|
+
}
|
|
2422
|
+
const cid = isValidChainId(evidence.chainId);
|
|
2423
|
+
const tokenAddress = evidence.token === "WETH" ? WETH_ADDRESS_BY_CHAIN[cid] : void 0;
|
|
2424
|
+
await this.sdk.logDeposit(cid, evidence.txHash, evidence.intendedAmount, tokenAddress);
|
|
2425
|
+
return { ...evidence, registration: "confirmed" };
|
|
2132
2426
|
}
|
|
2133
2427
|
// --- IAgent: Portfolio reads ---
|
|
2428
|
+
async getFundingWallet(state, chainId) {
|
|
2429
|
+
return (await this.sdk.getSmartWalletAddress(state.walletAddress, isValidChainId(chainId))).address;
|
|
2430
|
+
}
|
|
2134
2431
|
async getBalances(state, chainId) {
|
|
2432
|
+
const requestedAt = Date.now();
|
|
2135
2433
|
const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
|
|
2136
2434
|
const raw2 = await this.sdk.getPortfolio(this.getAddress());
|
|
2137
|
-
|
|
2435
|
+
const balance = mapBalances(raw2, validChainId, smartWallet);
|
|
2436
|
+
return { ...balance, readMetadata: balance.readMetadata?.map((read2) => ({ ...read2, requestedAt })) };
|
|
2138
2437
|
}
|
|
2139
2438
|
earningsKey(state, chainId, smartWallet) {
|
|
2140
2439
|
return JSON.stringify([
|
|
@@ -2207,7 +2506,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2207
2506
|
/**
|
|
2208
2507
|
* Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
|
|
2209
2508
|
* takes lowercase `assetType` and denominates WETH as "eth" (the same
|
|
2210
|
-
* spelling `
|
|
2509
|
+
* spelling `resolveFundingTransfers` normalizes on the way in). Anything
|
|
2211
2510
|
* unrecognised returns undefined so the request stays unfiltered rather
|
|
2212
2511
|
* than silently narrowing to nothing.
|
|
2213
2512
|
*/
|
|
@@ -2226,6 +2525,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2226
2525
|
}
|
|
2227
2526
|
async getHistory(state, chainId, options) {
|
|
2228
2527
|
const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
|
|
2528
|
+
return this.readHistory(state, smartWallet, validChainId, options);
|
|
2529
|
+
}
|
|
2530
|
+
/** Recovery reads never enter connectAuth or wallet activation. */
|
|
2531
|
+
async getFundingHistory(state, chainId, options) {
|
|
2532
|
+
const smartWallet = await this.getFundingWallet(state, chainId);
|
|
2533
|
+
return this.readHistory(state, smartWallet, isValidChainId(chainId), options);
|
|
2534
|
+
}
|
|
2535
|
+
async readHistory(state, smartWallet, validChainId, options) {
|
|
2229
2536
|
const limit = options?.limit ?? 10;
|
|
2230
2537
|
const assetType = _ZyfaiAgent.toZyfaiAssetType(options?.tokenSymbol);
|
|
2231
2538
|
const cursor = options?.cursor ? decodeHistoryCursor(options.cursor) : null;
|
|
@@ -2267,9 +2574,16 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2267
2574
|
rawOffset: firstOvershoot ? firstOvershoot.rawIdx : offset
|
|
2268
2575
|
}) : void 0;
|
|
2269
2576
|
const data = mapEntries(pageData, validChainId);
|
|
2270
|
-
await this.
|
|
2577
|
+
await this.resolveFundingTransfers(data, validChainId, state.walletAddress, smartWallet, options?.tokenSymbol);
|
|
2578
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2579
|
+
const unique = data.filter((entry) => {
|
|
2580
|
+
if (!entry.id || !entry.transactions[0]?.transferLogs?.length) return true;
|
|
2581
|
+
if (seen.has(entry.id)) return false;
|
|
2582
|
+
seen.add(entry.id);
|
|
2583
|
+
return true;
|
|
2584
|
+
});
|
|
2271
2585
|
return {
|
|
2272
|
-
data,
|
|
2586
|
+
data: unique,
|
|
2273
2587
|
hasMore,
|
|
2274
2588
|
nextCursor
|
|
2275
2589
|
};
|
|
@@ -2318,7 +2632,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2318
2632
|
};
|
|
2319
2633
|
|
|
2320
2634
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
2321
|
-
var
|
|
2635
|
+
var import_viem8 = require("viem");
|
|
2322
2636
|
var import_chains3 = require("viem/chains");
|
|
2323
2637
|
|
|
2324
2638
|
// src/lib/chain-guard.ts
|
|
@@ -2357,7 +2671,7 @@ async function ensureWalletOnChain(pub, wallet, expected) {
|
|
|
2357
2671
|
}
|
|
2358
2672
|
|
|
2359
2673
|
// src/lib/transfer-auth.ts
|
|
2360
|
-
var
|
|
2674
|
+
var import_viem4 = require("viem");
|
|
2361
2675
|
|
|
2362
2676
|
// src/lib/sponsor-client.ts
|
|
2363
2677
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
@@ -2473,7 +2787,7 @@ async function postSponsorBatchTransfer(input) {
|
|
|
2473
2787
|
}
|
|
2474
2788
|
|
|
2475
2789
|
// src/lib/permit2.ts
|
|
2476
|
-
var
|
|
2790
|
+
var import_viem5 = require("viem");
|
|
2477
2791
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2478
2792
|
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
2479
2793
|
function permit2ApprovalAmount(requiredAmount) {
|
|
@@ -2514,7 +2828,7 @@ var ERC20_ALLOWANCE_ABI = [
|
|
|
2514
2828
|
function randomPermit2Nonce() {
|
|
2515
2829
|
const bytes = new Uint8Array(32);
|
|
2516
2830
|
globalThis.crypto.getRandomValues(bytes);
|
|
2517
|
-
return BigInt((0,
|
|
2831
|
+
return BigInt((0, import_viem5.bytesToHex)(bytes));
|
|
2518
2832
|
}
|
|
2519
2833
|
async function readPermit2Allowance(publicClient, token, owner, blockNumber) {
|
|
2520
2834
|
return publicClient.readContract({
|
|
@@ -2557,7 +2871,7 @@ function makeVerificationAwareDepositCallback(implementation) {
|
|
|
2557
2871
|
|
|
2558
2872
|
// src/agents/yieldseeker/yieldseeker.auth.ts
|
|
2559
2873
|
var import_siwe = require("siwe");
|
|
2560
|
-
var
|
|
2874
|
+
var import_viem6 = require("viem");
|
|
2561
2875
|
var import_chains2 = require("viem/chains");
|
|
2562
2876
|
|
|
2563
2877
|
// src/agents/yieldseeker/yieldseeker.auth-cache.ts
|
|
@@ -2670,7 +2984,7 @@ function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
|
|
|
2670
2984
|
return new import_siwe.SiweMessage({
|
|
2671
2985
|
scheme: url.protocol.slice(0, -1),
|
|
2672
2986
|
domain: url.host,
|
|
2673
|
-
address: (0,
|
|
2987
|
+
address: (0, import_viem6.getAddress)(address),
|
|
2674
2988
|
uri: url.origin,
|
|
2675
2989
|
version: "1",
|
|
2676
2990
|
chainId,
|
|
@@ -2756,15 +3070,15 @@ var YieldseekerAuth = class {
|
|
|
2756
3070
|
clearYieldseekerSession(state.walletAddress, chainId);
|
|
2757
3071
|
}
|
|
2758
3072
|
async sign(state, chainId) {
|
|
2759
|
-
const account = (0,
|
|
2760
|
-
const publicClient = (0,
|
|
3073
|
+
const account = (0, import_viem6.getAddress)(state.walletAddress);
|
|
3074
|
+
const publicClient = (0, import_viem6.createPublicClient)({
|
|
2761
3075
|
chain: import_chains2.base,
|
|
2762
|
-
transport: (0,
|
|
3076
|
+
transport: (0, import_viem6.custom)(state.provider)
|
|
2763
3077
|
});
|
|
2764
|
-
const walletClient = (0,
|
|
3078
|
+
const walletClient = (0, import_viem6.createWalletClient)({
|
|
2765
3079
|
account,
|
|
2766
3080
|
chain: import_chains2.base,
|
|
2767
|
-
transport: (0,
|
|
3081
|
+
transport: (0, import_viem6.custom)(state.provider)
|
|
2768
3082
|
});
|
|
2769
3083
|
await ensureWalletOnChain(
|
|
2770
3084
|
publicClient,
|
|
@@ -2931,7 +3245,7 @@ var YieldseekerApiClient = class {
|
|
|
2931
3245
|
};
|
|
2932
3246
|
|
|
2933
3247
|
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
2934
|
-
var
|
|
3248
|
+
var import_viem7 = require("viem");
|
|
2935
3249
|
|
|
2936
3250
|
// src/lib/helpers/snapshot-apy.ts
|
|
2937
3251
|
var DAY_MS = 864e5;
|
|
@@ -2998,10 +3312,10 @@ function raw(value, endpoint) {
|
|
|
2998
3312
|
return BigInt(value);
|
|
2999
3313
|
}
|
|
3000
3314
|
function decimal(value, decimals, endpoint) {
|
|
3001
|
-
return (0,
|
|
3315
|
+
return (0, import_viem7.formatUnits)(raw(value, endpoint), decimals);
|
|
3002
3316
|
}
|
|
3003
3317
|
function usd(rawAmount, decimals, price) {
|
|
3004
|
-
return Number((0,
|
|
3318
|
+
return Number((0, import_viem7.formatUnits)(rawAmount, decimals)) * price;
|
|
3005
3319
|
}
|
|
3006
3320
|
function percent(value) {
|
|
3007
3321
|
const result = Number(value);
|
|
@@ -3027,7 +3341,7 @@ function assetAddressValue(record, address) {
|
|
|
3027
3341
|
}
|
|
3028
3342
|
function position(value, asset, baseAssetDecimals) {
|
|
3029
3343
|
const option = value?.yieldOption;
|
|
3030
|
-
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0,
|
|
3344
|
+
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem7.isAddress)(option.address)) {
|
|
3031
3345
|
return invalid("yield positions", "missing vault metadata");
|
|
3032
3346
|
}
|
|
3033
3347
|
return {
|
|
@@ -3097,7 +3411,17 @@ function mapYieldseekerBalances(contexts) {
|
|
|
3097
3411
|
totalBalanceAsset: "usdc",
|
|
3098
3412
|
assetBalances,
|
|
3099
3413
|
tokens,
|
|
3100
|
-
positions
|
|
3414
|
+
positions,
|
|
3415
|
+
readMetadata: contexts.map((context) => ({
|
|
3416
|
+
chainId: context.agent.chainId,
|
|
3417
|
+
asset: context.asset,
|
|
3418
|
+
fetchedAt: context.fetchedAt,
|
|
3419
|
+
readVersion: context.readVersion,
|
|
3420
|
+
providerUpdatedAt: context.snapshot.updatedDate,
|
|
3421
|
+
snapshotId: String(context.snapshot.agentWalletSnapshotId),
|
|
3422
|
+
netDepositsRaw: context.snapshot.netDepositsBase,
|
|
3423
|
+
positionsStatus: context.positionsUnavailable ? "unavailable" : "available"
|
|
3424
|
+
}))
|
|
3101
3425
|
};
|
|
3102
3426
|
}
|
|
3103
3427
|
function mapYieldseekerEarnings(contexts) {
|
|
@@ -3109,7 +3433,7 @@ function mapYieldseekerEarnings(contexts) {
|
|
|
3109
3433
|
chain: "BASE",
|
|
3110
3434
|
chainId: 8453,
|
|
3111
3435
|
asset: context.asset,
|
|
3112
|
-
amount: (0,
|
|
3436
|
+
amount: (0, import_viem7.formatUnits)(amount, context.snapshot.baseAssetDecimals)
|
|
3113
3437
|
});
|
|
3114
3438
|
lifetimeEarnings += usd(
|
|
3115
3439
|
amount,
|
|
@@ -3211,6 +3535,7 @@ function transactionHashes(details) {
|
|
|
3211
3535
|
function actionEntry(action) {
|
|
3212
3536
|
if (action.actionType.toLowerCase().includes("withdraw")) return void 0;
|
|
3213
3537
|
return {
|
|
3538
|
+
id: `yieldseeker:action:${action.agentActionId}`,
|
|
3214
3539
|
agent: "yieldseeker",
|
|
3215
3540
|
action: actionType(action.actionType),
|
|
3216
3541
|
date: action.createdDate,
|
|
@@ -3240,7 +3565,7 @@ function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddres
|
|
|
3240
3565
|
const owner = ownerAddress.toLowerCase();
|
|
3241
3566
|
const agentWallet = wallet.walletAddress.toLowerCase();
|
|
3242
3567
|
const baseAsset = agent.assetAddress.toLowerCase();
|
|
3243
|
-
if (movement.chainId !== agent.chainId || movement.assetAddress.toLowerCase() !== baseAsset) {
|
|
3568
|
+
if (movement.chainId !== agent.chainId || movement.assetAddress.toLowerCase() !== baseAsset || raw(movement.assetAmount, "historic position") <= 0n) {
|
|
3244
3569
|
return void 0;
|
|
3245
3570
|
}
|
|
3246
3571
|
let action;
|
|
@@ -3265,6 +3590,12 @@ function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddres
|
|
|
3265
3590
|
transactions: [
|
|
3266
3591
|
{
|
|
3267
3592
|
txHashes: [movement.transactionHash],
|
|
3593
|
+
tokenAddress: movement.assetAddress,
|
|
3594
|
+
agentWallet: wallet.walletAddress,
|
|
3595
|
+
logIndexes: [movement.logIndex],
|
|
3596
|
+
transferLogs: [{ logIndex: movement.logIndex, amountRaw: movement.assetAmount }],
|
|
3597
|
+
amountRaw: movement.assetAmount,
|
|
3598
|
+
blockNumber: String(movement.blockNumber),
|
|
3268
3599
|
chainId: agent.chainId,
|
|
3269
3600
|
tokenSymbol: asset,
|
|
3270
3601
|
amount: decimal(
|
|
@@ -3310,7 +3641,8 @@ function mapYieldseekerHistory(contexts, options) {
|
|
|
3310
3641
|
ungrouped.push(entry);
|
|
3311
3642
|
continue;
|
|
3312
3643
|
}
|
|
3313
|
-
const key2 = `${entry.agent}:${entry.action}:${tx.chainId}:${hash.toLowerCase()}`;
|
|
3644
|
+
const key2 = `${entry.agent}:${entry.action}:${tx.chainId}:${hash.toLowerCase()}:${tx.tokenAddress?.toLowerCase() ?? ""}:${tx.agentWallet?.toLowerCase() ?? ""}`;
|
|
3645
|
+
entry.id = key2;
|
|
3314
3646
|
const previous = grouped.get(key2);
|
|
3315
3647
|
if (!previous) {
|
|
3316
3648
|
grouped.set(key2, entry);
|
|
@@ -3323,14 +3655,52 @@ function mapYieldseekerHistory(contexts, options) {
|
|
|
3323
3655
|
}
|
|
3324
3656
|
previous.positions.push(...entry.positions);
|
|
3325
3657
|
previous.transactions.push(...entry.transactions);
|
|
3658
|
+
} else if ((entry.action === "Top up" || entry.action === "Withdraw") && tx.amountRaw) {
|
|
3659
|
+
const target = previous.transactions[0];
|
|
3660
|
+
const known = new Set(target.logIndexes ?? []);
|
|
3661
|
+
if (tx.logIndexes?.some((index) => !known.has(index))) {
|
|
3662
|
+
target.amountRaw = String(BigInt(target.amountRaw ?? "0") + BigInt(tx.amountRaw));
|
|
3663
|
+
target.amount = (0, import_viem7.formatUnits)(
|
|
3664
|
+
BigInt(target.amountRaw),
|
|
3665
|
+
YIELDSEEKER_ASSET_METADATA[target.tokenSymbol].decimals
|
|
3666
|
+
);
|
|
3667
|
+
target.logIndexes = [...known, ...tx.logIndexes.filter((index) => !known.has(index))];
|
|
3668
|
+
target.transferLogs = [...target.transferLogs ?? [], ...(tx.transferLogs ?? []).filter((log) => !known.has(log.logIndex))];
|
|
3669
|
+
}
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
const values = [...grouped.values(), ...ungrouped].filter((entry) => {
|
|
3673
|
+
const tx = entry.transactions[0];
|
|
3674
|
+
return tx?.amountRaw !== void 0 || ![...grouped.values()].some((other) => other !== entry && other.action === entry.action && other.transactions[0]?.amountRaw !== void 0 && other.transactions[0]?.txHashes[0]?.toLowerCase() === tx?.txHashes[0]?.toLowerCase());
|
|
3675
|
+
});
|
|
3676
|
+
let boundary;
|
|
3677
|
+
const scope = JSON.stringify([
|
|
3678
|
+
options.ownerAddress.toLowerCase(),
|
|
3679
|
+
contexts.map((context) => `${context.agent.chainId}:${context.wallet.walletAddress.toLowerCase()}:${context.asset}`).sort(),
|
|
3680
|
+
options.fromDate ?? null
|
|
3681
|
+
]);
|
|
3682
|
+
if (options.cursor) {
|
|
3683
|
+
try {
|
|
3684
|
+
boundary = JSON.parse(decodeURIComponent(atob(options.cursor)));
|
|
3685
|
+
if (!boundary || boundary.scope !== scope || typeof boundary.id !== "string" || !Number.isFinite(Date.parse(boundary.date)) || !Number.isFinite(Date.parse(boundary.toDate))) throw new Error();
|
|
3686
|
+
} catch {
|
|
3687
|
+
throw new InvalidHistoryCursorError("Invalid Yieldseeker history cursor.");
|
|
3326
3688
|
}
|
|
3327
3689
|
}
|
|
3328
|
-
const
|
|
3690
|
+
const toDate = boundary?.toDate ?? options.toDate ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3691
|
+
const filtered = values.filter((entry) => (!options.fromDate || entry.date >= options.fromDate) && entry.date <= toDate && (!boundary || entry.date < boundary.date || entry.date === boundary.date && (entry.id ?? "") > boundary.id)).sort((left, right) => right.date.localeCompare(left.date) || (left.id ?? "").localeCompare(right.id ?? ""));
|
|
3692
|
+
const data = filtered.slice(0, Math.max(1, options.limit));
|
|
3693
|
+
const hasMore = filtered.length > data.length;
|
|
3694
|
+
const last = data.at(-1);
|
|
3329
3695
|
return {
|
|
3330
|
-
data
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3696
|
+
data,
|
|
3697
|
+
hasMore,
|
|
3698
|
+
...hasMore && last ? { nextCursor: btoa(encodeURIComponent(JSON.stringify({
|
|
3699
|
+
date: last.date,
|
|
3700
|
+
id: last.id ?? "",
|
|
3701
|
+
toDate,
|
|
3702
|
+
scope
|
|
3703
|
+
}))) } : {}
|
|
3334
3704
|
};
|
|
3335
3705
|
}
|
|
3336
3706
|
function mapYieldseekerProfile(address, contexts) {
|
|
@@ -3505,7 +3875,7 @@ var YieldseekerAgent = class {
|
|
|
3505
3875
|
this.assertAsset(targetAsset);
|
|
3506
3876
|
await this.ensureAgent(state, chainId, targetAsset);
|
|
3507
3877
|
}
|
|
3508
|
-
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
3878
|
+
async deposit(state, chainId, amount, asset, depositCallback, onProgress) {
|
|
3509
3879
|
this.assertChain(chainId);
|
|
3510
3880
|
this.assertAsset(asset);
|
|
3511
3881
|
if (BigInt(amount) <= 0n) {
|
|
@@ -3519,7 +3889,20 @@ var YieldseekerAgent = class {
|
|
|
3519
3889
|
const context = await this.ensureAgent(state, chainId, asset);
|
|
3520
3890
|
const generation = this.readGeneration;
|
|
3521
3891
|
const movement = this.snapshotMovement(state, chainId, context, BigInt(amount));
|
|
3892
|
+
notifyFunding(onProgress, {
|
|
3893
|
+
agentId: this.id,
|
|
3894
|
+
chainId,
|
|
3895
|
+
token: asset,
|
|
3896
|
+
walletAddress: state.walletAddress,
|
|
3897
|
+
agentWallet: context.wallet.walletAddress,
|
|
3898
|
+
intendedAmount: amount,
|
|
3899
|
+
transfer: "pending",
|
|
3900
|
+
registration: "not-applicable",
|
|
3901
|
+
delivery: "not-applicable"
|
|
3902
|
+
});
|
|
3522
3903
|
let txHash;
|
|
3904
|
+
let receipt;
|
|
3905
|
+
const submitted = (hash) => notifyFunding(onProgress, { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount, txHash: hash, transfer: "pending", registration: "not-applicable", delivery: "not-applicable" });
|
|
3523
3906
|
if (depositCallback) {
|
|
3524
3907
|
provideDepositVerificationContext(depositCallback, {
|
|
3525
3908
|
agentId: "yieldseeker",
|
|
@@ -3532,30 +3915,57 @@ var YieldseekerAgent = class {
|
|
|
3532
3915
|
chainId,
|
|
3533
3916
|
amount
|
|
3534
3917
|
);
|
|
3535
|
-
|
|
3918
|
+
submitted(txHash);
|
|
3919
|
+
receipt = await this.waitForReceipt(state, chainId, txHash);
|
|
3536
3920
|
} else {
|
|
3537
3921
|
txHash = await this.submitTransaction(state, chainId, {
|
|
3538
|
-
from: (0,
|
|
3922
|
+
from: (0, import_viem8.getAddress)(state.walletAddress),
|
|
3539
3923
|
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
3540
|
-
data: (0,
|
|
3541
|
-
abi:
|
|
3924
|
+
data: (0, import_viem8.encodeFunctionData)({
|
|
3925
|
+
abi: import_viem8.erc20Abi,
|
|
3542
3926
|
functionName: "transfer",
|
|
3543
|
-
args: [(0,
|
|
3927
|
+
args: [(0, import_viem8.getAddress)(context.wallet.walletAddress), BigInt(amount)]
|
|
3544
3928
|
}),
|
|
3545
3929
|
value: "0",
|
|
3546
3930
|
chainId
|
|
3931
|
+
}, submitted, (value) => {
|
|
3932
|
+
receipt = value;
|
|
3547
3933
|
});
|
|
3548
3934
|
}
|
|
3549
3935
|
if (this.readGeneration === generation) {
|
|
3550
3936
|
void this.refreshSnapshotAfterMovement(state, chainId, context, "deposit", movement);
|
|
3551
3937
|
}
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3938
|
+
const base5 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount, confirmedAmount: amount, txHash, transfer: "confirmed", registration: "not-applicable", delivery: "not-applicable" };
|
|
3939
|
+
const evidence = receipt ? inspectFundingReceipt(receipt, base5, YIELDSEEKER_ASSET_METADATA[asset].address, "deposit") : base5;
|
|
3940
|
+
notifyFunding(onProgress, evidence);
|
|
3941
|
+
return { txHash, smartWallet: context.wallet.walletAddress, amount, evidence };
|
|
3942
|
+
}
|
|
3943
|
+
async withdraw(state, chainId, asset, amount, onProgress) {
|
|
3944
|
+
let ownerTransferAttempted = false;
|
|
3945
|
+
let evidence = {
|
|
3946
|
+
agentId: this.id,
|
|
3947
|
+
chainId,
|
|
3948
|
+
token: asset,
|
|
3949
|
+
walletAddress: state.walletAddress,
|
|
3950
|
+
intendedAmount: amount ?? "MAX",
|
|
3951
|
+
transfer: "pending",
|
|
3952
|
+
registration: "not-applicable",
|
|
3953
|
+
delivery: "pending"
|
|
3556
3954
|
};
|
|
3955
|
+
try {
|
|
3956
|
+
return await this.withdrawInternal(state, chainId, asset, amount, (next) => {
|
|
3957
|
+
evidence = { ...evidence, ...next };
|
|
3958
|
+
notifyFunding(onProgress, evidence);
|
|
3959
|
+
}, () => {
|
|
3960
|
+
ownerTransferAttempted = true;
|
|
3961
|
+
});
|
|
3962
|
+
} catch (error) {
|
|
3963
|
+
if (!ownerTransferAttempted || error instanceof OwneyError && error.code === "AGENT_TRANSACTION_REVERTED")
|
|
3964
|
+
notifyFunding(onProgress, { ...evidence, transfer: "failed", delivery: "failed" });
|
|
3965
|
+
throw error;
|
|
3966
|
+
}
|
|
3557
3967
|
}
|
|
3558
|
-
async
|
|
3968
|
+
async withdrawInternal(state, chainId, asset, amount, onProgress, onOwnerTransferAttempted) {
|
|
3559
3969
|
this.assertChain(chainId);
|
|
3560
3970
|
this.assertAsset(asset);
|
|
3561
3971
|
if (amount !== void 0 && BigInt(amount) <= 0n) {
|
|
@@ -3585,17 +3995,32 @@ var YieldseekerAgent = class {
|
|
|
3585
3995
|
context
|
|
3586
3996
|
);
|
|
3587
3997
|
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3588
|
-
const
|
|
3589
|
-
(
|
|
3590
|
-
|
|
3591
|
-
|
|
3998
|
+
const readIdle = async () => {
|
|
3999
|
+
const balance = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
4000
|
+
address: metadata.address,
|
|
4001
|
+
abi: import_viem8.erc20Abi,
|
|
4002
|
+
functionName: "balanceOf",
|
|
4003
|
+
args: [(0, import_viem8.getAddress)(context.wallet.walletAddress)]
|
|
4004
|
+
}), chainId, "eth_call", this.id);
|
|
4005
|
+
this.assertSession(generation, chainId, asset);
|
|
4006
|
+
return balance;
|
|
4007
|
+
};
|
|
4008
|
+
const idle = await readIdle();
|
|
3592
4009
|
const deployed = portfolio.positions.reduce(
|
|
3593
4010
|
(total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
|
|
3594
4011
|
0n
|
|
3595
4012
|
);
|
|
3596
4013
|
const totalAvailable = idle + deployed;
|
|
3597
4014
|
const requested = amount === void 0 ? totalAvailable : BigInt(amount);
|
|
3598
|
-
|
|
4015
|
+
if (requested === 0n) {
|
|
4016
|
+
this.invalidateFundingRead(state, chainId, asset);
|
|
4017
|
+
throw new OwneyError(
|
|
4018
|
+
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
4019
|
+
"No Yieldseeker funds are available to withdraw.",
|
|
4020
|
+
{ asset, available: "0" },
|
|
4021
|
+
this.id
|
|
4022
|
+
);
|
|
4023
|
+
}
|
|
3599
4024
|
if (requested > totalAvailable) {
|
|
3600
4025
|
throw new OwneyError(
|
|
3601
4026
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
@@ -3640,29 +4065,51 @@ var YieldseekerAgent = class {
|
|
|
3640
4065
|
remaining: remaining.toString()
|
|
3641
4066
|
});
|
|
3642
4067
|
}
|
|
3643
|
-
const
|
|
4068
|
+
const availableForOwner = confirmedMovement ? await readIdle() : idle;
|
|
4069
|
+
if (availableForOwner === 0n || amount !== void 0 && availableForOwner < requested) {
|
|
4070
|
+
this.invalidateFundingRead(state, chainId, asset);
|
|
4071
|
+
throw new OwneyError(
|
|
4072
|
+
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
4073
|
+
"Yieldseeker funds are not available for the owner transfer.",
|
|
4074
|
+
{ asset, requested: amount ?? "MAX", available: availableForOwner.toString() },
|
|
4075
|
+
this.id
|
|
4076
|
+
);
|
|
4077
|
+
}
|
|
4078
|
+
const payout = amount === void 0 ? availableForOwner : requested;
|
|
4079
|
+
const plannedMovement = this.snapshotMovement(state, chainId, context, -payout);
|
|
4080
|
+
const account = (0, import_viem8.getAddress)(state.walletAddress);
|
|
4081
|
+
let receipt;
|
|
4082
|
+
const base5 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount === void 0 ? "MAX" : requested.toString(), transfer: "pending", registration: "not-applicable", delivery: "pending" };
|
|
4083
|
+
onOwnerTransferAttempted?.();
|
|
3644
4084
|
const txHash = await this.submitTransaction(state, chainId, {
|
|
3645
4085
|
from: account,
|
|
3646
|
-
to: (0,
|
|
3647
|
-
data: amount === void 0 ? (0,
|
|
4086
|
+
to: (0, import_viem8.getAddress)(context.wallet.walletAddress),
|
|
4087
|
+
data: amount === void 0 ? (0, import_viem8.encodeFunctionData)({
|
|
3648
4088
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3649
4089
|
functionName: "withdrawAllAssetToUser",
|
|
3650
4090
|
args: [account, metadata.address]
|
|
3651
|
-
}) : (0,
|
|
4091
|
+
}) : (0, import_viem8.encodeFunctionData)({
|
|
3652
4092
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3653
4093
|
functionName: "withdrawAssetToUser",
|
|
3654
4094
|
args: [account, metadata.address, requested]
|
|
3655
4095
|
}),
|
|
3656
4096
|
value: "0",
|
|
3657
4097
|
chainId
|
|
4098
|
+
}, (hash) => notifyFunding(onProgress, { ...base5, txHash: hash }), (value) => {
|
|
4099
|
+
receipt = value;
|
|
3658
4100
|
});
|
|
3659
4101
|
confirmedMovement = true;
|
|
3660
4102
|
settlement = plannedMovement;
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
4103
|
+
const evidence = receipt ? inspectFundingReceipt(receipt, { ...base5, txHash }, metadata.address, "withdraw") : { ...base5, txHash, confirmedAmount: payout.toString(), transfer: "confirmed", delivery: "confirmed" };
|
|
4104
|
+
notifyFunding(onProgress, evidence);
|
|
4105
|
+
if (evidence.transfer === "failed" && evidence.confirmedAmount === "0")
|
|
4106
|
+
throw new OwneyError(
|
|
4107
|
+
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
4108
|
+
"The Yieldseeker withdrawal completed without transferring funds.",
|
|
4109
|
+
{ asset, available: "0", txHash },
|
|
4110
|
+
this.id
|
|
4111
|
+
);
|
|
4112
|
+
return { txHash, type: amount === void 0 ? "full" : "partial", amount: evidence.confirmedAmount ?? payout.toString(), evidence };
|
|
3666
4113
|
} finally {
|
|
3667
4114
|
if (confirmedMovement && this.readGeneration === generation) {
|
|
3668
4115
|
void this.refreshSnapshotAfterMovement(
|
|
@@ -3675,9 +4122,39 @@ var YieldseekerAgent = class {
|
|
|
3675
4122
|
}
|
|
3676
4123
|
}
|
|
3677
4124
|
}
|
|
3678
|
-
async getBalances(state, chainId) {
|
|
4125
|
+
async getBalances(state, chainId, asset) {
|
|
3679
4126
|
this.assertChain(chainId);
|
|
3680
|
-
|
|
4127
|
+
if (asset !== void 0) this.assertAsset(asset);
|
|
4128
|
+
return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, { asset, allowMissingPositions: true }));
|
|
4129
|
+
}
|
|
4130
|
+
invalidateFundingRead(state, chainId, asset, refreshUntil = Date.now() + YIELDSEEKER_SETTLEMENT_WINDOW_MS) {
|
|
4131
|
+
this.assertAsset(asset);
|
|
4132
|
+
const key2 = this.contextKey(state, chainId, asset);
|
|
4133
|
+
const failure = this.snapshotFailures.get(key2);
|
|
4134
|
+
this.advancePortfolioVersion(key2);
|
|
4135
|
+
if (failure && failure.retryAt > Date.now()) this.snapshotFailures.set(key2, failure);
|
|
4136
|
+
if (!this.snapshotMovements.has(key2)) this.snapshotMovements.set(key2, null);
|
|
4137
|
+
const until = Math.min(refreshUntil, Date.now() + YIELDSEEKER_SETTLEMENT_WINDOW_MS);
|
|
4138
|
+
this.reconcileUntil.set(key2, Math.max(this.reconcileUntil.get(key2) ?? 0, until));
|
|
4139
|
+
this.activityRefreshUntil.set(key2, Math.max(this.activityRefreshUntil.get(key2) ?? 0, until));
|
|
4140
|
+
}
|
|
4141
|
+
endFundingBalanceRefresh(state, chainId, asset, read2) {
|
|
4142
|
+
this.assertChain(chainId);
|
|
4143
|
+
this.assertAsset(asset);
|
|
4144
|
+
const key2 = this.contextKey(state, chainId, asset);
|
|
4145
|
+
const cached = this.readCache.get(`snapshot:${key2}`);
|
|
4146
|
+
const snapshot = cached?.value?.agentSnapshot;
|
|
4147
|
+
if (!cached || !snapshot || read2.chainId !== chainId || read2.asset.toUpperCase() !== asset || read2.readVersion !== this.portfolioVersion(key2) || read2.fetchedAt !== cached.fetchedAt || read2.snapshotId !== String(snapshot.agentWalletSnapshotId) || read2.providerUpdatedAt !== snapshot.updatedDate || read2.netDepositsRaw !== snapshot.netDepositsBase) return false;
|
|
4148
|
+
this.snapshotMovements.delete(key2);
|
|
4149
|
+
this.reconcileUntil.delete(key2);
|
|
4150
|
+
cached.expiresAt = cached.fetchedAt + YIELDSEEKER_PORTFOLIO_CACHE_MS;
|
|
4151
|
+
return true;
|
|
4152
|
+
}
|
|
4153
|
+
async getFundingWallet(state, chainId, asset) {
|
|
4154
|
+
this.assertAsset(asset);
|
|
4155
|
+
const context = this.agentContexts.get(this.contextKey(state, chainId, asset));
|
|
4156
|
+
if (!context) throw new OwneyError("NOT_CONNECTED", "Reconnect the agent before recovering funding.");
|
|
4157
|
+
return context.wallet.walletAddress;
|
|
3681
4158
|
}
|
|
3682
4159
|
async getEarnings(state, chainId) {
|
|
3683
4160
|
this.assertChain(chainId);
|
|
@@ -3709,11 +4186,12 @@ var YieldseekerAgent = class {
|
|
|
3709
4186
|
);
|
|
3710
4187
|
const vaultAddresses = new Set(
|
|
3711
4188
|
catalog.flat().filter(
|
|
3712
|
-
(yieldOption) => yieldOption.chainId === chainId && (0,
|
|
4189
|
+
(yieldOption) => yieldOption.chainId === chainId && (0, import_viem8.isAddress)(yieldOption.address)
|
|
3713
4190
|
).map((yieldOption) => yieldOption.address.toLowerCase())
|
|
3714
4191
|
);
|
|
3715
4192
|
return mapYieldseekerHistory(contexts, {
|
|
3716
4193
|
limit: options?.limit ?? 10,
|
|
4194
|
+
cursor: options?.cursor,
|
|
3717
4195
|
ownerAddress: state.walletAddress,
|
|
3718
4196
|
vaultAddresses,
|
|
3719
4197
|
...options?.fromDate ? { fromDate: options.fromDate } : {},
|
|
@@ -3788,6 +4266,7 @@ var YieldseekerAgent = class {
|
|
|
3788
4266
|
if (this.readGeneration === generation && this.pendingReads.get(key2) === request) {
|
|
3789
4267
|
this.readCache.set(key2, {
|
|
3790
4268
|
expiresAt: Date.now() + ttlMs,
|
|
4269
|
+
fetchedAt: Date.now(),
|
|
3791
4270
|
value
|
|
3792
4271
|
});
|
|
3793
4272
|
}
|
|
@@ -3834,7 +4313,7 @@ var YieldseekerAgent = class {
|
|
|
3834
4313
|
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
3835
4314
|
).then((walletResponse) => {
|
|
3836
4315
|
this.assertSession(generation, chainId, asset);
|
|
3837
|
-
if (!walletResponse?.agentWallet || !(0,
|
|
4316
|
+
if (!walletResponse?.agentWallet || !(0, import_viem8.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
3838
4317
|
throw this.invalidResponse("agent wallet");
|
|
3839
4318
|
}
|
|
3840
4319
|
const context = {
|
|
@@ -3864,7 +4343,7 @@ var YieldseekerAgent = class {
|
|
|
3864
4343
|
this.users.set(key2, persisted);
|
|
3865
4344
|
return persisted;
|
|
3866
4345
|
}
|
|
3867
|
-
const walletAddress = (0,
|
|
4346
|
+
const walletAddress = (0, import_viem8.getAddress)(state.walletAddress);
|
|
3868
4347
|
const generation = this.readGeneration;
|
|
3869
4348
|
let user = null;
|
|
3870
4349
|
try {
|
|
@@ -3988,6 +4467,7 @@ var YieldseekerAgent = class {
|
|
|
3988
4467
|
if (agent) {
|
|
3989
4468
|
this.readCache.set(this.agentListKey(state, chainId), {
|
|
3990
4469
|
expiresAt: Date.now() + YIELDSEEKER_AGENT_LIST_CACHE_MS,
|
|
4470
|
+
fetchedAt: Date.now(),
|
|
3991
4471
|
value: {
|
|
3992
4472
|
agents: [...agents, agent]
|
|
3993
4473
|
}
|
|
@@ -4048,7 +4528,6 @@ var YieldseekerAgent = class {
|
|
|
4048
4528
|
...previous,
|
|
4049
4529
|
epoch: this.movementEpochs.get(key2) ?? 0,
|
|
4050
4530
|
delta: previous.delta + delta,
|
|
4051
|
-
expectedBalance: previous.expectedBalance + delta,
|
|
4052
4531
|
expectedNetDeposits: previous.expectedNetDeposits + delta
|
|
4053
4532
|
};
|
|
4054
4533
|
}
|
|
@@ -4061,7 +4540,6 @@ var YieldseekerAgent = class {
|
|
|
4061
4540
|
epoch: this.movementEpochs.get(key2) ?? 0,
|
|
4062
4541
|
delta,
|
|
4063
4542
|
decimals: snapshot.baseAssetDecimals,
|
|
4064
|
-
expectedBalance: BigInt(snapshot.totalValueBase) + delta,
|
|
4065
4543
|
expectedNetDeposits: BigInt(snapshot.netDepositsBase) + delta
|
|
4066
4544
|
};
|
|
4067
4545
|
}
|
|
@@ -4090,9 +4568,8 @@ var YieldseekerAgent = class {
|
|
|
4090
4568
|
const movement = this.snapshotMovements.get(contextKey);
|
|
4091
4569
|
const snapshot = response.agentSnapshot;
|
|
4092
4570
|
if (movement && snapshot.baseAssetDecimals === movement.decimals && /^-?\d+$/.test(snapshot.netDepositsBase) && /^\d+$/.test(snapshot.totalValueBase)) {
|
|
4093
|
-
const balance = BigInt(snapshot.totalValueBase);
|
|
4094
4571
|
const netDeposits = BigInt(snapshot.netDepositsBase);
|
|
4095
|
-
const reconciled = movement.delta > 0n ?
|
|
4572
|
+
const reconciled = movement.delta > 0n ? netDeposits >= movement.expectedNetDeposits : netDeposits <= movement.expectedNetDeposits;
|
|
4096
4573
|
if (reconciled) {
|
|
4097
4574
|
this.snapshotMovements.delete(contextKey);
|
|
4098
4575
|
this.reconcileUntil.delete(contextKey);
|
|
@@ -4146,12 +4623,20 @@ var YieldseekerAgent = class {
|
|
|
4146
4623
|
const { version, read: read2 } = this.portfolioSnapshot(state, chainId, context, contextKey);
|
|
4147
4624
|
const parts = this.loadPortfolioParts(state, chainId, context, options, contextKey);
|
|
4148
4625
|
try {
|
|
4149
|
-
|
|
4626
|
+
let positionsUnavailable = false;
|
|
4627
|
+
const safeParts = options.allowMissingPositions ? parts.catch(() => {
|
|
4628
|
+
positionsUnavailable = true;
|
|
4629
|
+
return { positions: [] };
|
|
4630
|
+
}) : parts;
|
|
4631
|
+
const [snapshot, portfolioParts] = await Promise.all([read2, safeParts]);
|
|
4150
4632
|
assertSession();
|
|
4151
4633
|
if (this.portfolioVersion(contextKey) !== version) continue;
|
|
4152
4634
|
return {
|
|
4153
4635
|
...context,
|
|
4154
4636
|
snapshot: snapshot.agentSnapshot,
|
|
4637
|
+
fetchedAt: this.readCache.get(`snapshot:${contextKey}`)?.fetchedAt,
|
|
4638
|
+
readVersion: version,
|
|
4639
|
+
positionsUnavailable,
|
|
4155
4640
|
...portfolioParts
|
|
4156
4641
|
};
|
|
4157
4642
|
} catch (error) {
|
|
@@ -4241,7 +4726,7 @@ var YieldseekerAgent = class {
|
|
|
4241
4726
|
this.agentPath(context, "deploy"),
|
|
4242
4727
|
{ method: "POST", body: {} }
|
|
4243
4728
|
);
|
|
4244
|
-
if (!deployed?.agentWallet || !(0,
|
|
4729
|
+
if (!deployed?.agentWallet || !(0, import_viem8.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
|
|
4245
4730
|
throw this.invalidResponse("agent deployment", {
|
|
4246
4731
|
reason: "Deploy did not return the expected Agent Wallet."
|
|
4247
4732
|
});
|
|
@@ -4342,20 +4827,22 @@ var YieldseekerAgent = class {
|
|
|
4342
4827
|
this.id
|
|
4343
4828
|
);
|
|
4344
4829
|
}
|
|
4345
|
-
async submitTransaction(state, chainId, transaction) {
|
|
4830
|
+
async submitTransaction(state, chainId, transaction, onSubmitted, onReceipt) {
|
|
4346
4831
|
if (this.transactionExecutor) {
|
|
4347
|
-
|
|
4832
|
+
const hash2 = await this.transactionExecutor(state, chainId, transaction);
|
|
4833
|
+
onSubmitted?.(hash2);
|
|
4834
|
+
return hash2;
|
|
4348
4835
|
}
|
|
4349
4836
|
this.assertTransaction(transaction, state, chainId);
|
|
4350
|
-
const account = (0,
|
|
4351
|
-
const walletClient = (0,
|
|
4837
|
+
const account = (0, import_viem8.getAddress)(state.walletAddress);
|
|
4838
|
+
const walletClient = (0, import_viem8.createWalletClient)({
|
|
4352
4839
|
account,
|
|
4353
4840
|
chain: import_chains3.base,
|
|
4354
|
-
transport: (0,
|
|
4841
|
+
transport: (0, import_viem8.custom)(state.provider)
|
|
4355
4842
|
});
|
|
4356
|
-
const walletChainClient = (0,
|
|
4843
|
+
const walletChainClient = (0, import_viem8.createPublicClient)({
|
|
4357
4844
|
chain: import_chains3.base,
|
|
4358
|
-
transport: (0,
|
|
4845
|
+
transport: (0, import_viem8.custom)(state.provider)
|
|
4359
4846
|
});
|
|
4360
4847
|
await ensureWalletOnChain(
|
|
4361
4848
|
walletChainClient,
|
|
@@ -4365,10 +4852,11 @@ var YieldseekerAgent = class {
|
|
|
4365
4852
|
const hash = await walletClient.sendTransaction({
|
|
4366
4853
|
account,
|
|
4367
4854
|
chain: import_chains3.base,
|
|
4368
|
-
to: (0,
|
|
4855
|
+
to: (0, import_viem8.getAddress)(transaction.to),
|
|
4369
4856
|
data: transaction.data,
|
|
4370
4857
|
value: BigInt(transaction.value)
|
|
4371
4858
|
});
|
|
4859
|
+
onSubmitted?.(hash);
|
|
4372
4860
|
const receipt = await withPaidRpcDiagnostics(
|
|
4373
4861
|
() => this.getReceiptClient().waitForTransactionReceipt({
|
|
4374
4862
|
hash,
|
|
@@ -4386,6 +4874,7 @@ var YieldseekerAgent = class {
|
|
|
4386
4874
|
this.id
|
|
4387
4875
|
);
|
|
4388
4876
|
}
|
|
4877
|
+
onReceipt?.(receipt);
|
|
4389
4878
|
return hash;
|
|
4390
4879
|
}
|
|
4391
4880
|
async waitForReceipt(state, chainId, transactionHash) {
|
|
@@ -4410,14 +4899,15 @@ var YieldseekerAgent = class {
|
|
|
4410
4899
|
this.id
|
|
4411
4900
|
);
|
|
4412
4901
|
}
|
|
4902
|
+
return receipt;
|
|
4413
4903
|
}
|
|
4414
4904
|
assertTransaction(transaction, state, chainId) {
|
|
4415
|
-
if (!transaction || typeof transaction.from !== "string" || !(0,
|
|
4905
|
+
if (!transaction || typeof transaction.from !== "string" || !(0, import_viem8.isAddress)(transaction.from) || typeof transaction.to !== "string" || !(0, import_viem8.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_viem8.getAddress)(transaction.from) !== (0, import_viem8.getAddress)(state.walletAddress)) {
|
|
4416
4906
|
throw this.invalidResponse("transaction");
|
|
4417
4907
|
}
|
|
4418
4908
|
}
|
|
4419
4909
|
assertAgent(agent) {
|
|
4420
|
-
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0,
|
|
4910
|
+
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem8.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
|
|
4421
4911
|
throw this.invalidResponse("agent");
|
|
4422
4912
|
}
|
|
4423
4913
|
}
|
|
@@ -4570,7 +5060,7 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
4570
5060
|
}
|
|
4571
5061
|
|
|
4572
5062
|
// src/lib/helpers/withdraw-helper.ts
|
|
4573
|
-
var
|
|
5063
|
+
var import_viem9 = require("viem");
|
|
4574
5064
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
4575
5065
|
const target = asset.toUpperCase();
|
|
4576
5066
|
return agents.map((agent) => {
|
|
@@ -4578,7 +5068,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
4578
5068
|
const tokenBalance = agentBalance?.tokens.find(
|
|
4579
5069
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
4580
5070
|
);
|
|
4581
|
-
let balance = tokenBalance ? (0,
|
|
5071
|
+
let balance = tokenBalance ? (0, import_viem9.parseUnits)(tokenBalance.amount, decimals) : 0n;
|
|
4582
5072
|
if (agent.balanceComposition === "tokens-plus-positions") {
|
|
4583
5073
|
const chainNameById = {
|
|
4584
5074
|
1: "ETHEREUM",
|
|
@@ -4590,14 +5080,14 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
4590
5080
|
const positionChain = position2.chain.trim().toUpperCase();
|
|
4591
5081
|
const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
|
|
4592
5082
|
if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
|
|
4593
|
-
balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : (0,
|
|
5083
|
+
balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : (0, import_viem9.parseUnits)(position2.amount, decimals);
|
|
4594
5084
|
}
|
|
4595
5085
|
}
|
|
4596
5086
|
const assetTotal = agentBalance?.assetBalances?.find(
|
|
4597
5087
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
4598
5088
|
);
|
|
4599
5089
|
if (assetTotal) {
|
|
4600
|
-
const total = (0,
|
|
5090
|
+
const total = (0, import_viem9.parseUnits)(assetTotal.amount, decimals);
|
|
4601
5091
|
if (total < balance) balance = total > 0n ? total : 0n;
|
|
4602
5092
|
}
|
|
4603
5093
|
return { agent, balance };
|
|
@@ -4756,14 +5246,14 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
4756
5246
|
}
|
|
4757
5247
|
|
|
4758
5248
|
// src/client.ts
|
|
4759
|
-
var
|
|
5249
|
+
var import_viem13 = require("viem");
|
|
4760
5250
|
var import_chains4 = require("viem/chains");
|
|
4761
5251
|
|
|
4762
5252
|
// src/lib/sponsored-token-batch.ts
|
|
4763
|
-
var
|
|
5253
|
+
var import_viem11 = require("viem");
|
|
4764
5254
|
|
|
4765
5255
|
// src/lib/permit2-batch.ts
|
|
4766
|
-
var
|
|
5256
|
+
var import_viem10 = require("viem");
|
|
4767
5257
|
var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
4768
5258
|
var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
4769
5259
|
var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
@@ -4776,7 +5266,7 @@ var ERC2612_PERMIT_TYPES = {
|
|
|
4776
5266
|
{ name: "deadline", type: "uint256" }
|
|
4777
5267
|
]
|
|
4778
5268
|
};
|
|
4779
|
-
var ERC2612_READ_ABI = (0,
|
|
5269
|
+
var ERC2612_READ_ABI = (0, import_viem10.parseAbi)([
|
|
4780
5270
|
"function name() view returns (string)",
|
|
4781
5271
|
"function version() view returns (string)",
|
|
4782
5272
|
"function nonces(address owner) view returns (uint256)"
|
|
@@ -4814,7 +5304,7 @@ var PERMIT_BATCH_TYPES = {
|
|
|
4814
5304
|
{ name: "amount", type: "uint256" }
|
|
4815
5305
|
]
|
|
4816
5306
|
};
|
|
4817
|
-
var PERMIT2_BATCH_ABI = (0,
|
|
5307
|
+
var PERMIT2_BATCH_ABI = (0, import_viem10.parseAbi)([
|
|
4818
5308
|
"struct TokenPermissions { address token; uint256 amount; }",
|
|
4819
5309
|
"struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
|
|
4820
5310
|
"struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
|
|
@@ -4873,7 +5363,7 @@ function clear(key2) {
|
|
|
4873
5363
|
else window.localStorage.removeItem(key2);
|
|
4874
5364
|
}
|
|
4875
5365
|
function sponsorTokenBatch(i) {
|
|
4876
|
-
const key2 = `owney.token-batch.v1:${(0,
|
|
5366
|
+
const key2 = `owney.token-batch.v1:${(0, import_viem11.keccak256)((0, import_viem11.toBytes)(i.apiKey))}:${i.baseUrl ?? "default"}:${i.chainId}:${i.owner.toLowerCase()}:${i.token.toLowerCase()}`;
|
|
4877
5367
|
const plan = planOf(i.transfers);
|
|
4878
5368
|
const active = inflight.get(key2);
|
|
4879
5369
|
if (active) {
|
|
@@ -4904,7 +5394,7 @@ async function execute(i, key2, plan) {
|
|
|
4904
5394
|
baseUrl: i.baseUrl,
|
|
4905
5395
|
body
|
|
4906
5396
|
});
|
|
4907
|
-
if (!prepared.serializedTransaction || (0,
|
|
5397
|
+
if (!prepared.serializedTransaction || (0, import_viem11.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
|
|
4908
5398
|
throw new Error(
|
|
4909
5399
|
"Sponsorship API did not return a valid prepared transaction."
|
|
4910
5400
|
);
|
|
@@ -4914,12 +5404,16 @@ async function execute(i, key2, plan) {
|
|
|
4914
5404
|
};
|
|
4915
5405
|
save(key2, body);
|
|
4916
5406
|
}
|
|
5407
|
+
try {
|
|
5408
|
+
i.onSubmitted?.((0, import_viem11.keccak256)(body.serializedTransaction));
|
|
5409
|
+
} catch {
|
|
5410
|
+
}
|
|
4917
5411
|
const result = await postSponsorBatchTransfer({
|
|
4918
5412
|
apiKey: i.apiKey,
|
|
4919
5413
|
baseUrl: i.baseUrl,
|
|
4920
5414
|
body
|
|
4921
5415
|
});
|
|
4922
|
-
if (result.txHash !== (0,
|
|
5416
|
+
if (result.txHash !== (0, import_viem11.keccak256)(body.serializedTransaction))
|
|
4923
5417
|
throw new Error(
|
|
4924
5418
|
"Sponsorship receipt does not match the pending transaction."
|
|
4925
5419
|
);
|
|
@@ -4934,7 +5428,7 @@ async function execute(i, key2, plan) {
|
|
|
4934
5428
|
const saved = read(key2);
|
|
4935
5429
|
if (saved) {
|
|
4936
5430
|
const previous = JSON.parse(saved);
|
|
4937
|
-
if (previous.chainId !== i.chainId || !(0,
|
|
5431
|
+
if (previous.chainId !== i.chainId || !(0, import_viem11.isAddressEqual)(previous.from, i.owner) || !(0, import_viem11.isAddressEqual)(previous.token, i.token) || planOf(previous.transfers) !== plan)
|
|
4938
5432
|
throw new Error(
|
|
4939
5433
|
"Retry the previous token deposit and agent split first to reconcile its status."
|
|
4940
5434
|
);
|
|
@@ -4951,7 +5445,7 @@ async function execute(i, key2, plan) {
|
|
|
4951
5445
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
4952
5446
|
"Insufficient token balance for this deposit."
|
|
4953
5447
|
);
|
|
4954
|
-
if (allowance < total && (i.chainId !== 8453 || !(0,
|
|
5448
|
+
if (allowance < total && (i.chainId !== 8453 || !(0, import_viem11.isAddressEqual)(i.token, BASE_USDC_ADDRESS)))
|
|
4955
5449
|
throw new OwneyError(
|
|
4956
5450
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
4957
5451
|
"token deposits need a one-time Permit2 approval."
|
|
@@ -5042,7 +5536,8 @@ function makeSponsoredTokenCallback(deps) {
|
|
|
5042
5536
|
transfers,
|
|
5043
5537
|
pub,
|
|
5044
5538
|
wallet,
|
|
5045
|
-
onApproved: deps.onApproved
|
|
5539
|
+
onApproved: deps.onApproved,
|
|
5540
|
+
onSubmitted: (hash) => deps.onSubmitted?.(hash, transfers)
|
|
5046
5541
|
});
|
|
5047
5542
|
};
|
|
5048
5543
|
const callback = makeVerificationAwareDepositCallback(
|
|
@@ -5128,7 +5623,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
|
|
|
5128
5623
|
}
|
|
5129
5624
|
|
|
5130
5625
|
// src/lib/sponsored-calls-deposit.ts
|
|
5131
|
-
var
|
|
5626
|
+
var import_viem12 = require("viem");
|
|
5132
5627
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
5133
5628
|
var DEFAULT_MAX_POLLS = 30;
|
|
5134
5629
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -5136,7 +5631,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
5136
5631
|
method: "wallet_getCapabilities",
|
|
5137
5632
|
params: [owner]
|
|
5138
5633
|
});
|
|
5139
|
-
const forChain = caps?.[(0,
|
|
5634
|
+
const forChain = caps?.[(0, import_viem12.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
5140
5635
|
return Boolean(forChain?.paymasterService?.supported);
|
|
5141
5636
|
}
|
|
5142
5637
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -5173,8 +5668,8 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
5173
5668
|
const calls = transfers.map((transfer) => ({
|
|
5174
5669
|
to: token,
|
|
5175
5670
|
value: "0x0",
|
|
5176
|
-
data: (0,
|
|
5177
|
-
abi:
|
|
5671
|
+
data: (0, import_viem12.encodeFunctionData)({
|
|
5672
|
+
abi: import_viem12.erc20Abi,
|
|
5178
5673
|
functionName: "transfer",
|
|
5179
5674
|
args: [transfer.to, BigInt(transfer.amount)]
|
|
5180
5675
|
})
|
|
@@ -5212,7 +5707,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
5212
5707
|
{
|
|
5213
5708
|
version: "2.0.0",
|
|
5214
5709
|
from: deps.ownerAddress,
|
|
5215
|
-
chainId: (0,
|
|
5710
|
+
chainId: (0, import_viem12.toHex)(chainId),
|
|
5216
5711
|
atomicRequired: transfers.length > 1,
|
|
5217
5712
|
calls,
|
|
5218
5713
|
capabilities: {
|
|
@@ -5236,6 +5731,12 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
5236
5731
|
params: [callsId]
|
|
5237
5732
|
});
|
|
5238
5733
|
const txHash = status?.receipts?.[0]?.transactionHash;
|
|
5734
|
+
if (txHash && !status?.receipts?.some((receipt) => receipt.transactionHash !== txHash)) {
|
|
5735
|
+
try {
|
|
5736
|
+
deps.onSubmitted?.(txHash, transfers);
|
|
5737
|
+
} catch {
|
|
5738
|
+
}
|
|
5739
|
+
}
|
|
5239
5740
|
if (status?.receipts?.some((receipt) => receipt.status === "0x0") || typeof status?.status === "number" && status.status >= 400) {
|
|
5240
5741
|
throw new OwneyError(
|
|
5241
5742
|
"SPONSOR_REQUEST_FAILED",
|
|
@@ -5345,6 +5846,7 @@ var OwneySDK = class {
|
|
|
5345
5846
|
paymasterServiceUrl;
|
|
5346
5847
|
cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
|
|
5347
5848
|
agentReads = new AgentReads();
|
|
5849
|
+
recoveredFundingReads = /* @__PURE__ */ new Set();
|
|
5348
5850
|
activationChecks = /* @__PURE__ */ new Map();
|
|
5349
5851
|
readAgent(agent, method, fetch2, params = null) {
|
|
5350
5852
|
const key2 = JSON.stringify([
|
|
@@ -5458,8 +5960,8 @@ var OwneySDK = class {
|
|
|
5458
5960
|
return createPaidRpcClient(VIEM_CHAIN2[chainId], this.rpcUrls);
|
|
5459
5961
|
}
|
|
5460
5962
|
/** Builds the default USDC batch callback for the connected wallet. */
|
|
5461
|
-
getDefaultSponsoredCallback(onApproved) {
|
|
5462
|
-
if (!onApproved && this.cachedSponsoredCallback)
|
|
5963
|
+
getDefaultSponsoredCallback(onApproved, onSubmitted) {
|
|
5964
|
+
if (!onApproved && !onSubmitted && this.cachedSponsoredCallback)
|
|
5463
5965
|
return this.cachedSponsoredCallback;
|
|
5464
5966
|
const provider = this.requireConnectedProvider();
|
|
5465
5967
|
const owner = this.state.walletAddress;
|
|
@@ -5468,28 +5970,29 @@ var OwneySDK = class {
|
|
|
5468
5970
|
baseUrl: this.routingApiBaseUrl,
|
|
5469
5971
|
ownerAddress: owner,
|
|
5470
5972
|
onApproved,
|
|
5973
|
+
onSubmitted,
|
|
5471
5974
|
tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
|
|
5472
5975
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
5473
5976
|
// PublicClient/WalletClient param types — structurally identical at
|
|
5474
5977
|
// runtime, but the two share a name TS treats as unrelated.
|
|
5475
5978
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
5476
|
-
getWalletChainClient: (cid) => (0,
|
|
5979
|
+
getWalletChainClient: (cid) => (0, import_viem13.createPublicClient)({
|
|
5477
5980
|
chain: VIEM_CHAIN2[cid],
|
|
5478
|
-
transport: (0,
|
|
5981
|
+
transport: (0, import_viem13.custom)(provider)
|
|
5479
5982
|
}),
|
|
5480
|
-
getWalletClient: (cid) => (0,
|
|
5983
|
+
getWalletClient: (cid) => (0, import_viem13.createWalletClient)({
|
|
5481
5984
|
account: owner,
|
|
5482
5985
|
chain: VIEM_CHAIN2[cid],
|
|
5483
|
-
transport: (0,
|
|
5986
|
+
transport: (0, import_viem13.custom)(provider)
|
|
5484
5987
|
})
|
|
5485
5988
|
});
|
|
5486
|
-
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
5989
|
+
if (!onApproved && !onSubmitted) this.cachedSponsoredCallback = callback;
|
|
5487
5990
|
return callback;
|
|
5488
5991
|
}
|
|
5489
5992
|
/** Builds the wallet-native sponsored calls callback for compatible paymasters. */
|
|
5490
|
-
getDefaultSponsoredCallsCallback(asset, onApproved) {
|
|
5993
|
+
getDefaultSponsoredCallsCallback(asset, onApproved, onSubmitted) {
|
|
5491
5994
|
const cached = this.cachedSponsoredCallsCallbacks.get(asset);
|
|
5492
|
-
if (!onApproved && cached) return cached;
|
|
5995
|
+
if (!onApproved && !onSubmitted && cached) return cached;
|
|
5493
5996
|
const provider = this.requireConnectedProvider();
|
|
5494
5997
|
const callback = makeSponsoredCallsCallback({
|
|
5495
5998
|
apiKey: this.apiKey,
|
|
@@ -5498,9 +6001,10 @@ var OwneySDK = class {
|
|
|
5498
6001
|
ownerAddress: this.state.walletAddress,
|
|
5499
6002
|
paymasterServiceUrl: this.paymasterServiceUrl,
|
|
5500
6003
|
onApproved,
|
|
6004
|
+
onSubmitted,
|
|
5501
6005
|
tokenAddressByChain: sponsoredTokensFor(asset)
|
|
5502
6006
|
});
|
|
5503
|
-
if (!onApproved) this.cachedSponsoredCallsCallbacks.set(asset, callback);
|
|
6007
|
+
if (!onApproved && !onSubmitted) this.cachedSponsoredCallsCallbacks.set(asset, callback);
|
|
5504
6008
|
return callback;
|
|
5505
6009
|
}
|
|
5506
6010
|
/**
|
|
@@ -5509,8 +6013,8 @@ var OwneySDK = class {
|
|
|
5509
6013
|
* Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
5510
6014
|
* single-use batch authorization instead of an EIP-3009 authorization.
|
|
5511
6015
|
*/
|
|
5512
|
-
getDefaultWethSponsoredCallback(onApproved) {
|
|
5513
|
-
if (!onApproved && this.cachedWethSponsoredCallback)
|
|
6016
|
+
getDefaultWethSponsoredCallback(onApproved, onSubmitted) {
|
|
6017
|
+
if (!onApproved && !onSubmitted && this.cachedWethSponsoredCallback)
|
|
5514
6018
|
return this.cachedWethSponsoredCallback;
|
|
5515
6019
|
const provider = this.requireConnectedProvider();
|
|
5516
6020
|
const owner = this.state.walletAddress;
|
|
@@ -5519,22 +6023,23 @@ var OwneySDK = class {
|
|
|
5519
6023
|
baseUrl: this.routingApiBaseUrl,
|
|
5520
6024
|
ownerAddress: owner,
|
|
5521
6025
|
onApproved,
|
|
6026
|
+
onSubmitted,
|
|
5522
6027
|
tokenAddressByChain: SPONSORED_WETH_BY_CHAIN,
|
|
5523
6028
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
5524
6029
|
// PublicClient/WalletClient param types — structurally identical at
|
|
5525
6030
|
// runtime, but the two share a name TS treats as unrelated.
|
|
5526
6031
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
5527
|
-
getWalletChainClient: (cid) => (0,
|
|
6032
|
+
getWalletChainClient: (cid) => (0, import_viem13.createPublicClient)({
|
|
5528
6033
|
chain: VIEM_CHAIN2[cid],
|
|
5529
|
-
transport: (0,
|
|
6034
|
+
transport: (0, import_viem13.custom)(provider)
|
|
5530
6035
|
}),
|
|
5531
|
-
getWalletClient: (cid) => (0,
|
|
6036
|
+
getWalletClient: (cid) => (0, import_viem13.createWalletClient)({
|
|
5532
6037
|
account: owner,
|
|
5533
6038
|
chain: VIEM_CHAIN2[cid],
|
|
5534
|
-
transport: (0,
|
|
6039
|
+
transport: (0, import_viem13.custom)(provider)
|
|
5535
6040
|
})
|
|
5536
6041
|
});
|
|
5537
|
-
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
6042
|
+
if (!onApproved && !onSubmitted) this.cachedWethSponsoredCallback = callback;
|
|
5538
6043
|
return callback;
|
|
5539
6044
|
}
|
|
5540
6045
|
getAgent(agentId) {
|
|
@@ -5544,6 +6049,9 @@ var OwneySDK = class {
|
|
|
5544
6049
|
}
|
|
5545
6050
|
return agent;
|
|
5546
6051
|
}
|
|
6052
|
+
getActiveAgentIds() {
|
|
6053
|
+
return [...this.getActiveAgents().keys()].sort();
|
|
6054
|
+
}
|
|
5547
6055
|
getActiveAgents() {
|
|
5548
6056
|
const active = /* @__PURE__ */ new Map();
|
|
5549
6057
|
for (const id of this.activeAgents) {
|
|
@@ -5838,12 +6346,23 @@ var OwneySDK = class {
|
|
|
5838
6346
|
*/
|
|
5839
6347
|
async deposit(options) {
|
|
5840
6348
|
const { amount, asset, depositCallback, agentId, onApproved } = options;
|
|
6349
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
6350
|
+
const onProgress = options.onProgress ? (evidence) => {
|
|
6351
|
+
if (evidence.agentWallet) prepared.set(evidence.agentWallet.toLowerCase(), evidence);
|
|
6352
|
+
notifyFunding(options.onProgress, evidence);
|
|
6353
|
+
} : void 0;
|
|
6354
|
+
const onSubmitted = onProgress ? (hash, destinations) => {
|
|
6355
|
+
for (const destination of destinations) {
|
|
6356
|
+
const evidence = prepared.get(destination.to.toLowerCase());
|
|
6357
|
+
if (evidence) notifyFunding(onProgress, { ...evidence, txHash: hash, transfer: "pending" });
|
|
6358
|
+
}
|
|
6359
|
+
} : void 0;
|
|
5841
6360
|
if (BigInt(amount) === 0n) {
|
|
5842
6361
|
return { agentResults: {} };
|
|
5843
6362
|
}
|
|
5844
6363
|
const state = this.requireState();
|
|
5845
6364
|
const chainId = this.requireChainId();
|
|
5846
|
-
const effectiveCallback = depositCallback ?? (this.paymasterServiceUrl ? this.getDefaultSponsoredCallsCallback(asset, onApproved) : asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved) : this.getDefaultSponsoredCallback(onApproved));
|
|
6365
|
+
const effectiveCallback = depositCallback ?? (this.paymasterServiceUrl ? this.getDefaultSponsoredCallsCallback(asset, onApproved, onSubmitted) : asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved, onSubmitted) : this.getDefaultSponsoredCallback(onApproved, onSubmitted));
|
|
5847
6366
|
if (agentId) {
|
|
5848
6367
|
if (this.isAgentDisabled(agentId)) {
|
|
5849
6368
|
throw new OwneyError(
|
|
@@ -5862,7 +6381,8 @@ var OwneySDK = class {
|
|
|
5862
6381
|
amount,
|
|
5863
6382
|
asset,
|
|
5864
6383
|
effectiveCallback,
|
|
5865
|
-
depositCallback
|
|
6384
|
+
depositCallback,
|
|
6385
|
+
onProgress
|
|
5866
6386
|
);
|
|
5867
6387
|
}
|
|
5868
6388
|
const totalAmount = BigInt(amount);
|
|
@@ -5926,7 +6446,7 @@ var OwneySDK = class {
|
|
|
5926
6446
|
run: (callback) => withFailureReporting(
|
|
5927
6447
|
this.apiKey,
|
|
5928
6448
|
agent.id,
|
|
5929
|
-
() => agent.deposit(state, chainId, amount2, asset, callback),
|
|
6449
|
+
() => onProgress ? agent.deposit(state, chainId, amount2, asset, callback, onProgress) : agent.deposit(state, chainId, amount2, asset, callback),
|
|
5930
6450
|
this.routingApiBaseUrl
|
|
5931
6451
|
)
|
|
5932
6452
|
})),
|
|
@@ -5963,7 +6483,8 @@ var OwneySDK = class {
|
|
|
5963
6483
|
agentAmount,
|
|
5964
6484
|
asset,
|
|
5965
6485
|
effectiveCallback,
|
|
5966
|
-
depositCallback
|
|
6486
|
+
depositCallback,
|
|
6487
|
+
onProgress
|
|
5967
6488
|
);
|
|
5968
6489
|
} catch (error) {
|
|
5969
6490
|
if (Object.keys(agentResults).length === 0) throw error;
|
|
@@ -6010,17 +6531,11 @@ var OwneySDK = class {
|
|
|
6010
6531
|
* propagates unchanged. Scoped per agent invocation so one agent's failure
|
|
6011
6532
|
* doesn't force a retry of sibling agents in a multi-agent split.
|
|
6012
6533
|
*/
|
|
6013
|
-
async depositWithFallback(agent, state, chainId, amount, asset, effectiveCallback, appCallback) {
|
|
6534
|
+
async depositWithFallback(agent, state, chainId, amount, asset, effectiveCallback, appCallback, onProgress) {
|
|
6014
6535
|
const attempt = (callback) => withFailureReporting(
|
|
6015
6536
|
this.apiKey,
|
|
6016
6537
|
agent.id,
|
|
6017
|
-
() => agent.deposit(
|
|
6018
|
-
state,
|
|
6019
|
-
chainId,
|
|
6020
|
-
amount,
|
|
6021
|
-
asset,
|
|
6022
|
-
callback
|
|
6023
|
-
),
|
|
6538
|
+
() => onProgress ? agent.deposit(state, chainId, amount, asset, callback, onProgress) : agent.deposit(state, chainId, amount, asset, callback),
|
|
6024
6539
|
this.routingApiBaseUrl
|
|
6025
6540
|
);
|
|
6026
6541
|
let approvalAttempted = false;
|
|
@@ -6200,15 +6715,81 @@ var OwneySDK = class {
|
|
|
6200
6715
|
while (current && typeof current === "object" && !seen.has(current)) {
|
|
6201
6716
|
seen.add(current);
|
|
6202
6717
|
const candidate = current;
|
|
6203
|
-
if (candidate.code === 4001 || candidate.code === "4001") return true;
|
|
6718
|
+
if (candidate.code === 4001 || candidate.code === "4001" || candidate.code === "ACTION_REJECTED") return true;
|
|
6204
6719
|
const message = [candidate.message, candidate.shortMessage].filter((value) => typeof value === "string").join(" ");
|
|
6205
|
-
if (/user (?:rejected|denied)|rejected by user/i.test(message)) {
|
|
6720
|
+
if (/user (?:rejected|denied)|rejected by user|request rejected/i.test(message)) {
|
|
6206
6721
|
return true;
|
|
6207
6722
|
}
|
|
6208
6723
|
current = candidate.cause;
|
|
6209
6724
|
}
|
|
6210
6725
|
return false;
|
|
6211
6726
|
}
|
|
6727
|
+
captureReadScope(requestedChain) {
|
|
6728
|
+
const original = this.requireState();
|
|
6729
|
+
const chainId = this.requireChainId();
|
|
6730
|
+
if (requestedChain !== void 0 && requestedChain !== chainId) {
|
|
6731
|
+
throw new OwneyError("NO_ACTIVE_CHAIN", "Account read scope changed. Please retry.");
|
|
6732
|
+
}
|
|
6733
|
+
const wallet = original.walletAddress;
|
|
6734
|
+
return { state: { ...original }, chainId, assertCurrent: () => {
|
|
6735
|
+
if (this.state !== original || this.state.walletAddress !== wallet || this.state.chainId !== chainId)
|
|
6736
|
+
throw new OwneyError("NOT_CONNECTED", "Account read scope changed. Please retry.");
|
|
6737
|
+
} };
|
|
6738
|
+
}
|
|
6739
|
+
/** Revalidate a saved transfer against the authenticated account and actual receipt. */
|
|
6740
|
+
async inspectFunding(evidence, direction, options = {}) {
|
|
6741
|
+
const { state, chainId, assertCurrent } = this.captureReadScope(evidence.chainId);
|
|
6742
|
+
if (state.walletAddress.toLowerCase() !== evidence.walletAddress.toLowerCase() || !evidence.txHash)
|
|
6743
|
+
throw new OwneyError("AGENT_API_ERROR", "Funding evidence does not match the connected account.");
|
|
6744
|
+
const agent = this.getAgent(evidence.agentId);
|
|
6745
|
+
const verifiedWallet = agent.getFundingWallet ? await agent.getFundingWallet(state, chainId, evidence.token) : (await agent.getUserProfile(state, chainId)).smartWallet;
|
|
6746
|
+
const agentWallet = evidence.agentWallet ?? verifiedWallet;
|
|
6747
|
+
if (!agentWallet || agentWallet.toLowerCase() !== verifiedWallet.toLowerCase())
|
|
6748
|
+
throw new OwneyError("AGENT_API_ERROR", "Funding wallet does not match this account.");
|
|
6749
|
+
const token = SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token);
|
|
6750
|
+
if (!token) throw new OwneyError("CHAIN_UNSUPPORTED", "Unsupported funding asset.");
|
|
6751
|
+
const rpc = this.getPaidRpcClient(chainId);
|
|
6752
|
+
const receipt = await rpc.getTransactionReceipt({ hash: evidence.txHash });
|
|
6753
|
+
assertCurrent();
|
|
6754
|
+
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction);
|
|
6755
|
+
if (direction === "withdraw" && evidence.agentId === "yieldseeker" && verified.transfer === "unknown" && verified.confirmedAmount && BigInt(verified.confirmedAmount) > 0n) {
|
|
6756
|
+
const transaction = await rpc.getTransaction({ hash: evidence.txHash });
|
|
6757
|
+
assertCurrent();
|
|
6758
|
+
if (isFullYieldseekerWithdrawal(transaction, { ...evidence, agentWallet }, token.address))
|
|
6759
|
+
verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet, intendedAmount: "MAX" }, token.address, direction);
|
|
6760
|
+
}
|
|
6761
|
+
const key2 = `${state.walletAddress.toLowerCase()}:${chainId}:${evidence.agentId}:${evidence.token}:${evidence.txHash}`;
|
|
6762
|
+
if ((verified.transfer === "confirmed" || verified.transfer === "failed" && verified.confirmedAmount === "0") && !this.recoveredFundingReads.has(key2)) {
|
|
6763
|
+
if (options.refreshBalance !== false)
|
|
6764
|
+
agent.invalidateFundingRead?.(state, chainId, evidence.token, options.balanceRefreshUntil);
|
|
6765
|
+
this.recoveredFundingReads.add(key2);
|
|
6766
|
+
if (this.recoveredFundingReads.size > 256) this.recoveredFundingReads.delete(this.recoveredFundingReads.values().next().value);
|
|
6767
|
+
}
|
|
6768
|
+
return verified;
|
|
6769
|
+
}
|
|
6770
|
+
/** A display acknowledgement controls polling only; it never confirms a financial outcome. */
|
|
6771
|
+
endFundingBalanceRefresh(evidence, read2) {
|
|
6772
|
+
const { state, chainId } = this.captureReadScope(evidence.chainId);
|
|
6773
|
+
if (state.walletAddress.toLowerCase() !== evidence.walletAddress.toLowerCase() || read2.chainId !== chainId || read2.asset.toUpperCase() !== evidence.token) return false;
|
|
6774
|
+
return this.getAgent(evidence.agentId).endFundingBalanceRefresh?.(state, chainId, evidence.token, read2) ?? false;
|
|
6775
|
+
}
|
|
6776
|
+
/** History lookup for receipt recovery; adapters may not authenticate or sign here. */
|
|
6777
|
+
async getFundingHistory(evidence, fromDate, options) {
|
|
6778
|
+
const { state, chainId, assertCurrent } = this.captureReadScope(evidence.chainId);
|
|
6779
|
+
if (state.walletAddress.toLowerCase() !== evidence.walletAddress.toLowerCase())
|
|
6780
|
+
throw new OwneyError("NOT_CONNECTED", "Funding account changed.");
|
|
6781
|
+
const agent = this.getAgent(evidence.agentId);
|
|
6782
|
+
if (!agent.getFundingHistory) return { data: [], hasMore: false };
|
|
6783
|
+
const filters = { tokenSymbol: evidence.token, fromDate, limit: 50, ...options };
|
|
6784
|
+
const page = await this.readAgent(agent, "history", () => agent.getFundingHistory(state, chainId, filters), filters);
|
|
6785
|
+
assertCurrent();
|
|
6786
|
+
return page;
|
|
6787
|
+
}
|
|
6788
|
+
async recoverDepositRegistration(evidence) {
|
|
6789
|
+
const verified = await this.inspectFunding(evidence, "deposit");
|
|
6790
|
+
if (verified.agentId !== "zyfai") return verified;
|
|
6791
|
+
return this.getAgent("zyfai").retryDepositRegistration(this.requireState(), verified);
|
|
6792
|
+
}
|
|
6212
6793
|
// --- Fund operations ---
|
|
6213
6794
|
/**
|
|
6214
6795
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -6220,17 +6801,66 @@ var OwneySDK = class {
|
|
|
6220
6801
|
* @returns {AgentWithdrawResult} for a single agent, or {OwneyWithdrawResult} with per-agent results
|
|
6221
6802
|
*/
|
|
6222
6803
|
async withdraw(options) {
|
|
6804
|
+
const state = this.requireState();
|
|
6805
|
+
const chainId = this.requireChainId();
|
|
6806
|
+
const ids = options.agentId ? [options.agentId] : this.getActiveAgentIds().filter((id) => !options.excludeAgentIds?.includes(id));
|
|
6807
|
+
const attempted = /* @__PURE__ */ new Set();
|
|
6808
|
+
try {
|
|
6809
|
+
return await this.withdrawFromAgents(options, state, chainId, attempted);
|
|
6810
|
+
} catch (error) {
|
|
6811
|
+
for (const id of ids) if (!attempted.has(id)) {
|
|
6812
|
+
notifyFunding(options.onProgress, {
|
|
6813
|
+
agentId: id,
|
|
6814
|
+
chainId,
|
|
6815
|
+
token: options.asset,
|
|
6816
|
+
walletAddress: state.walletAddress,
|
|
6817
|
+
intendedAmount: options.amount ?? "MAX",
|
|
6818
|
+
transfer: "failed",
|
|
6819
|
+
registration: "not-applicable",
|
|
6820
|
+
delivery: "failed"
|
|
6821
|
+
});
|
|
6822
|
+
}
|
|
6823
|
+
throw error;
|
|
6824
|
+
}
|
|
6825
|
+
}
|
|
6826
|
+
async withdrawFromAgents(options, state, chainId, attempted) {
|
|
6223
6827
|
const { asset, amount, agentId, onAgentResult } = options;
|
|
6224
6828
|
const notifyAgentResult = (id, result) => {
|
|
6225
6829
|
try {
|
|
6830
|
+
if (result.evidence) notifyFunding(options.onProgress, result.evidence);
|
|
6226
6831
|
onAgentResult?.(id, result);
|
|
6227
6832
|
} catch (error) {
|
|
6228
6833
|
console.warn("Withdrawal result observer failed:", error);
|
|
6229
6834
|
}
|
|
6230
6835
|
};
|
|
6231
|
-
const state = this.requireState();
|
|
6232
|
-
const chainId = this.requireChainId();
|
|
6233
6836
|
const token = asset;
|
|
6837
|
+
const submissionEvidence = /* @__PURE__ */ new Map();
|
|
6838
|
+
const submit = async (agent, requested2) => {
|
|
6839
|
+
attempted.add(agent.id);
|
|
6840
|
+
let evidence = {
|
|
6841
|
+
agentId: agent.id,
|
|
6842
|
+
chainId,
|
|
6843
|
+
token,
|
|
6844
|
+
walletAddress: state.walletAddress,
|
|
6845
|
+
intendedAmount: requested2 ?? "MAX",
|
|
6846
|
+
transfer: "pending",
|
|
6847
|
+
registration: "not-applicable",
|
|
6848
|
+
delivery: "pending"
|
|
6849
|
+
};
|
|
6850
|
+
const progress = (next) => {
|
|
6851
|
+
evidence = { ...evidence, ...next };
|
|
6852
|
+
submissionEvidence.set(agent.id, evidence);
|
|
6853
|
+
notifyFunding(options.onProgress, evidence);
|
|
6854
|
+
};
|
|
6855
|
+
progress(evidence);
|
|
6856
|
+
try {
|
|
6857
|
+
return await agent.withdraw(state, chainId, token, requested2, progress);
|
|
6858
|
+
} catch (error) {
|
|
6859
|
+
if (!evidence.txHash && (this.isUserRejectedWithdrawal(error) || /insufficient (balance|funds)/i.test(error instanceof Error ? error.message : "")))
|
|
6860
|
+
progress({ ...evidence, transfer: "failed", delivery: "failed" });
|
|
6861
|
+
throw error;
|
|
6862
|
+
}
|
|
6863
|
+
};
|
|
6234
6864
|
const assetInfo = SupportedAssets.find(
|
|
6235
6865
|
(a) => a.chainId === chainId && a.symbol === token
|
|
6236
6866
|
);
|
|
@@ -6246,23 +6876,24 @@ var OwneySDK = class {
|
|
|
6246
6876
|
const result = await withFailureReporting(
|
|
6247
6877
|
this.apiKey,
|
|
6248
6878
|
agent.id,
|
|
6249
|
-
() => agent
|
|
6879
|
+
() => submit(agent, amount),
|
|
6250
6880
|
this.routingApiBaseUrl
|
|
6251
6881
|
);
|
|
6252
6882
|
notifyAgentResult(agent.id, result);
|
|
6253
6883
|
return result;
|
|
6254
6884
|
}
|
|
6255
|
-
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
6885
|
+
const eligibleAgents = this.getEligibleAgents(chainId, asset).filter((agent) => !options.excludeAgentIds?.includes(agent.id));
|
|
6256
6886
|
const withdrawalAgents = this.orderAgentsForWithdrawal(eligibleAgents);
|
|
6257
6887
|
if (!amount) {
|
|
6258
6888
|
const results2 = {};
|
|
6259
6889
|
const agentErrors2 = {};
|
|
6260
6890
|
for (const agent of withdrawalAgents) {
|
|
6261
6891
|
try {
|
|
6262
|
-
results2[agent.id] = await agent
|
|
6892
|
+
results2[agent.id] = await submit(agent);
|
|
6263
6893
|
notifyAgentResult(agent.id, results2[agent.id]);
|
|
6264
6894
|
} catch (err) {
|
|
6265
6895
|
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
6896
|
+
if (err instanceof OwneyError && err.code === "WITHDRAW_INSUFFICIENT_BALANCE" && err.details?.available === "0" && submissionEvidence.get(agent.id)?.transfer === "failed") continue;
|
|
6266
6897
|
console.error(`withdraw failed for agent "${agent.id}":`, err);
|
|
6267
6898
|
agentErrors2[agent.id] = err instanceof Error ? err.message : String(err);
|
|
6268
6899
|
const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
|
|
@@ -6281,6 +6912,13 @@ var OwneySDK = class {
|
|
|
6281
6912
|
{ asset, agentErrors: agentErrors2 }
|
|
6282
6913
|
);
|
|
6283
6914
|
}
|
|
6915
|
+
if (Object.keys(agentErrors2).length > 0) {
|
|
6916
|
+
throw new OwneyError(
|
|
6917
|
+
"WITHDRAW_PARTIAL_FAILURE",
|
|
6918
|
+
"Some agents could not complete the withdrawal.",
|
|
6919
|
+
{ asset, partialResults: results2, agentErrors: agentErrors2 }
|
|
6920
|
+
);
|
|
6921
|
+
}
|
|
6284
6922
|
const amountsKnown = Object.values(results2).every(
|
|
6285
6923
|
(result) => typeof result.amount === "string" && /^\d+$/.test(result.amount)
|
|
6286
6924
|
);
|
|
@@ -6290,7 +6928,7 @@ var OwneySDK = class {
|
|
|
6290
6928
|
};
|
|
6291
6929
|
}
|
|
6292
6930
|
const requested = BigInt(amount);
|
|
6293
|
-
const aggregated = await this.getBalances();
|
|
6931
|
+
const aggregated = await this.getBalances(void 0, { chainId, asset: token });
|
|
6294
6932
|
const unavailableAgents = eligibleAgents.filter(
|
|
6295
6933
|
(agent) => !(agent.id in aggregated.agentBalances)
|
|
6296
6934
|
);
|
|
@@ -6352,12 +6990,7 @@ var OwneySDK = class {
|
|
|
6352
6990
|
const p = orderedPlans[i];
|
|
6353
6991
|
if (p.planned === 0n) continue;
|
|
6354
6992
|
try {
|
|
6355
|
-
results[p.agent.id] = await p.agent.
|
|
6356
|
-
state,
|
|
6357
|
-
chainId,
|
|
6358
|
-
token,
|
|
6359
|
-
p.planned.toString()
|
|
6360
|
-
);
|
|
6993
|
+
results[p.agent.id] = await submit(p.agent, p.planned.toString());
|
|
6361
6994
|
notifyAgentResult(p.agent.id, results[p.agent.id]);
|
|
6362
6995
|
} catch (err) {
|
|
6363
6996
|
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
@@ -6372,7 +7005,8 @@ var OwneySDK = class {
|
|
|
6372
7005
|
);
|
|
6373
7006
|
const failedAmount = p.planned;
|
|
6374
7007
|
p.planned = 0n;
|
|
6375
|
-
|
|
7008
|
+
if (submissionEvidence.get(p.agent.id)?.transfer === "failed")
|
|
7009
|
+
redistributeShare(orderedPlans, i, failedAmount);
|
|
6376
7010
|
}
|
|
6377
7011
|
}
|
|
6378
7012
|
if (Object.keys(results).length === 0) {
|
|
@@ -6409,12 +7043,19 @@ var OwneySDK = class {
|
|
|
6409
7043
|
* @param agentId - Optional. Agent to query. Omit for aggregated balances.
|
|
6410
7044
|
* @returns {AgentBalance} for a single agent, or {OwneyBalances} with totalBalance and per-agent breakdown
|
|
6411
7045
|
*/
|
|
6412
|
-
async getBalances(agentId) {
|
|
6413
|
-
const state = this.
|
|
6414
|
-
const
|
|
7046
|
+
async getBalances(agentId, options) {
|
|
7047
|
+
const { state, chainId, assertCurrent } = this.captureReadScope(options?.chainId);
|
|
7048
|
+
const asset = options?.asset;
|
|
7049
|
+
const readBalance = (agent) => this.readAgent(
|
|
7050
|
+
agent,
|
|
7051
|
+
"balances",
|
|
7052
|
+
() => asset ? agent.getBalances(state, chainId, asset) : agent.getBalances(state, chainId),
|
|
7053
|
+
asset ? { asset } : null
|
|
7054
|
+
);
|
|
6415
7055
|
if (agentId) {
|
|
6416
7056
|
const agent = this.getAgent(agentId);
|
|
6417
|
-
const result = await
|
|
7057
|
+
const result = await readBalance(agent);
|
|
7058
|
+
assertCurrent();
|
|
6418
7059
|
return {
|
|
6419
7060
|
...result,
|
|
6420
7061
|
balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
|
|
@@ -6425,7 +7066,7 @@ var OwneySDK = class {
|
|
|
6425
7066
|
const entries = [...this.getActiveAgents().entries()];
|
|
6426
7067
|
const balanceResults = await Promise.allSettled(
|
|
6427
7068
|
entries.map(async ([id, agent]) => {
|
|
6428
|
-
const b = await
|
|
7069
|
+
const b = await readBalance(agent);
|
|
6429
7070
|
return [
|
|
6430
7071
|
id,
|
|
6431
7072
|
{
|
|
@@ -6435,6 +7076,7 @@ var OwneySDK = class {
|
|
|
6435
7076
|
];
|
|
6436
7077
|
})
|
|
6437
7078
|
);
|
|
7079
|
+
assertCurrent();
|
|
6438
7080
|
let successCount = 0;
|
|
6439
7081
|
const agentErrors = {};
|
|
6440
7082
|
const agentRetryAt = {};
|
|
@@ -6702,12 +7344,13 @@ var OwneySDK = class {
|
|
|
6702
7344
|
* @returns {OwneyAgentHistory} `data` (up to `limit` entries), `hasMore`, `nextCursor`.
|
|
6703
7345
|
*/
|
|
6704
7346
|
async getHistory(options) {
|
|
6705
|
-
const state = this.
|
|
6706
|
-
const chainId = this.requireChainId();
|
|
7347
|
+
const { state, chainId, assertCurrent } = this.captureReadScope(options?.chainId);
|
|
6707
7348
|
const { agentId, filters } = options ?? {};
|
|
6708
7349
|
if (agentId) {
|
|
6709
7350
|
const agent = this.getAgent(agentId);
|
|
6710
|
-
|
|
7351
|
+
const page = await this.readAgent(agent, "history", () => agent.getHistory(state, chainId, filters), filters);
|
|
7352
|
+
assertCurrent();
|
|
7353
|
+
return page;
|
|
6711
7354
|
}
|
|
6712
7355
|
const activeAgents = [...this.getActiveAgents().values()];
|
|
6713
7356
|
const cursorMap = filters?.cursor ? decodeMultiAgentCursor(filters.cursor) : {};
|
|
@@ -6717,20 +7360,35 @@ var OwneySDK = class {
|
|
|
6717
7360
|
if (filters?.cursor && agentCursor === void 0) {
|
|
6718
7361
|
return { agentId: agent.id, page: null };
|
|
6719
7362
|
}
|
|
6720
|
-
const agentFilters = { ...filters, cursor: agentCursor };
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
7363
|
+
const agentFilters = { ...filters, cursor: agentCursor || void 0 };
|
|
7364
|
+
try {
|
|
7365
|
+
const page = await this.readAgent(
|
|
7366
|
+
agent,
|
|
7367
|
+
"history",
|
|
7368
|
+
() => agent.getHistory(state, chainId, agentFilters),
|
|
7369
|
+
agentFilters
|
|
7370
|
+
);
|
|
7371
|
+
return { agentId: agent.id, page };
|
|
7372
|
+
} catch (error) {
|
|
7373
|
+
return { agentId: agent.id, page: null, error };
|
|
7374
|
+
}
|
|
6728
7375
|
})
|
|
6729
7376
|
);
|
|
7377
|
+
assertCurrent();
|
|
7378
|
+
const agentErrors = {};
|
|
7379
|
+
const agentRetryAt = {};
|
|
6730
7380
|
const merged = [];
|
|
6731
7381
|
const nextCursorMap = {};
|
|
6732
7382
|
let hasMore = false;
|
|
6733
|
-
for (const
|
|
7383
|
+
for (const result of perAgent) {
|
|
7384
|
+
const { agentId: id, page } = result;
|
|
7385
|
+
if ("error" in result) {
|
|
7386
|
+
agentErrors[id] = result.error instanceof Error ? result.error.message : String(result.error);
|
|
7387
|
+
const delay = rateLimitDelay(result.error);
|
|
7388
|
+
if (delay !== void 0) agentRetryAt[id] = Date.now() + delay;
|
|
7389
|
+
nextCursorMap[id] = cursorMap[id] ?? "";
|
|
7390
|
+
hasMore = true;
|
|
7391
|
+
}
|
|
6734
7392
|
if (!page) continue;
|
|
6735
7393
|
merged.push(...page.data);
|
|
6736
7394
|
if (page.hasMore && page.nextCursor) {
|
|
@@ -6750,6 +7408,7 @@ var OwneySDK = class {
|
|
|
6750
7408
|
});
|
|
6751
7409
|
return {
|
|
6752
7410
|
data: merged,
|
|
7411
|
+
...Object.keys(agentErrors).length ? { agentErrors, agentRetryAt } : {},
|
|
6753
7412
|
hasMore,
|
|
6754
7413
|
nextCursor: hasMore ? encodeMultiAgentCursor(nextCursorMap) : void 0
|
|
6755
7414
|
};
|
|
@@ -6831,16 +7490,16 @@ var OwneySDK = class {
|
|
|
6831
7490
|
);
|
|
6832
7491
|
}
|
|
6833
7492
|
const provider = this.requireConnectedProvider();
|
|
6834
|
-
const walletChainClient = (0,
|
|
7493
|
+
const walletChainClient = (0, import_viem13.createPublicClient)({
|
|
6835
7494
|
chain: VIEM_CHAIN2[chainId],
|
|
6836
|
-
transport: (0,
|
|
7495
|
+
transport: (0, import_viem13.custom)(provider)
|
|
6837
7496
|
});
|
|
6838
7497
|
const publicClient = this.getPaidRpcClient(chainId);
|
|
6839
7498
|
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
6840
|
-
const wallet = (0,
|
|
7499
|
+
const wallet = (0, import_viem13.createWalletClient)({
|
|
6841
7500
|
account: state.walletAddress,
|
|
6842
7501
|
chain: VIEM_CHAIN2[chainId],
|
|
6843
|
-
transport: (0,
|
|
7502
|
+
transport: (0, import_viem13.custom)(provider)
|
|
6844
7503
|
});
|
|
6845
7504
|
await ensureWalletOnChain(walletChainClient, wallet, chainId);
|
|
6846
7505
|
const hash = await wallet.writeContract({
|
|
@@ -7002,7 +7661,7 @@ var OwneySDK = class {
|
|
|
7002
7661
|
};
|
|
7003
7662
|
|
|
7004
7663
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
7005
|
-
var
|
|
7664
|
+
var import_viem14 = require("viem");
|
|
7006
7665
|
var import_siwe2 = require("siwe");
|
|
7007
7666
|
var import_sdk2 = require("@zyfai/sdk");
|
|
7008
7667
|
|
|
@@ -7129,7 +7788,7 @@ function buildSIWXConfig(deps) {
|
|
|
7129
7788
|
issuedAt,
|
|
7130
7789
|
toString() {
|
|
7131
7790
|
return new import_siwe2.SiweMessage({
|
|
7132
|
-
address: (0,
|
|
7791
|
+
address: (0, import_viem14.getAddress)(accountAddress),
|
|
7133
7792
|
chainId: numericChainId(chainId),
|
|
7134
7793
|
domain,
|
|
7135
7794
|
uri,
|