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