@owney/sdk 0.2.5

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.js ADDED
@@ -0,0 +1,1435 @@
1
+ // src/agents/zyfai/zyfai.agent.ts
2
+ import { ZyfaiSDK } from "@zyfai/sdk";
3
+
4
+ // src/types/config.ts
5
+ var P_SUPPORTED_CHAINS = {
6
+ chainIds: [8453, 42161],
7
+ chains: ["BASE", "ARBITRUM"]
8
+ };
9
+ var SUPPORTED_CHAIN_IDS = P_SUPPORTED_CHAINS.chainIds;
10
+ var SUPPORTED_CHAINS = P_SUPPORTED_CHAINS.chains;
11
+
12
+ // src/lib/utils.ts
13
+ var isValidChainId = (chainId) => {
14
+ if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
15
+ throw new Error(
16
+ `Unsupported chain ID: ${chainId}. Supported chains: ${SUPPORTED_CHAIN_IDS.join(", ")}`
17
+ );
18
+ }
19
+ return chainId;
20
+ };
21
+ function hexToDecimal(hex, decimals = 6) {
22
+ const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
23
+ const parsed = BigInt(normalized);
24
+ if (decimals <= 0)
25
+ return Number(parsed);
26
+ const divisor = BigInt(10 ** decimals);
27
+ const whole = parsed / divisor;
28
+ const remainder = parsed % divisor;
29
+ return Number(whole) + Number(remainder) / Number(divisor);
30
+ }
31
+ var DayFilterMapping = {
32
+ "30D": 30,
33
+ "14D": 14,
34
+ "7D": 7
35
+ };
36
+
37
+ // src/agents/zyfai/zyfai.mapper.ts
38
+ function mapDeposit(raw) {
39
+ return {
40
+ txHash: raw.txHash,
41
+ smartWallet: raw.smartWallet,
42
+ amount: raw.amount
43
+ };
44
+ }
45
+ function mapWithdraw(raw) {
46
+ return {
47
+ txHash: raw.txHash,
48
+ type: raw.type,
49
+ amount: raw.amount
50
+ };
51
+ }
52
+ var CHAIN_ID_TO_NAME = {
53
+ 8453: "BASE",
54
+ 42161: "ARBITRUM"
55
+ };
56
+ var CHAIN_NAME_TO_ID = {
57
+ BASE: 8453,
58
+ ARBITRUM: 42161
59
+ };
60
+ function mapBalances(raw, chainId) {
61
+ const portfolio = raw.portfolio;
62
+ const tokenMap = /* @__PURE__ */ new Map();
63
+ for (const p of portfolio.positions || []) {
64
+ const symbol = p.token_symbol || "USDC";
65
+ const positionChainId = (p.chain ? CHAIN_NAME_TO_ID[p.chain.toUpperCase()] : void 0) ?? chainId;
66
+ const key = `${symbol}:${positionChainId}`;
67
+ const current = tokenMap.get(key);
68
+ tokenMap.set(key, {
69
+ symbol,
70
+ chainId: positionChainId,
71
+ amount: (current?.amount ?? 0) + hexToDecimal(p.amount || "0")
72
+ });
73
+ }
74
+ for (const s of portfolio.staleBalances || []) {
75
+ const symbol = s.tokenSymbol || "USDC";
76
+ const staleChainId = s.chainId ?? chainId;
77
+ const key = `${symbol}:${staleChainId}`;
78
+ const current = tokenMap.get(key);
79
+ tokenMap.set(key, {
80
+ symbol,
81
+ chainId: staleChainId,
82
+ amount: (current?.amount ?? 0) + hexToDecimal(s.balance || "0")
83
+ });
84
+ }
85
+ let totalBalance = 0;
86
+ const tokens = [];
87
+ for (const [, entry] of tokenMap) {
88
+ totalBalance += entry.amount;
89
+ tokens.push({
90
+ chain: CHAIN_ID_TO_NAME[entry.chainId] ?? "BASE",
91
+ chainId: entry.chainId,
92
+ asset: entry.symbol,
93
+ amount: String(entry.amount)
94
+ });
95
+ }
96
+ return {
97
+ smartWallet: portfolio.smartWallet,
98
+ totalBalance: String(totalBalance),
99
+ tokens
100
+ };
101
+ }
102
+ function sumTokenValues(tokens) {
103
+ return Object.values(tokens).reduce((sum, val) => sum + val, 0);
104
+ }
105
+ function sumTokenEarnings(tokens) {
106
+ return Object.values(tokens).reduce((sum, val) => sum + Number(val), 0);
107
+ }
108
+ function mapEarnings(raw, smartWallet) {
109
+ return {
110
+ smartWallet,
111
+ lifetimeEarnings: sumTokenEarnings(raw.data.totalEarningsByToken)
112
+ };
113
+ }
114
+ function mapApyHistory(raw) {
115
+ return {
116
+ walletAddress: raw.walletAddress,
117
+ weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0
118
+ };
119
+ }
120
+ function mapHistory(raw) {
121
+ const actionMap = {
122
+ "Deposit to protocol": "Deposit",
123
+ "Top up wallet": "Top up",
124
+ "Withdraw from protocol": "Withdraw",
125
+ Rebalance: "Rebalance"
126
+ };
127
+ return {
128
+ total: raw.total,
129
+ data: raw.data.map((entry) => {
130
+ const rawLog = entry.rebalanceLog;
131
+ const positions = entry.positions ?? [];
132
+ let rebalanceLog = [];
133
+ let oldApy = null;
134
+ let newApy = null;
135
+ if (rawLog) {
136
+ const matched = positions.find(
137
+ (p) => p.protocol_name ? rawLog.newOpportunity.includes(`${p.protocol_name} (${p.pool})`) : false
138
+ );
139
+ oldApy = Number(rawLog.oldApy);
140
+ newApy = Number(rawLog.newApy);
141
+ rebalanceLog = [
142
+ {
143
+ fromProtocol: rawLog.oldOpportunity.replace(/\s*\(.*?\)/g, "").trim(),
144
+ toProtocol: rawLog.newOpportunity.replace(/\s*\(.*?\)/g, "").trim(),
145
+ tokenSymbol: matched?.token_symbol ?? "",
146
+ amount: matched ? String(hexToDecimal(matched.amount || "0x")) : "",
147
+ status: "success"
148
+ }
149
+ ];
150
+ }
151
+ return {
152
+ agent: "zyfai",
153
+ action: (entry.action ? actionMap[entry.action] : void 0) ?? entry.action,
154
+ date: entry.date || "",
155
+ newApy: String(newApy),
156
+ oldApy: String(oldApy),
157
+ transactions: [
158
+ {
159
+ txHashes: entry.transactionHash ? [entry.transactionHash] : [],
160
+ chainId: entry.chainId,
161
+ tokenSymbol: entry?.positions?.[0]?.token_symbol,
162
+ amount: String(hexToDecimal(entry?.positions?.[0]?.amount || "0x"))
163
+ }
164
+ ],
165
+ rebalanceLog
166
+ };
167
+ })
168
+ };
169
+ }
170
+ function mapAgentStatus(raw) {
171
+ return {
172
+ success: raw.success,
173
+ strategy: raw.strategy,
174
+ protocols: raw.protocols
175
+ };
176
+ }
177
+ function mapUserProfile(raw, userAddress) {
178
+ return {
179
+ address: userAddress,
180
+ smartWallet: raw.smartWallet || "",
181
+ chains: raw.chains || [],
182
+ strategy: raw.strategy,
183
+ hasActiveSessionKey: raw.hasActiveSessionKey || false,
184
+ protocols: raw.protocols || []
185
+ };
186
+ }
187
+ function mapApyByStrategy(raw) {
188
+ const first = raw.data[0];
189
+ return {
190
+ averageApy: first?.average_apy ?? 0
191
+ };
192
+ }
193
+
194
+ // src/agents/zyfai/zyfai.agent.ts
195
+ var ZyfaiAgent = class {
196
+ id = "zyfai";
197
+ supportedChainIds = [8453, 42161];
198
+ supportedAssets = [
199
+ {
200
+ chainId: 8453,
201
+ chain: "BASE",
202
+ assets: ["USDC"]
203
+ },
204
+ {
205
+ chainId: 42161,
206
+ chain: "ARBITRUM",
207
+ assets: ["USDC"]
208
+ }
209
+ ];
210
+ sdk;
211
+ connectedAddress = null;
212
+ connectedChainId = null;
213
+ constructor(apiKey) {
214
+ this.sdk = new ZyfaiSDK({ apiKey });
215
+ }
216
+ // --- Private helpers ---
217
+ getAddress() {
218
+ if (!this.connectedAddress) {
219
+ throw new Error("Wallet not connected. Call sdk.connect() first.");
220
+ }
221
+ return this.connectedAddress;
222
+ }
223
+ /** Light connect: SIWE auth only. Re-auths if chain changed. */
224
+ async connectAuth(state, chainId) {
225
+ const validChainId = isValidChainId(chainId);
226
+ if (!this.connectedAddress || this.connectedChainId !== validChainId) {
227
+ const address = await this.sdk.connectAccount(
228
+ state.provider,
229
+ validChainId
230
+ );
231
+ this.connectedAddress = address;
232
+ this.connectedChainId = validChainId;
233
+ }
234
+ }
235
+ /** Full connect: SIWE auth + Safe deploy check + session key. */
236
+ async connectFull(state, chainId) {
237
+ await this.connectAuth(state, chainId);
238
+ const validChainId = isValidChainId(chainId);
239
+ const address = this.getAddress();
240
+ const wallet = await this.sdk.getSmartWalletAddress(address, validChainId);
241
+ if (!wallet.isDeployed) {
242
+ await this.sdk.deploySafe(address, validChainId, "aggressive", true);
243
+ }
244
+ const user = await this.sdk.getUserDetails();
245
+ if (!user.hasActiveSessionKey) {
246
+ await this.sdk.createSessionKey(address, validChainId);
247
+ }
248
+ }
249
+ /** Connect + resolve smart wallet address for read operations. */
250
+ async resolveSmartWallet(state, chainId) {
251
+ await this.connectAuth(state, chainId);
252
+ const validChainId = isValidChainId(chainId);
253
+ const { address } = await this.sdk.getSmartWalletAddress(
254
+ this.getAddress(),
255
+ validChainId
256
+ );
257
+ return { smartWallet: address, chainId: validChainId };
258
+ }
259
+ // --- IAgent: Connection lifecycle ---
260
+ async disconnect() {
261
+ await this.sdk.disconnectAccount();
262
+ this.connectedAddress = null;
263
+ this.connectedChainId = null;
264
+ }
265
+ // --- IAgent: Account lifecycle ---
266
+ async activateAgent(state, chainId) {
267
+ try {
268
+ await this.connectFull(state, chainId);
269
+ } catch (error) {
270
+ await this.disconnect();
271
+ throw error;
272
+ }
273
+ }
274
+ async deposit(state, chainId, amount, depositCallback) {
275
+ try {
276
+ await this.connectFull(state, chainId);
277
+ const validChainId = isValidChainId(chainId);
278
+ if (depositCallback) {
279
+ const wallet = await this.sdk.getSmartWalletAddress(
280
+ this.getAddress(),
281
+ validChainId
282
+ );
283
+ const txHash = await depositCallback(
284
+ wallet.address,
285
+ validChainId,
286
+ amount
287
+ );
288
+ await this.sdk.logDeposit(validChainId, txHash, amount);
289
+ return { txHash, smartWallet: wallet.address, amount };
290
+ }
291
+ const raw = await this.sdk.depositFunds(
292
+ this.getAddress(),
293
+ validChainId,
294
+ amount
295
+ );
296
+ return mapDeposit(raw);
297
+ } catch (error) {
298
+ await this.disconnect();
299
+ throw error;
300
+ }
301
+ }
302
+ // --- IAgent: Fund operations ---
303
+ async withdraw(state, chainId, amount) {
304
+ await this.connectFull(state, chainId);
305
+ const validChainId = isValidChainId(chainId);
306
+ const raw = await this.sdk.withdrawFunds(
307
+ this.getAddress(),
308
+ validChainId,
309
+ amount
310
+ );
311
+ return mapWithdraw(raw);
312
+ }
313
+ // --- IAgent: Portfolio reads ---
314
+ async getBalances(state, chainId) {
315
+ await this.connectAuth(state, chainId);
316
+ const validChainId = isValidChainId(chainId);
317
+ const raw = await this.sdk.getPositions(this.getAddress(), validChainId);
318
+ return mapBalances(raw, validChainId);
319
+ }
320
+ async getEarnings(state, chainId) {
321
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
322
+ const raw = await this.sdk.calculateOnchainEarnings(smartWallet);
323
+ return mapEarnings(raw, smartWallet);
324
+ }
325
+ async getAccountApy(state, chainId, days) {
326
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
327
+ const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
328
+ return mapApyHistory(raw);
329
+ }
330
+ async getHistory(state, chainId, options) {
331
+ const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
332
+ const raw = await this.sdk.getHistory(smartWallet, validChainId, options);
333
+ return mapHistory(raw);
334
+ }
335
+ // --- IAgent: Agent control ---
336
+ async pause(state, chainId) {
337
+ await this.connectAuth(state, chainId);
338
+ const raw = await this.sdk.pauseAgent();
339
+ return mapAgentStatus(raw);
340
+ }
341
+ async resume(state, chainId) {
342
+ await this.connectAuth(state, chainId);
343
+ const raw = await this.sdk.resumeAgent();
344
+ return mapAgentStatus(raw);
345
+ }
346
+ async getUserProfile(state, chainId) {
347
+ await this.connectAuth(state, chainId);
348
+ const raw = await this.sdk.getUserDetails();
349
+ return mapUserProfile(raw, this.connectedAddress);
350
+ }
351
+ // --- IAgent: Discovery (no wallet required) ---
352
+ async getAgentApy(days) {
353
+ const raw = await this.sdk.getAPYPerStrategy(
354
+ false,
355
+ DayFilterMapping[days],
356
+ "aggressive"
357
+ );
358
+ return mapApyByStrategy(raw);
359
+ }
360
+ };
361
+
362
+ // src/agents/sail/sail.mapper.ts
363
+ function mapDeposit2(raw) {
364
+ return {
365
+ txHash: raw.txHash,
366
+ smartWallet: raw.smartWallet,
367
+ amount: raw.amount
368
+ };
369
+ }
370
+ function mapWithdraw2(raw) {
371
+ return {
372
+ txHash: raw.txHash,
373
+ type: raw.type,
374
+ amount: raw.amount
375
+ };
376
+ }
377
+ function mapPortfolioBalances(raw, smartWallet) {
378
+ let total = 0;
379
+ const tokens = [];
380
+ for (const item of raw.result) {
381
+ total += item.usd_value;
382
+ tokens.push({
383
+ chain: item.chain.toUpperCase(),
384
+ chainId: item.chain_id,
385
+ asset: item.token === "USD\u20AE0" ? "USDT" : item.token,
386
+ amount: String(item.usd_value)
387
+ });
388
+ }
389
+ return {
390
+ smartWallet,
391
+ totalBalance: String(total),
392
+ tokens
393
+ };
394
+ }
395
+ function mapEarnings2(raw, smartWallet) {
396
+ return {
397
+ smartWallet,
398
+ lifetimeEarnings: raw.result
399
+ };
400
+ }
401
+ function mapApyHistory2(raw, walletAddress) {
402
+ return {
403
+ walletAddress,
404
+ weightedApyAfterFee: raw.result
405
+ };
406
+ }
407
+ function mapSailTransaction(tx) {
408
+ switch (tx.type) {
409
+ case "deposit":
410
+ case "redeem":
411
+ return {
412
+ txHashes: tx.tx_hashes,
413
+ chainId: tx.chain_id,
414
+ tokenSymbol: tx.asset,
415
+ amount: String(tx.amount)
416
+ };
417
+ case "swap":
418
+ return {
419
+ txHashes: tx.tx_hashes,
420
+ chainId: tx.chain_id,
421
+ tokenSymbol: tx.from_asset,
422
+ amount: String(tx.amount)
423
+ };
424
+ case "bridge":
425
+ return {
426
+ txHashes: tx.tx_hashes,
427
+ chainId: Number(tx.from_chain_id),
428
+ tokenSymbol: tx.asset,
429
+ amount: String(tx.amount)
430
+ };
431
+ }
432
+ }
433
+ function buildRebalanceLogs(transactions, failedTransactions) {
434
+ const redeems = transactions.filter(
435
+ (tx) => tx.type === "redeem"
436
+ );
437
+ const deposits = transactions.filter(
438
+ (tx) => tx.type === "deposit"
439
+ );
440
+ const failedRedeems = failedTransactions.filter(
441
+ (tx) => tx.type === "redeem"
442
+ );
443
+ const failedDeposits = failedTransactions.filter(
444
+ (tx) => tx.type === "deposit"
445
+ );
446
+ const logs = [];
447
+ const matchedDeposits = /* @__PURE__ */ new Set();
448
+ const matchedRedeems = /* @__PURE__ */ new Set();
449
+ for (let r = 0; r < redeems.length; r++) {
450
+ const idx = deposits.findIndex(
451
+ (d, i) => !matchedDeposits.has(i) && d.amount === redeems[r].amount
452
+ );
453
+ if (idx !== -1) {
454
+ matchedDeposits.add(idx);
455
+ matchedRedeems.add(r);
456
+ logs.push({
457
+ fromProtocol: redeems[r].protocol_name,
458
+ toProtocol: deposits[idx].protocol_name,
459
+ tokenSymbol: redeems[r].asset,
460
+ amount: String(redeems[r].amount),
461
+ status: "success"
462
+ });
463
+ }
464
+ }
465
+ for (let i = 0; i < deposits.length; i++) {
466
+ if (matchedDeposits.has(i))
467
+ continue;
468
+ const failedRedeem = failedRedeems.find(
469
+ (fr) => fr.amount === deposits[i].amount
470
+ );
471
+ logs.push({
472
+ fromProtocol: failedRedeem ? failedRedeem.protocol_name : "Wallet",
473
+ toProtocol: deposits[i].protocol_name,
474
+ tokenSymbol: deposits[i].asset,
475
+ amount: String(deposits[i].amount),
476
+ status: failedRedeem ? "failed" : "success"
477
+ });
478
+ }
479
+ for (let i = 0; i < redeems.length; i++) {
480
+ if (matchedRedeems.has(i))
481
+ continue;
482
+ const failedDeposit = failedDeposits.find(
483
+ (fd) => fd.amount === redeems[i].amount
484
+ );
485
+ logs.push({
486
+ fromProtocol: redeems[i].protocol_name,
487
+ toProtocol: failedDeposit ? failedDeposit.protocol_name : "Wallet",
488
+ tokenSymbol: redeems[i].asset,
489
+ amount: String(redeems[i].amount),
490
+ status: failedDeposit ? "failed" : "success"
491
+ });
492
+ }
493
+ return logs;
494
+ }
495
+ function mapHistory2(raw) {
496
+ const actionMap = {
497
+ execution: "Rebalance",
498
+ deposit: "Top up",
499
+ withdraw: "Withdraw",
500
+ rewards: "Earned"
501
+ };
502
+ const filtered = raw.result.items.filter(
503
+ (i) => i.status === "success" && i.transactions.length
504
+ );
505
+ return {
506
+ total: filtered.length,
507
+ data: filtered.map((entry) => ({
508
+ agent: "sail",
509
+ action: actionMap[entry.type] ?? entry.type,
510
+ date: entry.time,
511
+ newApy: String(entry.new_apy),
512
+ oldApy: String(entry.previous_apy),
513
+ transactions: (entry.transactions ?? []).map(mapSailTransaction),
514
+ rebalanceLog: buildRebalanceLogs(
515
+ entry.transactions ?? [],
516
+ entry.failed_transactions ?? []
517
+ )
518
+ }))
519
+ };
520
+ }
521
+ function mapAgentStatus2(raw) {
522
+ return {
523
+ success: raw.success,
524
+ strategy: raw.strategy,
525
+ protocols: raw.protocols
526
+ };
527
+ }
528
+ function mapUserProfile2(raw) {
529
+ return {
530
+ address: raw.result.smart_account,
531
+ smartWallet: raw.result.smart_account,
532
+ chains: [],
533
+ hasActiveSessionKey: false,
534
+ protocols: []
535
+ };
536
+ }
537
+ function mapApyByStrategy2(raw) {
538
+ return {
539
+ averageApy: raw.result
540
+ };
541
+ }
542
+
543
+ // src/agents/sail/sail.agent.ts
544
+ var SAIL_API_BASE = "https://app.sail.money";
545
+ var PROJECT_ID = "sail";
546
+ var PAGE_ID = "home";
547
+ var SailAgent = class {
548
+ id = "sail";
549
+ supportedChainIds = [8453, 42161];
550
+ supportedAssets = [
551
+ {
552
+ chainId: 8453,
553
+ chain: "BASE",
554
+ assets: ["USDC"]
555
+ },
556
+ {
557
+ chainId: 42161,
558
+ chain: "ARBITRUM",
559
+ assets: ["USDC", "USDT"]
560
+ }
561
+ ];
562
+ apiKey;
563
+ authToken = null;
564
+ accountToken = null;
565
+ connectedAddress = null;
566
+ smartWalletAddress = null;
567
+ connectedChainId = null;
568
+ constructor(apiKey) {
569
+ this.apiKey = apiKey;
570
+ }
571
+ // --- Private helpers ---
572
+ async request(method, path, body) {
573
+ const headers = {
574
+ "Content-Type": "application/json",
575
+ "X-Business-API-Key": this.apiKey
576
+ };
577
+ if (this.authToken) {
578
+ headers["Authorization"] = `Bearer ${this.authToken}`;
579
+ }
580
+ if (this.accountToken) {
581
+ headers["X-Account-Token"] = this.accountToken;
582
+ }
583
+ const res = await fetch(`${SAIL_API_BASE}${path}`, {
584
+ method,
585
+ headers,
586
+ body: body ? JSON.stringify(body) : void 0
587
+ });
588
+ if (!res.ok) {
589
+ const text = await res.text().catch(() => "");
590
+ throw new Error(`Sail API error ${res.status}: ${text}`);
591
+ }
592
+ return res.json();
593
+ }
594
+ /** Initiate SIWE and sign with the user's wallet. */
595
+ async signSiwe(state, chainId) {
596
+ const initiate = await this.request(
597
+ "POST",
598
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/auth/initiate`,
599
+ {
600
+ method: "siwe",
601
+ address: state.walletAddress,
602
+ chainId
603
+ }
604
+ );
605
+ const signature = await state.provider.request({
606
+ method: "personal_sign",
607
+ params: [initiate.message, state.walletAddress]
608
+ });
609
+ return {
610
+ sessionId: initiate.sessionId,
611
+ message: initiate.message,
612
+ signature
613
+ };
614
+ }
615
+ /** Full connect: auth handles smart account creation via SIWE flow. */
616
+ async connectFull(state, chainId) {
617
+ if (this.connectedAddress && this.connectedChainId === chainId) {
618
+ return;
619
+ }
620
+ if (!state.walletAddress) {
621
+ throw new Error("Wallet address is required");
622
+ }
623
+ const { sessionId, signature, message } = await this.signSiwe(
624
+ state,
625
+ chainId
626
+ );
627
+ const complete = await this.request(
628
+ "POST",
629
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/auth/complete`,
630
+ {
631
+ method: "custom",
632
+ sessionId,
633
+ signature,
634
+ walletAddress: state.walletAddress
635
+ }
636
+ );
637
+ this.authToken = complete.token;
638
+ this.accountToken = complete.accountToken;
639
+ this.connectedAddress = state.walletAddress;
640
+ this.smartWalletAddress = complete.walletAddress;
641
+ this.connectedChainId = chainId;
642
+ }
643
+ async resolveSmartWallet(state, chainId) {
644
+ await this.connectFull(state, chainId);
645
+ const validChainId = isValidChainId(chainId);
646
+ if (!this.smartWalletAddress) {
647
+ throw new Error("Wallet not connected. Call sdk.connect() first.");
648
+ }
649
+ return {
650
+ smartWallet: this.smartWalletAddress,
651
+ chainId: validChainId
652
+ };
653
+ }
654
+ // --- IAgent: Connection lifecycle ---
655
+ async disconnect() {
656
+ this.authToken = null;
657
+ this.accountToken = null;
658
+ this.connectedAddress = null;
659
+ this.smartWalletAddress = null;
660
+ this.connectedChainId = null;
661
+ }
662
+ // --- IAgent: Account lifecycle ---
663
+ async activateAgent(state, chainId) {
664
+ try {
665
+ await this.connectFull(state, chainId);
666
+ } catch (error) {
667
+ await this.disconnect();
668
+ throw error;
669
+ }
670
+ }
671
+ async deposit(state, chainId, amount, depositCallback) {
672
+ if (!depositCallback) {
673
+ throw new Error(
674
+ "depositCallback is required for Sail. Provide a callback that transfers tokens and returns the transaction hash."
675
+ );
676
+ }
677
+ try {
678
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
679
+ const depositInfo = await this.getDepositInfo();
680
+ const resolvedTokenAddress = depositInfo.permittedTokens[0]?.address;
681
+ if (!resolvedTokenAddress) {
682
+ throw new Error("No permitted tokens available for deposit.");
683
+ }
684
+ await this.executePreHooks(resolvedTokenAddress, amount, chainId);
685
+ const txHash = await depositCallback(smartWallet, chainId, amount);
686
+ if (!txHash) {
687
+ throw new Error(
688
+ "depositCallback must return a transaction hash (txHash) for Sail deposits."
689
+ );
690
+ }
691
+ const postResult = await this.executePostHooks(
692
+ resolvedTokenAddress,
693
+ amount,
694
+ chainId,
695
+ txHash
696
+ );
697
+ return mapDeposit2({
698
+ txHash: postResult.transactionHash,
699
+ smartWallet,
700
+ amount
701
+ });
702
+ } catch (error) {
703
+ await this.disconnect();
704
+ throw error;
705
+ }
706
+ }
707
+ // --- Private deposit flow helpers ---
708
+ async getDepositInfo() {
709
+ return this.request(
710
+ "GET",
711
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/deposit-info`
712
+ );
713
+ }
714
+ async executePreHooks(tokenAddress, amount, chainId) {
715
+ return this.request(
716
+ "POST",
717
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/deposit/pre-hooks`,
718
+ { tokenAddress, amount, chainId }
719
+ );
720
+ }
721
+ async executePostHooks(tokenAddress, amount, chainId, txHash) {
722
+ return this.request(
723
+ "POST",
724
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/deposit/post-hooks`,
725
+ { tokenAddress, amount, chainId, txHash }
726
+ );
727
+ }
728
+ // --- Private withdraw flow helpers ---
729
+ async getWithdrawInfo() {
730
+ return this.request(
731
+ "GET",
732
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/withdraw-info`
733
+ );
734
+ }
735
+ // --- IAgent: Fund operations ---
736
+ async withdraw(state, chainId, amount) {
737
+ await this.connectFull(state, chainId);
738
+ const withdrawInfo = await this.getWithdrawInfo();
739
+ const tokenAddress = withdrawInfo.permittedTokens[0]?.address;
740
+ if (!tokenAddress) {
741
+ throw new Error("No permitted tokens available for withdrawal.");
742
+ }
743
+ const resolvedAmount = amount ?? withdrawInfo.currentBalance;
744
+ const { signature: adminWalletSignature, message: adminWalletPayload } = await this.signSiwe(state, chainId);
745
+ const payload = {
746
+ amount: String(resolvedAmount),
747
+ tokenAddress,
748
+ chainId,
749
+ adminWalletSignature,
750
+ adminWalletPayload
751
+ };
752
+ const raw = await this.request(
753
+ "POST",
754
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/withdraw`,
755
+ payload
756
+ );
757
+ return mapWithdraw2({
758
+ txHash: raw.transactionHash,
759
+ type: amount ? "partial" : "full",
760
+ amount: resolvedAmount
761
+ });
762
+ }
763
+ // --- IAgent: Portfolio reads ---
764
+ async getBalances(state, chainId) {
765
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
766
+ const raw = await this.getMetricsPortfolio(state, chainId);
767
+ return mapPortfolioBalances(raw, smartWallet);
768
+ }
769
+ async getEarnings(state, chainId) {
770
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
771
+ const raw = await this.getMetricsEarnings(state, chainId);
772
+ return mapEarnings2(raw, smartWallet);
773
+ }
774
+ async getAccountApy(state, chainId, days) {
775
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
776
+ const raw = await this.getMetricsYield(days, state, chainId);
777
+ return mapApyHistory2(raw, smartWallet);
778
+ }
779
+ async getHistory(state, chainId, options) {
780
+ const raw = await this.getMetricsHistory(state, chainId, options);
781
+ return mapHistory2(raw);
782
+ }
783
+ // -- Sail-specific: Metrics ---
784
+ async getMetricsPortfolio(state, chainId) {
785
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
786
+ return this.request(
787
+ "GET",
788
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/portfolio?${smartWallet ? `smart_account=${smartWallet}` : ""}`
789
+ );
790
+ }
791
+ async getMetricsEarnings(state, chainId) {
792
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
793
+ return this.request(
794
+ "GET",
795
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/earnings?smart_account=${smartWallet}`
796
+ );
797
+ }
798
+ async getMetricsBalance(state, chainId, currency) {
799
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
800
+ return this.request(
801
+ "GET",
802
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/balance?smart_account=${smartWallet}&currency=${currency}&limit=1000`
803
+ );
804
+ }
805
+ async getMetricsHistory(state, chainId, filters) {
806
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
807
+ const params = new URLSearchParams();
808
+ params.set("smart_account", smartWallet);
809
+ if (filters?.fromDate) {
810
+ params.set("start_date", filters.fromDate);
811
+ }
812
+ if (filters?.toDate) {
813
+ params.set("end_date", filters.toDate);
814
+ }
815
+ return this.request(
816
+ "GET",
817
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/history?${params.toString()}`
818
+ );
819
+ }
820
+ async getMetricsUser(state, chainId, currency) {
821
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
822
+ return this.request(
823
+ "GET",
824
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/user-metrics?smart_account=${smartWallet}&currency=${currency}`
825
+ );
826
+ }
827
+ async getMetricsYield(days, state, chainId) {
828
+ let walletAddress = "";
829
+ if (state && chainId) {
830
+ const { smartWallet } = await this.resolveSmartWallet(state, chainId);
831
+ walletAddress = smartWallet;
832
+ }
833
+ const dayCount = DayFilterMapping[days];
834
+ if (dayCount === void 0) {
835
+ throw new Error(
836
+ `Invalid days value: "${days}". Expected one of: "7D", "14D", "30D".`
837
+ );
838
+ }
839
+ const now = /* @__PURE__ */ new Date();
840
+ const end = now.toISOString().split("T")[0];
841
+ const start = new Date(now.getTime() - dayCount * 864e5).toISOString().split("T")[0];
842
+ return this.request(
843
+ "GET",
844
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/yield?start=${start}&end=${end}${walletAddress ? `&smart_account=${walletAddress}` : ""}`
845
+ );
846
+ }
847
+ // --- Sail-specific: Automation jobs ---
848
+ async getAutomationStatus(state, chainId) {
849
+ await this.connectFull(state, chainId);
850
+ return this.request(
851
+ "GET",
852
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/automation/status`
853
+ );
854
+ }
855
+ async startAutomation(state, chainId, graphId, prompt, options) {
856
+ await this.connectFull(state, chainId);
857
+ return this.request(
858
+ "POST",
859
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/automation/start`,
860
+ {
861
+ graphId,
862
+ prompt,
863
+ paramValues: options?.paramValues ?? {},
864
+ iterations: options?.iterations ?? 1,
865
+ branchId: options?.branchId
866
+ }
867
+ );
868
+ }
869
+ async pauseAutomation(state, chainId) {
870
+ await this.connectFull(state, chainId);
871
+ return this.request(
872
+ "POST",
873
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/automation/pause`
874
+ );
875
+ }
876
+ async resumeAutomation(state, chainId) {
877
+ await this.connectFull(state, chainId);
878
+ return this.request(
879
+ "POST",
880
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/automation/resume`
881
+ );
882
+ }
883
+ async stopAutomation(state, chainId) {
884
+ await this.connectFull(state, chainId);
885
+ return this.request(
886
+ "POST",
887
+ `/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/automation/stop`
888
+ );
889
+ }
890
+ // --- IAgent: Agent control ---
891
+ async pause(state, chainId) {
892
+ await this.connectFull(state, chainId);
893
+ await this.pauseAutomation(state, chainId);
894
+ return mapAgentStatus2({ success: true });
895
+ }
896
+ async resume(state, chainId) {
897
+ await this.connectFull(state, chainId);
898
+ await this.resumeAutomation(state, chainId);
899
+ return mapAgentStatus2({ success: true });
900
+ }
901
+ async getUserProfile(state, chainId) {
902
+ await this.connectFull(state, chainId);
903
+ const raw = await this.getMetricsUser(state, chainId, "usd");
904
+ return mapUserProfile2(raw);
905
+ }
906
+ // --- IAgent: Discovery (no wallet required) ---
907
+ async getAgentApy(days) {
908
+ const raw = await this.getMetricsYield(days);
909
+ return mapApyByStrategy2(raw);
910
+ }
911
+ };
912
+
913
+ // src/errors.ts
914
+ var AgentNotFoundError = class extends Error {
915
+ constructor(agentId, available) {
916
+ super(
917
+ `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`
918
+ );
919
+ this.name = "AgentNotFoundError";
920
+ }
921
+ };
922
+ var NotConnectedError = class extends Error {
923
+ constructor() {
924
+ super("Not connected. Call sdk.connect(provider) first.");
925
+ this.name = "NotConnectedError";
926
+ }
927
+ };
928
+ var AgentChainIncompatibleError = class extends Error {
929
+ incompatibleAgents;
930
+ connectedChainId;
931
+ constructor(incompatibleAgents, connectedChainId) {
932
+ const details = incompatibleAgents.map(
933
+ ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
934
+ ).join("; ");
935
+ super(
936
+ `Chain ${connectedChainId} is not supported by the following agents: ${details}`
937
+ );
938
+ this.name = "AgentChainIncompatibleError";
939
+ this.incompatibleAgents = incompatibleAgents;
940
+ this.connectedChainId = connectedChainId;
941
+ }
942
+ };
943
+
944
+ // src/lib/routing-api.ts
945
+ var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
946
+ async function fetchAgentKeys(apiKey) {
947
+ const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
948
+ const res = await fetch(url, {
949
+ method: "GET",
950
+ headers: {
951
+ "Content-Type": "application/json",
952
+ "x-owney-api-key": `${apiKey}`
953
+ }
954
+ });
955
+ if (!res.ok) {
956
+ const text = await res.text().catch(() => "");
957
+ throw new Error(`Routing API error ${res.status}: ${text}`);
958
+ }
959
+ const json = await res.json();
960
+ if (!json.success) {
961
+ throw new Error(`Routing API request failed: ${json.message}`);
962
+ }
963
+ return json.data;
964
+ }
965
+
966
+ // src/client.ts
967
+ var AGENT_CONSTRUCTORS = {
968
+ zyfai: ZyfaiAgent,
969
+ sail: SailAgent
970
+ };
971
+ var OwneySDK = class {
972
+ agents = /* @__PURE__ */ new Map();
973
+ activeAgents = /* @__PURE__ */ new Set();
974
+ state = null;
975
+ apiKey;
976
+ constructor(config) {
977
+ this.apiKey = config.apiKey;
978
+ }
979
+ /**
980
+ * Establish connection state for all subsequent SDK calls.
981
+ * Must be called once before any agent operation that requires a wallet.
982
+ * @param provider - EIP-1193 wallet provider
983
+ */
984
+ // TODO: replace with a proper EIP-1193 Provider type
985
+ async connect(provider) {
986
+ const accounts = await provider.request({
987
+ method: "eth_accounts"
988
+ });
989
+ const walletAddress = accounts[0];
990
+ if (!walletAddress) {
991
+ throw new Error(
992
+ "No accounts found. Ensure the wallet is unlocked and connected."
993
+ );
994
+ }
995
+ this.state = { provider, walletAddress, chainId: null };
996
+ }
997
+ /**
998
+ * Disconnect from all agents and clear connection state.
999
+ * After calling this, `connect()` must be called again before using agent methods.
1000
+ */
1001
+ async disconnect() {
1002
+ for (const agent of this.agents.values()) {
1003
+ await agent.disconnect();
1004
+ }
1005
+ this.activeAgents.clear();
1006
+ this.state = null;
1007
+ }
1008
+ /**
1009
+ * Check if the SDK has an active connection state.
1010
+ * @returns `true` if `connect()` has been called and `disconnect()` has not
1011
+ */
1012
+ isConnected() {
1013
+ return this.state !== null;
1014
+ }
1015
+ /**
1016
+ * Get the currently active chain ID, set by `activateAgent`.
1017
+ * @returns The active chain ID, or `null` if `activateAgent` has not been called
1018
+ */
1019
+ getActiveChainId() {
1020
+ return this.state?.chainId ?? null;
1021
+ }
1022
+ requireState() {
1023
+ if (!this.state)
1024
+ throw new NotConnectedError();
1025
+ return this.state;
1026
+ }
1027
+ requireChainId() {
1028
+ const chainId = this.state?.chainId ?? null;
1029
+ if (chainId === null) {
1030
+ throw new Error(
1031
+ "No active chain. Call sdk.activateAgent(chainId) first."
1032
+ );
1033
+ }
1034
+ return chainId;
1035
+ }
1036
+ getAgent(agentId) {
1037
+ const agent = this.agents.get(agentId);
1038
+ if (!agent) {
1039
+ throw new AgentNotFoundError(agentId, [...this.agents.keys()]);
1040
+ }
1041
+ return agent;
1042
+ }
1043
+ getActiveAgents() {
1044
+ const active = /* @__PURE__ */ new Map();
1045
+ for (const id of this.activeAgents) {
1046
+ const agent = this.agents.get(id);
1047
+ if (agent)
1048
+ active.set(id, agent);
1049
+ }
1050
+ return active;
1051
+ }
1052
+ // --- Account lifecycle ---
1053
+ /**
1054
+ * Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted.
1055
+ * Deploys the Safe contract and creates a session key if not already set up.
1056
+ * Saves the chainId for use by all subsequent SDK calls.
1057
+ * @param chainId - Target chain ID (e.g. 8453 for Base, 42161 for Arbitrum)
1058
+ * @param agentId - Optional. One or more agent IDs to activate. Omit to activate all agents
1059
+ * that support the given chainId (incompatible agents are silently skipped).
1060
+ * If provided, ALL specified agents must support the chainId or the call
1061
+ * throws before activating any agent.
1062
+ */
1063
+ async activateAgent(chainId, agentId) {
1064
+ const state = this.requireState();
1065
+ if (this.agents.size === 0) {
1066
+ const agentKeys = await fetchAgentKeys(this.apiKey);
1067
+ for (const { key, agent_type } of agentKeys) {
1068
+ const AgentClass = AGENT_CONSTRUCTORS[agent_type];
1069
+ if (!AgentClass)
1070
+ continue;
1071
+ const agent = new AgentClass(key);
1072
+ this.agents.set(agent_type, agent);
1073
+ }
1074
+ if (this.agents.size === 0) {
1075
+ throw new Error(
1076
+ "No supported agents returned by the routing API. Check your API key and routing configuration."
1077
+ );
1078
+ }
1079
+ }
1080
+ if (agentId !== void 0) {
1081
+ if (agentId.length === 0) {
1082
+ throw new Error(
1083
+ "agentId array must not be empty. Omit the argument to activate all compatible agents."
1084
+ );
1085
+ }
1086
+ const uniqueIds = [...new Set(agentId)];
1087
+ const agents = uniqueIds.map((id) => this.getAgent(id));
1088
+ const incompatibleAgents = agents.filter(
1089
+ (agent) => !agent.supportedChainIds.includes(chainId)
1090
+ ).map((agent) => ({
1091
+ agentId: agent.id,
1092
+ supportedChainIds: agent.supportedChainIds
1093
+ }));
1094
+ if (incompatibleAgents.length > 0) {
1095
+ throw new AgentChainIncompatibleError(incompatibleAgents, chainId);
1096
+ }
1097
+ for (const agent of agents) {
1098
+ await agent.activateAgent(state, chainId);
1099
+ }
1100
+ this.activeAgents.clear();
1101
+ for (const id of uniqueIds) {
1102
+ this.activeAgents.add(id);
1103
+ }
1104
+ state.chainId = chainId;
1105
+ return;
1106
+ }
1107
+ const compatible = [...this.agents.values()].filter(
1108
+ (agent) => agent.supportedChainIds.includes(chainId)
1109
+ );
1110
+ if (compatible.length === 0) {
1111
+ throw new Error(`No agents support chain ${chainId}.`);
1112
+ }
1113
+ for (const agent of compatible) {
1114
+ await agent.activateAgent(state, chainId);
1115
+ }
1116
+ this.activeAgents.clear();
1117
+ for (const agent of compatible) {
1118
+ this.activeAgents.add(agent.id);
1119
+ }
1120
+ state.chainId = chainId;
1121
+ }
1122
+ /**
1123
+ * Deposit funds into a specific agent, or split equally across all agents if agentId is omitted.
1124
+ * Validates that the asset is supported by the target agent(s) on the active chain.
1125
+ * @param options - Deposit parameters
1126
+ * @param options.amount - Amount to deposit in smallest unit (e.g. "100000000" for 100 USDC)
1127
+ * @param options.asset - Asset symbol to deposit (e.g. "USDC")
1128
+ * @param options.depositCallback - Callback that performs the token transfer and returns a tx hash.
1129
+ * When agentId is omitted, this callback is invoked once per eligible agent with that agent's
1130
+ * split amount and smart wallet address — expect multiple wallet prompts.
1131
+ * @param options.agentId - Optional. Target agent. Omit to split equally across all agents.
1132
+ * @returns {OwneyDepositResult} for a single agent, or {OwneyMultiDepositResult} with per-agent results
1133
+ */
1134
+ async deposit(options) {
1135
+ const { amount, asset, depositCallback, agentId } = options;
1136
+ const state = this.requireState();
1137
+ const chainId = this.requireChainId();
1138
+ if (agentId) {
1139
+ const agent = this.getAgent(agentId);
1140
+ this.validateAssetSupport(agent, chainId, asset);
1141
+ return agent.deposit(state, chainId, amount, depositCallback);
1142
+ }
1143
+ const eligibleAgents = this.getEligibleAgents(chainId, asset);
1144
+ const totalAmount = BigInt(amount);
1145
+ if (totalAmount < BigInt(eligibleAgents.length)) {
1146
+ throw new Error(
1147
+ `Amount "${amount}" is too small to split across ${eligibleAgents.length} agents.`
1148
+ );
1149
+ }
1150
+ const perAgent = totalAmount / BigInt(eligibleAgents.length);
1151
+ const remainder = totalAmount % BigInt(eligibleAgents.length);
1152
+ const agentResults = {};
1153
+ for (let i = 0; i < eligibleAgents.length; i++) {
1154
+ const agent = eligibleAgents[i];
1155
+ const agentAmount = i === eligibleAgents.length - 1 ? String(perAgent + remainder) : String(perAgent);
1156
+ agentResults[agent.id] = await agent.deposit(
1157
+ state,
1158
+ chainId,
1159
+ agentAmount,
1160
+ depositCallback
1161
+ );
1162
+ }
1163
+ return { agentResults };
1164
+ }
1165
+ validateAssetSupport(agent, chainId, asset) {
1166
+ const chainAssets = agent.supportedAssets.find(
1167
+ (sa) => sa.chainId === chainId
1168
+ );
1169
+ if (!chainAssets || !chainAssets.assets.includes(asset)) {
1170
+ throw new Error(
1171
+ `Agent "${agent.id}" does not support asset "${asset}" on chain ${chainId}.`
1172
+ );
1173
+ }
1174
+ }
1175
+ getEligibleAgents(chainId, asset) {
1176
+ const eligible = [...this.agents.values()].filter((agent) => {
1177
+ const chainAssets = agent.supportedAssets.find(
1178
+ (sa) => sa.chainId === chainId
1179
+ );
1180
+ return chainAssets && chainAssets.assets.includes(asset);
1181
+ });
1182
+ if (eligible.length === 0) {
1183
+ throw new Error(
1184
+ `No agents support asset "${asset}" on chain ${chainId}.`
1185
+ );
1186
+ }
1187
+ return eligible;
1188
+ }
1189
+ // --- Fund operations ---
1190
+ /**
1191
+ * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
1192
+ * Validates that the asset is supported by the target agent(s) on the active chain.
1193
+ * @param options - Withdraw parameters
1194
+ * @param options.asset - Asset symbol (e.g. "USDC")
1195
+ * @param options.amount - Optional. Amount to withdraw. Omit for full withdrawal.
1196
+ * @param options.agentId - Optional. Target agent. Omit to withdraw from all agents.
1197
+ * @returns {AgentWithdrawResult} for a single agent, or {OwneyWithdrawResult} with per-agent results
1198
+ */
1199
+ async withdraw(options) {
1200
+ const { asset, amount, agentId } = options;
1201
+ const state = this.requireState();
1202
+ const chainId = this.requireChainId();
1203
+ if (agentId) {
1204
+ const agent = this.getAgent(agentId);
1205
+ this.validateAssetSupport(agent, chainId, asset);
1206
+ return agent.withdraw(state, chainId, amount);
1207
+ }
1208
+ const eligibleAgents = this.getEligibleAgents(chainId, asset);
1209
+ const results = {};
1210
+ for (const agent of eligibleAgents) {
1211
+ results[agent.id] = await agent.withdraw(state, chainId, amount);
1212
+ }
1213
+ return {
1214
+ agentResult: results
1215
+ };
1216
+ }
1217
+ // --- Portfolio reads ---
1218
+ /**
1219
+ * Get the user's balances for a specific agent, or aggregated across all agents.
1220
+ * @param agentId - Optional. Agent to query. Omit for aggregated balances.
1221
+ * @returns {AgentBalance} for a single agent, or {OwneyBalances} with totalBalance and per-agent breakdown
1222
+ */
1223
+ async getBalances(agentId) {
1224
+ const state = this.requireState();
1225
+ const chainId = this.requireChainId();
1226
+ if (agentId) {
1227
+ return this.getAgent(agentId).getBalances(state, chainId);
1228
+ }
1229
+ let totalBalance = 0;
1230
+ const results = {};
1231
+ for (const [id, agent] of this.getActiveAgents()) {
1232
+ results[id] = await agent.getBalances(state, chainId);
1233
+ totalBalance = totalBalance + Number(results[id].totalBalance);
1234
+ }
1235
+ return {
1236
+ totalBalance: String(totalBalance),
1237
+ agentBalances: results
1238
+ };
1239
+ }
1240
+ /**
1241
+ * Get the user's on-chain earnings for a specific agent, or aggregated across all agents.
1242
+ * @param agentId - Optional. Agent to query. Omit for aggregated earnings.
1243
+ * @returns {AgentEarnings} for a single agent, or {OwneyEarnings} with totalEarnings and per-agent breakdown
1244
+ */
1245
+ async getEarnings(agentId) {
1246
+ const state = this.requireState();
1247
+ const chainId = this.requireChainId();
1248
+ if (agentId) {
1249
+ return this.getAgent(agentId).getEarnings(state, chainId);
1250
+ }
1251
+ let totalEarnings = 0;
1252
+ const results = {};
1253
+ for (const [id, agent] of this.getActiveAgents()) {
1254
+ results[id] = await agent.getEarnings(state, chainId);
1255
+ totalEarnings = totalEarnings + Number(results[id].lifetimeEarnings);
1256
+ }
1257
+ return {
1258
+ totalEarnings: String(totalEarnings),
1259
+ agentEarnings: results
1260
+ };
1261
+ }
1262
+ /**
1263
+ * Get the weighted APY for the user's account over a time period.
1264
+ * When querying all agents, the total APY is a balance-weighted average.
1265
+ * @param options - Contains agentId (optional) and days ("7D", "14D", or "30D")
1266
+ * @param options.agentId - Optional. Agent to query. Omit for balance-weighted total APY.
1267
+ * @param options.days - Lookback period: "7D", "14D", or "30D"
1268
+ * @returns {AccountAgentApy} for a single agent, or {OwneyAccountApy} with totalApy and per-agent breakdown
1269
+ */
1270
+ async getAccountApy({
1271
+ agentId,
1272
+ days
1273
+ }) {
1274
+ const state = this.requireState();
1275
+ const chainId = this.requireChainId();
1276
+ if (agentId) {
1277
+ return this.getAgent(agentId).getAccountApy(state, chainId, days);
1278
+ }
1279
+ const activeAgents = this.getActiveAgents();
1280
+ const results = {};
1281
+ for (const [id, agent] of activeAgents) {
1282
+ results[id] = await agent.getAccountApy(state, chainId, days);
1283
+ }
1284
+ const balances = {};
1285
+ let totalBalance = 0;
1286
+ for (const [id, agent] of activeAgents) {
1287
+ const b = await agent.getBalances(state, chainId);
1288
+ balances[id] = Number(b.totalBalance);
1289
+ totalBalance += balances[id];
1290
+ }
1291
+ let totalApy = 0;
1292
+ if (totalBalance > 0) {
1293
+ for (const id of Object.keys(results)) {
1294
+ const weight = balances[id] / totalBalance;
1295
+ totalApy += Number(results[id].weightedApyAfterFee ?? 0) * weight;
1296
+ }
1297
+ }
1298
+ return {
1299
+ totalApy: String(totalApy),
1300
+ agentApy: results
1301
+ };
1302
+ }
1303
+ /**
1304
+ * Get transaction history for a specific agent, or all agents.
1305
+ * @param params - Optional. Contains agentId and filters.
1306
+ * @param params.agentId - Optional. Agent to query. Omit for all agents.
1307
+ * @param params.filters - Optional. Pagination and date filters (fromDate, toDate)
1308
+ * @returns {OwneyAgentHistory} with per-agent history
1309
+ */
1310
+ async getHistory(params) {
1311
+ const state = this.requireState();
1312
+ const chainId = this.requireChainId();
1313
+ const { agentId, filters } = params ?? {};
1314
+ if (agentId) {
1315
+ return this.getAgent(agentId).getHistory(state, chainId, filters);
1316
+ }
1317
+ let results = [];
1318
+ for (const [, agent] of this.getActiveAgents()) {
1319
+ const { data } = await agent.getHistory(state, chainId, filters);
1320
+ results = [...results, ...data];
1321
+ }
1322
+ results.sort(
1323
+ (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
1324
+ );
1325
+ return {
1326
+ total: results.length,
1327
+ data: results
1328
+ };
1329
+ }
1330
+ // --- Agent control ---
1331
+ /**
1332
+ * Pause an agent's automated operations. The agent will stop rebalancing until resumed.
1333
+ * @param agentId - The agent to pause (e.g. "zyfai")
1334
+ * @returns OwneyAgentStatus with success flag
1335
+ */
1336
+ async pauseAgent(agentId) {
1337
+ const state = this.requireState();
1338
+ const chainId = this.requireChainId();
1339
+ return this.getAgent(agentId).pause(state, chainId);
1340
+ }
1341
+ /**
1342
+ * Resume an agent's automated operations.
1343
+ * @param agentId - The agent to resume (e.g. "zyfai")
1344
+ * @returns OwneyAgentStatus with success flag
1345
+ */
1346
+ async resumeAgent(agentId) {
1347
+ const state = this.requireState();
1348
+ const chainId = this.requireChainId();
1349
+ return this.getAgent(agentId).resume(state, chainId);
1350
+ }
1351
+ /**
1352
+ * Get the user's profile for a specific agent, or all agents.
1353
+ * @param agentId - Optional. Agent to query. Omit for all agents.
1354
+ * @returns {AgentUserProfile} for a single agent, or {OwneyUserProfile} with per-agent profiles
1355
+ */
1356
+ async getUserProfile(agentId) {
1357
+ const state = this.requireState();
1358
+ const chainId = this.requireChainId();
1359
+ if (agentId) {
1360
+ return this.getAgent(agentId).getUserProfile(state, chainId);
1361
+ }
1362
+ const results = {};
1363
+ for (const [id, agent] of this.getActiveAgents()) {
1364
+ results[id] = await agent.getUserProfile(state, chainId);
1365
+ }
1366
+ return {
1367
+ agentUserProfile: results
1368
+ };
1369
+ }
1370
+ // --- Discovery (no wallet required) ---
1371
+ /**
1372
+ * Get the agent's average APY performance over a time period. Does not require a wallet connection.
1373
+ * @param options - Contains agentId (optional) and days ("7D", "14D", or "30D")
1374
+ * @param options.agentId - Optional. Agent to query. Omit for all agents.
1375
+ * @param options.days - Lookback period: "7D", "14D", or "30D"
1376
+ * @returns {AgentApy} for a single agent, or {OwneyAgentApy} with per-agent APY
1377
+ */
1378
+ async getAgentApy({
1379
+ agentId,
1380
+ days
1381
+ }) {
1382
+ if (agentId) {
1383
+ return this.getAgent(agentId).getAgentApy(days);
1384
+ }
1385
+ const results = {};
1386
+ for (const [id, agent] of this.agents) {
1387
+ results[id] = await agent.getAgentApy(days);
1388
+ }
1389
+ return {
1390
+ agentApy: results
1391
+ };
1392
+ }
1393
+ /**
1394
+ * Get the current fund allocation percentages across agents.
1395
+ * @returns Object with agent names as keys and allocation percentages as values
1396
+ */
1397
+ async getAgentAllocation() {
1398
+ const state = this.requireState();
1399
+ const chainId = this.requireChainId();
1400
+ const activeAgents = this.getActiveAgents();
1401
+ const balances = {};
1402
+ let totalBalance = 0;
1403
+ for (const [id, agent] of activeAgents) {
1404
+ const b = await agent.getBalances(state, chainId);
1405
+ balances[id] = Number(b.totalBalance);
1406
+ totalBalance += balances[id];
1407
+ }
1408
+ const allocation = {};
1409
+ if (totalBalance === 0) {
1410
+ for (const id of activeAgents.keys()) {
1411
+ allocation[id] = 0;
1412
+ }
1413
+ } else {
1414
+ for (const id of activeAgents.keys()) {
1415
+ allocation[id] = balances[id] > 0 ? Math.max(1, Math.floor(balances[id] / totalBalance * 100)) : 0;
1416
+ }
1417
+ const remainder = 100 - Object.values(allocation).reduce((a, b) => a + b, 0);
1418
+ if (remainder > 0) {
1419
+ const largestId = [...activeAgents.keys()].reduce(
1420
+ (a, b) => balances[a] >= balances[b] ? a : b
1421
+ );
1422
+ allocation[largestId] += remainder;
1423
+ }
1424
+ }
1425
+ return {
1426
+ agentAllocation: allocation
1427
+ };
1428
+ }
1429
+ };
1430
+ export {
1431
+ AgentChainIncompatibleError,
1432
+ AgentNotFoundError,
1433
+ NotConnectedError,
1434
+ OwneySDK
1435
+ };