@owney/sdk 0.2.5 → 0.2.6
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/README.md +33 -1
- package/dist/index.cjs +433 -89
- package/dist/index.d.cts +36 -3
- package/dist/index.d.ts +36 -3
- package/dist/index.js +433 -89
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,6 +8,23 @@ var P_SUPPORTED_CHAINS = {
|
|
|
8
8
|
};
|
|
9
9
|
var SUPPORTED_CHAIN_IDS = P_SUPPORTED_CHAINS.chainIds;
|
|
10
10
|
var SUPPORTED_CHAINS = P_SUPPORTED_CHAINS.chains;
|
|
11
|
+
var SupportedAssets = [
|
|
12
|
+
{
|
|
13
|
+
address: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`,
|
|
14
|
+
symbol: "USDC",
|
|
15
|
+
chainId: 8453
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
address: `0xaf88d065e77c8cC2239327C5EDb3A432268e5831`,
|
|
19
|
+
symbol: "USDC",
|
|
20
|
+
chainId: 42161
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
address: `0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9`,
|
|
24
|
+
symbol: "USDT",
|
|
25
|
+
chainId: 42161
|
|
26
|
+
}
|
|
27
|
+
];
|
|
11
28
|
|
|
12
29
|
// src/lib/utils.ts
|
|
13
30
|
var isValidChainId = (chainId) => {
|
|
@@ -185,13 +202,41 @@ function mapUserProfile(raw, userAddress) {
|
|
|
185
202
|
};
|
|
186
203
|
}
|
|
187
204
|
function mapApyByStrategy(raw) {
|
|
188
|
-
const
|
|
205
|
+
const apyPerAsset = {};
|
|
206
|
+
let apySum = 0;
|
|
207
|
+
let apyCount = 0;
|
|
208
|
+
for (const entry of raw.data) {
|
|
209
|
+
const supported = SupportedAssets.find(
|
|
210
|
+
(asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
|
|
211
|
+
);
|
|
212
|
+
if (!supported)
|
|
213
|
+
continue;
|
|
214
|
+
const chainKey = supported.chainId;
|
|
215
|
+
const symbolKey = supported.symbol;
|
|
216
|
+
const bucket = apyPerAsset[chainKey] ?? {};
|
|
217
|
+
bucket[symbolKey] = entry.average_apy;
|
|
218
|
+
apyPerAsset[chainKey] = bucket;
|
|
219
|
+
apySum += entry.average_apy;
|
|
220
|
+
apyCount += 1;
|
|
221
|
+
}
|
|
222
|
+
const averageApy = apyCount > 0 ? apySum / apyCount : 0;
|
|
223
|
+
const hasDetails = Object.keys(apyPerAsset).length > 0;
|
|
189
224
|
return {
|
|
190
|
-
averageApy
|
|
225
|
+
averageApy,
|
|
226
|
+
detailedApys: hasDetails ? { apyPerAsset } : void 0
|
|
191
227
|
};
|
|
192
228
|
}
|
|
193
229
|
|
|
194
230
|
// src/agents/zyfai/zyfai.agent.ts
|
|
231
|
+
var ZYFAI_TIMING_PREFIX = "[AgentTiming][zyfai]";
|
|
232
|
+
function logTiming(label, startedAt, meta) {
|
|
233
|
+
const elapsedMs = Date.now() - startedAt;
|
|
234
|
+
if (meta) {
|
|
235
|
+
console.log(`${ZYFAI_TIMING_PREFIX} ${label} ${elapsedMs}ms`, meta);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
console.log(`${ZYFAI_TIMING_PREFIX} ${label} ${elapsedMs}ms`);
|
|
239
|
+
}
|
|
195
240
|
var ZyfaiAgent = class {
|
|
196
241
|
id = "zyfai";
|
|
197
242
|
supportedChainIds = [8453, 42161];
|
|
@@ -210,6 +255,8 @@ var ZyfaiAgent = class {
|
|
|
210
255
|
sdk;
|
|
211
256
|
connectedAddress = null;
|
|
212
257
|
connectedChainId = null;
|
|
258
|
+
smartWalletCache = /* @__PURE__ */ new Map();
|
|
259
|
+
connectAuthPromise = null;
|
|
213
260
|
constructor(apiKey) {
|
|
214
261
|
this.sdk = new ZyfaiSDK({ apiKey });
|
|
215
262
|
}
|
|
@@ -222,50 +269,105 @@ var ZyfaiAgent = class {
|
|
|
222
269
|
}
|
|
223
270
|
/** Light connect: SIWE auth only. Re-auths if chain changed. */
|
|
224
271
|
async connectAuth(state, chainId) {
|
|
272
|
+
const startedAt = Date.now();
|
|
225
273
|
const validChainId = isValidChainId(chainId);
|
|
226
|
-
if (
|
|
274
|
+
if (this.connectedAddress && this.connectedChainId === validChainId) {
|
|
275
|
+
logTiming("connectAuth cache-hit", startedAt, { chainId: validChainId });
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (this.connectAuthPromise) {
|
|
279
|
+
await this.connectAuthPromise;
|
|
280
|
+
logTiming("connectAuth awaited-inflight", startedAt, {
|
|
281
|
+
chainId: validChainId
|
|
282
|
+
});
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
this.connectAuthPromise = (async () => {
|
|
227
286
|
const address = await this.sdk.connectAccount(
|
|
228
287
|
state.provider,
|
|
229
288
|
validChainId
|
|
230
289
|
);
|
|
231
290
|
this.connectedAddress = address;
|
|
232
291
|
this.connectedChainId = validChainId;
|
|
292
|
+
})();
|
|
293
|
+
try {
|
|
294
|
+
await this.connectAuthPromise;
|
|
295
|
+
logTiming("connectAuth success", startedAt, { chainId: validChainId });
|
|
296
|
+
} finally {
|
|
297
|
+
this.connectAuthPromise = null;
|
|
233
298
|
}
|
|
234
299
|
}
|
|
235
300
|
/** Full connect: SIWE auth + Safe deploy check + session key. */
|
|
236
301
|
async connectFull(state, chainId) {
|
|
302
|
+
const startedAt = Date.now();
|
|
237
303
|
await this.connectAuth(state, chainId);
|
|
238
304
|
const validChainId = isValidChainId(chainId);
|
|
239
305
|
const address = this.getAddress();
|
|
306
|
+
const walletLookupStart = Date.now();
|
|
240
307
|
const wallet = await this.sdk.getSmartWalletAddress(address, validChainId);
|
|
308
|
+
logTiming("connectFull getSmartWalletAddress", walletLookupStart, {
|
|
309
|
+
chainId: validChainId
|
|
310
|
+
});
|
|
311
|
+
this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
|
|
241
312
|
if (!wallet.isDeployed) {
|
|
313
|
+
const deployStart = Date.now();
|
|
242
314
|
await this.sdk.deploySafe(address, validChainId, "aggressive", true);
|
|
315
|
+
logTiming("connectFull deploySafe", deployStart, {
|
|
316
|
+
chainId: validChainId
|
|
317
|
+
});
|
|
243
318
|
}
|
|
319
|
+
const userDetailsStart = Date.now();
|
|
244
320
|
const user = await this.sdk.getUserDetails();
|
|
321
|
+
logTiming("connectFull getUserDetails", userDetailsStart, {
|
|
322
|
+
chainId: validChainId
|
|
323
|
+
});
|
|
245
324
|
if (!user.hasActiveSessionKey) {
|
|
325
|
+
const sessionKeyStart = Date.now();
|
|
246
326
|
await this.sdk.createSessionKey(address, validChainId);
|
|
327
|
+
logTiming("connectFull createSessionKey", sessionKeyStart, {
|
|
328
|
+
chainId: validChainId
|
|
329
|
+
});
|
|
247
330
|
}
|
|
331
|
+
logTiming("connectFull success", startedAt, { chainId: validChainId });
|
|
248
332
|
}
|
|
249
333
|
/** Connect + resolve smart wallet address for read operations. */
|
|
250
334
|
async resolveSmartWallet(state, chainId) {
|
|
335
|
+
const startedAt = Date.now();
|
|
251
336
|
await this.connectAuth(state, chainId);
|
|
252
337
|
const validChainId = isValidChainId(chainId);
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
)
|
|
257
|
-
|
|
338
|
+
const ownerAddress = this.getAddress();
|
|
339
|
+
const cacheKey = `${ownerAddress}_${validChainId}`;
|
|
340
|
+
let smartWallet = this.smartWalletCache.get(cacheKey);
|
|
341
|
+
if (!smartWallet) {
|
|
342
|
+
const lookupStart = Date.now();
|
|
343
|
+
const { address } = await this.sdk.getSmartWalletAddress(
|
|
344
|
+
ownerAddress,
|
|
345
|
+
validChainId
|
|
346
|
+
);
|
|
347
|
+
logTiming("resolveSmartWallet remote-lookup", lookupStart, {
|
|
348
|
+
chainId: validChainId
|
|
349
|
+
});
|
|
350
|
+
smartWallet = address;
|
|
351
|
+
this.smartWalletCache.set(cacheKey, smartWallet);
|
|
352
|
+
} else {
|
|
353
|
+
logTiming("resolveSmartWallet cache-hit", startedAt, {
|
|
354
|
+
chainId: validChainId
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
logTiming("resolveSmartWallet ready", startedAt, { chainId: validChainId });
|
|
358
|
+
return { smartWallet, chainId: validChainId };
|
|
258
359
|
}
|
|
259
360
|
// --- IAgent: Connection lifecycle ---
|
|
260
361
|
async disconnect() {
|
|
261
362
|
await this.sdk.disconnectAccount();
|
|
262
363
|
this.connectedAddress = null;
|
|
263
364
|
this.connectedChainId = null;
|
|
365
|
+
this.smartWalletCache.clear();
|
|
264
366
|
}
|
|
265
367
|
// --- IAgent: Account lifecycle ---
|
|
266
368
|
async activateAgent(state, chainId) {
|
|
267
369
|
try {
|
|
268
|
-
await this.
|
|
370
|
+
await this.connectAuth(state, chainId);
|
|
269
371
|
} catch (error) {
|
|
270
372
|
await this.disconnect();
|
|
271
373
|
throw error;
|
|
@@ -312,9 +414,15 @@ var ZyfaiAgent = class {
|
|
|
312
414
|
}
|
|
313
415
|
// --- IAgent: Portfolio reads ---
|
|
314
416
|
async getBalances(state, chainId) {
|
|
417
|
+
const startedAt = Date.now();
|
|
315
418
|
await this.connectAuth(state, chainId);
|
|
316
419
|
const validChainId = isValidChainId(chainId);
|
|
420
|
+
const positionsStart = Date.now();
|
|
317
421
|
const raw = await this.sdk.getPositions(this.getAddress(), validChainId);
|
|
422
|
+
logTiming("getBalances getPositions", positionsStart, {
|
|
423
|
+
chainId: validChainId
|
|
424
|
+
});
|
|
425
|
+
logTiming("getBalances success", startedAt, { chainId: validChainId });
|
|
318
426
|
return mapBalances(raw, validChainId);
|
|
319
427
|
}
|
|
320
428
|
async getEarnings(state, chainId) {
|
|
@@ -349,11 +457,13 @@ var ZyfaiAgent = class {
|
|
|
349
457
|
return mapUserProfile(raw, this.connectedAddress);
|
|
350
458
|
}
|
|
351
459
|
// --- IAgent: Discovery (no wallet required) ---
|
|
352
|
-
async getAgentApy(days) {
|
|
460
|
+
async getAgentApy(days, options) {
|
|
353
461
|
const raw = await this.sdk.getAPYPerStrategy(
|
|
354
462
|
false,
|
|
355
463
|
DayFilterMapping[days],
|
|
356
|
-
"aggressive"
|
|
464
|
+
"aggressive",
|
|
465
|
+
options?.chainId,
|
|
466
|
+
options?.tokenSymbol
|
|
357
467
|
);
|
|
358
468
|
return mapApyByStrategy(raw);
|
|
359
469
|
}
|
|
@@ -399,9 +509,11 @@ function mapEarnings2(raw, smartWallet) {
|
|
|
399
509
|
};
|
|
400
510
|
}
|
|
401
511
|
function mapApyHistory2(raw, walletAddress) {
|
|
512
|
+
const apyPerAsset = remapApyPerAssetToSymbols(raw.result.apy_per_asset);
|
|
402
513
|
return {
|
|
403
514
|
walletAddress,
|
|
404
|
-
weightedApyAfterFee: raw.result
|
|
515
|
+
weightedApyAfterFee: raw.result.apy,
|
|
516
|
+
weightedApyAfterFeeDetails: apyPerAsset ? { apyPerAsset } : void 0
|
|
405
517
|
};
|
|
406
518
|
}
|
|
407
519
|
function mapSailTransaction(tx) {
|
|
@@ -535,15 +647,45 @@ function mapUserProfile2(raw) {
|
|
|
535
647
|
};
|
|
536
648
|
}
|
|
537
649
|
function mapApyByStrategy2(raw) {
|
|
650
|
+
const apyPerAsset = remapApyPerAssetToSymbols(raw.result.apy_per_asset);
|
|
538
651
|
return {
|
|
539
|
-
averageApy: raw.result
|
|
652
|
+
averageApy: raw.result.apy,
|
|
653
|
+
detailedApys: apyPerAsset ? { apyPerAsset } : void 0
|
|
540
654
|
};
|
|
541
655
|
}
|
|
656
|
+
function remapApyPerAssetToSymbols(raw) {
|
|
657
|
+
if (!raw)
|
|
658
|
+
return void 0;
|
|
659
|
+
const remapped = {};
|
|
660
|
+
for (const asset of SupportedAssets) {
|
|
661
|
+
const chainKey = asset.chainId;
|
|
662
|
+
const apyByAddress = raw[String(chainKey)];
|
|
663
|
+
if (!apyByAddress)
|
|
664
|
+
continue;
|
|
665
|
+
const apy = apyByAddress[asset.address] ?? apyByAddress[asset.address.toLowerCase()];
|
|
666
|
+
if (apy === void 0)
|
|
667
|
+
continue;
|
|
668
|
+
const bucket = remapped[chainKey] ?? {};
|
|
669
|
+
bucket[asset.symbol] = apy;
|
|
670
|
+
remapped[chainKey] = bucket;
|
|
671
|
+
}
|
|
672
|
+
return Object.keys(remapped).length > 0 ? remapped : void 0;
|
|
673
|
+
}
|
|
542
674
|
|
|
543
675
|
// src/agents/sail/sail.agent.ts
|
|
544
676
|
var SAIL_API_BASE = "https://app.sail.money";
|
|
545
677
|
var PROJECT_ID = "sail";
|
|
546
678
|
var PAGE_ID = "home";
|
|
679
|
+
var SAIL_TIMING_PREFIX = "[AgentTiming][sail]";
|
|
680
|
+
var SAIL_PORTFOLIO_TIMEOUT_MS = 8e3;
|
|
681
|
+
function logTiming2(label, startedAt, meta) {
|
|
682
|
+
const elapsedMs = Date.now() - startedAt;
|
|
683
|
+
if (meta) {
|
|
684
|
+
console.log(`${SAIL_TIMING_PREFIX} ${label} ${elapsedMs}ms`, meta);
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
console.log(`${SAIL_TIMING_PREFIX} ${label} ${elapsedMs}ms`);
|
|
688
|
+
}
|
|
547
689
|
var SailAgent = class {
|
|
548
690
|
id = "sail";
|
|
549
691
|
supportedChainIds = [8453, 42161];
|
|
@@ -565,11 +707,12 @@ var SailAgent = class {
|
|
|
565
707
|
connectedAddress = null;
|
|
566
708
|
smartWalletAddress = null;
|
|
567
709
|
connectedChainId = null;
|
|
710
|
+
connectPromise = null;
|
|
568
711
|
constructor(apiKey) {
|
|
569
712
|
this.apiKey = apiKey;
|
|
570
713
|
}
|
|
571
714
|
// --- Private helpers ---
|
|
572
|
-
async request(method, path, body) {
|
|
715
|
+
async request(method, path, body, timeoutMs) {
|
|
573
716
|
const headers = {
|
|
574
717
|
"Content-Type": "application/json",
|
|
575
718
|
"X-Business-API-Key": this.apiKey
|
|
@@ -580,11 +723,25 @@ var SailAgent = class {
|
|
|
580
723
|
if (this.accountToken) {
|
|
581
724
|
headers["X-Account-Token"] = this.accountToken;
|
|
582
725
|
}
|
|
583
|
-
const
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
726
|
+
const controller = new AbortController();
|
|
727
|
+
const timeoutId = typeof timeoutMs === "number" && timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
|
|
728
|
+
let res;
|
|
729
|
+
try {
|
|
730
|
+
res = await fetch(`${SAIL_API_BASE}${path}`, {
|
|
731
|
+
method,
|
|
732
|
+
headers,
|
|
733
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
734
|
+
signal: controller.signal
|
|
735
|
+
});
|
|
736
|
+
} catch (error) {
|
|
737
|
+
if (error instanceof Error && error.name === "AbortError" && timeoutMs) {
|
|
738
|
+
throw new Error(`Sail API timeout ${timeoutMs}ms: ${method} ${path}`);
|
|
739
|
+
}
|
|
740
|
+
throw error;
|
|
741
|
+
} finally {
|
|
742
|
+
if (timeoutId)
|
|
743
|
+
clearTimeout(timeoutId);
|
|
744
|
+
}
|
|
588
745
|
if (!res.ok) {
|
|
589
746
|
const text = await res.text().catch(() => "");
|
|
590
747
|
throw new Error(`Sail API error ${res.status}: ${text}`);
|
|
@@ -593,19 +750,22 @@ var SailAgent = class {
|
|
|
593
750
|
}
|
|
594
751
|
/** Initiate SIWE and sign with the user's wallet. */
|
|
595
752
|
async signSiwe(state, chainId) {
|
|
753
|
+
const startedAt = Date.now();
|
|
596
754
|
const initiate = await this.request(
|
|
597
755
|
"POST",
|
|
598
756
|
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/auth/initiate`,
|
|
599
757
|
{
|
|
600
758
|
method: "siwe",
|
|
601
759
|
address: state.walletAddress,
|
|
602
|
-
chainId
|
|
760
|
+
chainId,
|
|
761
|
+
identityMode: "byWallet"
|
|
603
762
|
}
|
|
604
763
|
);
|
|
605
764
|
const signature = await state.provider.request({
|
|
606
765
|
method: "personal_sign",
|
|
607
766
|
params: [initiate.message, state.walletAddress]
|
|
608
767
|
});
|
|
768
|
+
logTiming2("signSiwe success", startedAt, { chainId });
|
|
609
769
|
return {
|
|
610
770
|
sessionId: initiate.sessionId,
|
|
611
771
|
message: initiate.message,
|
|
@@ -614,38 +774,56 @@ var SailAgent = class {
|
|
|
614
774
|
}
|
|
615
775
|
/** Full connect: auth handles smart account creation via SIWE flow. */
|
|
616
776
|
async connectFull(state, chainId) {
|
|
777
|
+
const startedAt = Date.now();
|
|
617
778
|
if (this.connectedAddress && this.connectedChainId === chainId) {
|
|
779
|
+
logTiming2("connectFull cache-hit", startedAt, { chainId });
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
if (this.connectPromise) {
|
|
783
|
+
await this.connectPromise;
|
|
784
|
+
logTiming2("connectFull awaited-inflight", startedAt, { chainId });
|
|
618
785
|
return;
|
|
619
786
|
}
|
|
620
787
|
if (!state.walletAddress) {
|
|
621
788
|
throw new Error("Wallet address is required");
|
|
622
789
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
790
|
+
this.connectPromise = (async () => {
|
|
791
|
+
const { sessionId, signature, message } = await this.signSiwe(
|
|
792
|
+
state,
|
|
793
|
+
chainId
|
|
794
|
+
);
|
|
795
|
+
const complete = await this.request(
|
|
796
|
+
"POST",
|
|
797
|
+
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/auth/complete`,
|
|
798
|
+
{
|
|
799
|
+
method: "custom",
|
|
800
|
+
sessionId,
|
|
801
|
+
signature,
|
|
802
|
+
walletAddress: state.walletAddress,
|
|
803
|
+
identityMode: "byWallet"
|
|
804
|
+
}
|
|
805
|
+
);
|
|
806
|
+
this.authToken = complete.token;
|
|
807
|
+
this.accountToken = complete.accountToken;
|
|
808
|
+
this.connectedAddress = state.walletAddress;
|
|
809
|
+
this.smartWalletAddress = complete.walletAddress;
|
|
810
|
+
this.connectedChainId = chainId;
|
|
811
|
+
})();
|
|
812
|
+
try {
|
|
813
|
+
await this.connectPromise;
|
|
814
|
+
logTiming2("connectFull success", startedAt, { chainId });
|
|
815
|
+
} finally {
|
|
816
|
+
this.connectPromise = null;
|
|
817
|
+
}
|
|
642
818
|
}
|
|
643
819
|
async resolveSmartWallet(state, chainId) {
|
|
820
|
+
const startedAt = Date.now();
|
|
644
821
|
await this.connectFull(state, chainId);
|
|
645
822
|
const validChainId = isValidChainId(chainId);
|
|
646
823
|
if (!this.smartWalletAddress) {
|
|
647
824
|
throw new Error("Wallet not connected. Call sdk.connect() first.");
|
|
648
825
|
}
|
|
826
|
+
logTiming2("resolveSmartWallet ready", startedAt, { chainId: validChainId });
|
|
649
827
|
return {
|
|
650
828
|
smartWallet: this.smartWalletAddress,
|
|
651
829
|
chainId: validChainId
|
|
@@ -762,9 +940,30 @@ var SailAgent = class {
|
|
|
762
940
|
}
|
|
763
941
|
// --- IAgent: Portfolio reads ---
|
|
764
942
|
async getBalances(state, chainId) {
|
|
943
|
+
const startedAt = Date.now();
|
|
765
944
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
766
|
-
const
|
|
767
|
-
|
|
945
|
+
const portfolioStart = Date.now();
|
|
946
|
+
try {
|
|
947
|
+
const raw = await this.getMetricsPortfolio(state, chainId);
|
|
948
|
+
logTiming2("getBalances getMetricsPortfolio", portfolioStart, { chainId });
|
|
949
|
+
logTiming2("getBalances success", startedAt, { chainId });
|
|
950
|
+
return mapPortfolioBalances(raw, smartWallet);
|
|
951
|
+
} catch (error) {
|
|
952
|
+
if (error instanceof Error && error.message.startsWith("Sail API timeout")) {
|
|
953
|
+
console.warn(
|
|
954
|
+
"Sail portfolio request timed out; using empty snapshot.",
|
|
955
|
+
{
|
|
956
|
+
chainId
|
|
957
|
+
}
|
|
958
|
+
);
|
|
959
|
+
logTiming2("getBalances timeout-fallback", startedAt, { chainId });
|
|
960
|
+
return mapPortfolioBalances(
|
|
961
|
+
{ message: "timeout", result: [] },
|
|
962
|
+
smartWallet
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
throw error;
|
|
966
|
+
}
|
|
768
967
|
}
|
|
769
968
|
async getEarnings(state, chainId) {
|
|
770
969
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
@@ -785,7 +984,9 @@ var SailAgent = class {
|
|
|
785
984
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
786
985
|
return this.request(
|
|
787
986
|
"GET",
|
|
788
|
-
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/portfolio?${smartWallet ? `smart_account=${smartWallet}` : ""}
|
|
987
|
+
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/portfolio?${smartWallet ? `smart_account=${smartWallet}` : ""}`,
|
|
988
|
+
void 0,
|
|
989
|
+
SAIL_PORTFOLIO_TIMEOUT_MS
|
|
789
990
|
);
|
|
790
991
|
}
|
|
791
992
|
async getMetricsEarnings(state, chainId) {
|
|
@@ -904,7 +1105,7 @@ var SailAgent = class {
|
|
|
904
1105
|
return mapUserProfile2(raw);
|
|
905
1106
|
}
|
|
906
1107
|
// --- IAgent: Discovery (no wallet required) ---
|
|
907
|
-
async getAgentApy(days) {
|
|
1108
|
+
async getAgentApy(days, _options) {
|
|
908
1109
|
const raw = await this.getMetricsYield(days);
|
|
909
1110
|
return mapApyByStrategy2(raw);
|
|
910
1111
|
}
|
|
@@ -968,11 +1169,21 @@ var AGENT_CONSTRUCTORS = {
|
|
|
968
1169
|
zyfai: ZyfaiAgent,
|
|
969
1170
|
sail: SailAgent
|
|
970
1171
|
};
|
|
1172
|
+
var SDK_TIMING_PREFIX = "[OwneySDKTiming]";
|
|
1173
|
+
function logTiming3(label, startedAt, meta) {
|
|
1174
|
+
const elapsedMs = Date.now() - startedAt;
|
|
1175
|
+
if (meta) {
|
|
1176
|
+
console.log(`${SDK_TIMING_PREFIX} ${label} ${elapsedMs}ms`, meta);
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
console.log(`${SDK_TIMING_PREFIX} ${label} ${elapsedMs}ms`);
|
|
1180
|
+
}
|
|
971
1181
|
var OwneySDK = class {
|
|
972
1182
|
agents = /* @__PURE__ */ new Map();
|
|
973
1183
|
activeAgents = /* @__PURE__ */ new Set();
|
|
974
1184
|
state = null;
|
|
975
1185
|
apiKey;
|
|
1186
|
+
initializingAgentsPromise = null;
|
|
976
1187
|
constructor(config) {
|
|
977
1188
|
this.apiKey = config.apiKey;
|
|
978
1189
|
}
|
|
@@ -1049,6 +1260,32 @@ var OwneySDK = class {
|
|
|
1049
1260
|
}
|
|
1050
1261
|
return active;
|
|
1051
1262
|
}
|
|
1263
|
+
async ensureAgentsInitialized() {
|
|
1264
|
+
if (this.agents.size > 0)
|
|
1265
|
+
return;
|
|
1266
|
+
if (!this.initializingAgentsPromise) {
|
|
1267
|
+
this.initializingAgentsPromise = (async () => {
|
|
1268
|
+
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
1269
|
+
for (const { key, agent_type } of agentKeys) {
|
|
1270
|
+
const AgentClass = AGENT_CONSTRUCTORS[agent_type];
|
|
1271
|
+
if (!AgentClass)
|
|
1272
|
+
continue;
|
|
1273
|
+
const agent = new AgentClass(key);
|
|
1274
|
+
this.agents.set(agent_type, agent);
|
|
1275
|
+
}
|
|
1276
|
+
if (this.agents.size === 0) {
|
|
1277
|
+
throw new Error(
|
|
1278
|
+
"No supported agents returned by the routing API. Check your API key and routing configuration."
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
})();
|
|
1282
|
+
}
|
|
1283
|
+
try {
|
|
1284
|
+
await this.initializingAgentsPromise;
|
|
1285
|
+
} finally {
|
|
1286
|
+
this.initializingAgentsPromise = null;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1052
1289
|
// --- Account lifecycle ---
|
|
1053
1290
|
/**
|
|
1054
1291
|
* Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted.
|
|
@@ -1061,22 +1298,9 @@ var OwneySDK = class {
|
|
|
1061
1298
|
* throws before activating any agent.
|
|
1062
1299
|
*/
|
|
1063
1300
|
async activateAgent(chainId, agentId) {
|
|
1301
|
+
const startedAt = Date.now();
|
|
1064
1302
|
const state = this.requireState();
|
|
1065
|
-
|
|
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
|
-
}
|
|
1303
|
+
await this.ensureAgentsInitialized();
|
|
1080
1304
|
if (agentId !== void 0) {
|
|
1081
1305
|
if (agentId.length === 0) {
|
|
1082
1306
|
throw new Error(
|
|
@@ -1094,14 +1318,27 @@ var OwneySDK = class {
|
|
|
1094
1318
|
if (incompatibleAgents.length > 0) {
|
|
1095
1319
|
throw new AgentChainIncompatibleError(incompatibleAgents, chainId);
|
|
1096
1320
|
}
|
|
1097
|
-
for (const agent of agents) {
|
|
1098
|
-
await agent.activateAgent(state, chainId);
|
|
1099
|
-
}
|
|
1100
1321
|
this.activeAgents.clear();
|
|
1101
1322
|
for (const id of uniqueIds) {
|
|
1102
1323
|
this.activeAgents.add(id);
|
|
1103
1324
|
}
|
|
1104
1325
|
state.chainId = chainId;
|
|
1326
|
+
Promise.all(
|
|
1327
|
+
agents.map(async (agent) => {
|
|
1328
|
+
const agentStart = Date.now();
|
|
1329
|
+
await agent.activateAgent(state, chainId);
|
|
1330
|
+
logTiming3("activateAgent background-agent-ready", agentStart, {
|
|
1331
|
+
chainId,
|
|
1332
|
+
agentId: agent.id
|
|
1333
|
+
});
|
|
1334
|
+
})
|
|
1335
|
+
).catch((error) => {
|
|
1336
|
+
console.error("activateAgent background init failed:", error);
|
|
1337
|
+
});
|
|
1338
|
+
logTiming3("activateAgent scheduled", startedAt, {
|
|
1339
|
+
chainId,
|
|
1340
|
+
agentIds: uniqueIds
|
|
1341
|
+
});
|
|
1105
1342
|
return;
|
|
1106
1343
|
}
|
|
1107
1344
|
const compatible = [...this.agents.values()].filter(
|
|
@@ -1110,14 +1347,27 @@ var OwneySDK = class {
|
|
|
1110
1347
|
if (compatible.length === 0) {
|
|
1111
1348
|
throw new Error(`No agents support chain ${chainId}.`);
|
|
1112
1349
|
}
|
|
1113
|
-
for (const agent of compatible) {
|
|
1114
|
-
await agent.activateAgent(state, chainId);
|
|
1115
|
-
}
|
|
1116
1350
|
this.activeAgents.clear();
|
|
1117
1351
|
for (const agent of compatible) {
|
|
1118
1352
|
this.activeAgents.add(agent.id);
|
|
1119
1353
|
}
|
|
1120
1354
|
state.chainId = chainId;
|
|
1355
|
+
Promise.all(
|
|
1356
|
+
compatible.map(async (agent) => {
|
|
1357
|
+
const agentStart = Date.now();
|
|
1358
|
+
await agent.activateAgent(state, chainId);
|
|
1359
|
+
logTiming3("activateAgent background-agent-ready", agentStart, {
|
|
1360
|
+
chainId,
|
|
1361
|
+
agentId: agent.id
|
|
1362
|
+
});
|
|
1363
|
+
})
|
|
1364
|
+
).catch((error) => {
|
|
1365
|
+
console.error("activateAgent background init failed:", error);
|
|
1366
|
+
});
|
|
1367
|
+
logTiming3("activateAgent scheduled", startedAt, {
|
|
1368
|
+
chainId,
|
|
1369
|
+
agentIds: compatible.map((agent) => agent.id)
|
|
1370
|
+
});
|
|
1121
1371
|
}
|
|
1122
1372
|
/**
|
|
1123
1373
|
* Deposit funds into a specific agent, or split equally across all agents if agentId is omitted.
|
|
@@ -1221,17 +1471,47 @@ var OwneySDK = class {
|
|
|
1221
1471
|
* @returns {AgentBalance} for a single agent, or {OwneyBalances} with totalBalance and per-agent breakdown
|
|
1222
1472
|
*/
|
|
1223
1473
|
async getBalances(agentId) {
|
|
1474
|
+
const startedAt = Date.now();
|
|
1224
1475
|
const state = this.requireState();
|
|
1225
1476
|
const chainId = this.requireChainId();
|
|
1226
1477
|
if (agentId) {
|
|
1227
|
-
|
|
1478
|
+
const result = await this.getAgent(agentId).getBalances(state, chainId);
|
|
1479
|
+
logTiming3("getBalances single-agent", startedAt, { chainId, agentId });
|
|
1480
|
+
return result;
|
|
1228
1481
|
}
|
|
1229
1482
|
let totalBalance = 0;
|
|
1230
1483
|
const results = {};
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1484
|
+
const entries = [...this.getActiveAgents().entries()];
|
|
1485
|
+
const balanceResults = await Promise.allSettled(
|
|
1486
|
+
entries.map(async ([id, agent]) => {
|
|
1487
|
+
const agentStartedAt = Date.now();
|
|
1488
|
+
const b = await agent.getBalances(state, chainId);
|
|
1489
|
+
logTiming3("getBalances per-agent", agentStartedAt, {
|
|
1490
|
+
chainId,
|
|
1491
|
+
agentId: id
|
|
1492
|
+
});
|
|
1493
|
+
return [id, b];
|
|
1494
|
+
})
|
|
1495
|
+
);
|
|
1496
|
+
let successCount = 0;
|
|
1497
|
+
for (const settledResult of balanceResults) {
|
|
1498
|
+
if (settledResult.status === "fulfilled") {
|
|
1499
|
+
const [id, b] = settledResult.value;
|
|
1500
|
+
results[id] = b;
|
|
1501
|
+
totalBalance += Number(b.totalBalance);
|
|
1502
|
+
successCount += 1;
|
|
1503
|
+
continue;
|
|
1504
|
+
}
|
|
1505
|
+
console.error("getBalances agent failed:", settledResult.reason);
|
|
1506
|
+
}
|
|
1507
|
+
if (successCount === 0) {
|
|
1508
|
+
throw new Error("Failed to fetch balances for all active agents.");
|
|
1234
1509
|
}
|
|
1510
|
+
logTiming3("getBalances aggregate", startedAt, {
|
|
1511
|
+
chainId,
|
|
1512
|
+
totalAgents: entries.length,
|
|
1513
|
+
successCount
|
|
1514
|
+
});
|
|
1235
1515
|
return {
|
|
1236
1516
|
totalBalance: String(totalBalance),
|
|
1237
1517
|
agentBalances: results
|
|
@@ -1250,9 +1530,16 @@ var OwneySDK = class {
|
|
|
1250
1530
|
}
|
|
1251
1531
|
let totalEarnings = 0;
|
|
1252
1532
|
const results = {};
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1533
|
+
const entries = [...this.getActiveAgents().entries()];
|
|
1534
|
+
const earningsResults = await Promise.all(
|
|
1535
|
+
entries.map(async ([id, agent]) => {
|
|
1536
|
+
const e = await agent.getEarnings(state, chainId);
|
|
1537
|
+
return [id, e];
|
|
1538
|
+
})
|
|
1539
|
+
);
|
|
1540
|
+
for (const [id, e] of earningsResults) {
|
|
1541
|
+
results[id] = e;
|
|
1542
|
+
totalEarnings += Number(e.lifetimeEarnings);
|
|
1256
1543
|
}
|
|
1257
1544
|
return {
|
|
1258
1545
|
totalEarnings: String(totalEarnings),
|
|
@@ -1277,16 +1564,30 @@ var OwneySDK = class {
|
|
|
1277
1564
|
return this.getAgent(agentId).getAccountApy(state, chainId, days);
|
|
1278
1565
|
}
|
|
1279
1566
|
const activeAgents = this.getActiveAgents();
|
|
1567
|
+
const entries = [...activeAgents.entries()];
|
|
1568
|
+
const [apyResults, balanceResults] = await Promise.all([
|
|
1569
|
+
Promise.all(
|
|
1570
|
+
entries.map(async ([id, agent]) => {
|
|
1571
|
+
const apy = await agent.getAccountApy(state, chainId, days);
|
|
1572
|
+
return [id, apy];
|
|
1573
|
+
})
|
|
1574
|
+
),
|
|
1575
|
+
Promise.all(
|
|
1576
|
+
entries.map(async ([id, agent]) => {
|
|
1577
|
+
const b = await agent.getBalances(state, chainId);
|
|
1578
|
+
return [id, Number(b.totalBalance)];
|
|
1579
|
+
})
|
|
1580
|
+
)
|
|
1581
|
+
]);
|
|
1280
1582
|
const results = {};
|
|
1281
|
-
for (const [id,
|
|
1282
|
-
results[id] =
|
|
1583
|
+
for (const [id, apy] of apyResults) {
|
|
1584
|
+
results[id] = apy;
|
|
1283
1585
|
}
|
|
1284
1586
|
const balances = {};
|
|
1285
1587
|
let totalBalance = 0;
|
|
1286
|
-
for (const [id,
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
totalBalance += balances[id];
|
|
1588
|
+
for (const [id, bal] of balanceResults) {
|
|
1589
|
+
balances[id] = bal;
|
|
1590
|
+
totalBalance += bal;
|
|
1290
1591
|
}
|
|
1291
1592
|
let totalApy = 0;
|
|
1292
1593
|
if (totalBalance > 0) {
|
|
@@ -1314,9 +1615,13 @@ var OwneySDK = class {
|
|
|
1314
1615
|
if (agentId) {
|
|
1315
1616
|
return this.getAgent(agentId).getHistory(state, chainId, filters);
|
|
1316
1617
|
}
|
|
1618
|
+
const historyResults = await Promise.all(
|
|
1619
|
+
[...this.getActiveAgents().values()].map(
|
|
1620
|
+
(agent) => agent.getHistory(state, chainId, filters)
|
|
1621
|
+
)
|
|
1622
|
+
);
|
|
1317
1623
|
let results = [];
|
|
1318
|
-
for (const
|
|
1319
|
-
const { data } = await agent.getHistory(state, chainId, filters);
|
|
1624
|
+
for (const { data } of historyResults) {
|
|
1320
1625
|
results = [...results, ...data];
|
|
1321
1626
|
}
|
|
1322
1627
|
results.sort(
|
|
@@ -1360,8 +1665,15 @@ var OwneySDK = class {
|
|
|
1360
1665
|
return this.getAgent(agentId).getUserProfile(state, chainId);
|
|
1361
1666
|
}
|
|
1362
1667
|
const results = {};
|
|
1363
|
-
|
|
1364
|
-
|
|
1668
|
+
const entries = [...this.getActiveAgents().entries()];
|
|
1669
|
+
const profileResults = await Promise.all(
|
|
1670
|
+
entries.map(async ([id, agent]) => {
|
|
1671
|
+
const p = await agent.getUserProfile(state, chainId);
|
|
1672
|
+
return [id, p];
|
|
1673
|
+
})
|
|
1674
|
+
);
|
|
1675
|
+
for (const [id, p] of profileResults) {
|
|
1676
|
+
results[id] = p;
|
|
1365
1677
|
}
|
|
1366
1678
|
return {
|
|
1367
1679
|
agentUserProfile: results
|
|
@@ -1373,18 +1685,34 @@ var OwneySDK = class {
|
|
|
1373
1685
|
* @param options - Contains agentId (optional) and days ("7D", "14D", or "30D")
|
|
1374
1686
|
* @param options.agentId - Optional. Agent to query. Omit for all agents.
|
|
1375
1687
|
* @param options.days - Lookback period: "7D", "14D", or "30D"
|
|
1688
|
+
* @param options.tokenSymbol - Optional asset symbol ("USDC" / "WETH") to
|
|
1689
|
+
* scope the APY to a specific asset+chain. Agents whose backends do not
|
|
1690
|
+
* support per-asset APY (currently Sail) ignore this.
|
|
1691
|
+
* @param options.chainId - Optional chain id for per-asset APY lookups.
|
|
1692
|
+
* Typically paired with `tokenSymbol`.
|
|
1376
1693
|
* @returns {AgentApy} for a single agent, or {OwneyAgentApy} with per-agent APY
|
|
1377
1694
|
*/
|
|
1378
1695
|
async getAgentApy({
|
|
1379
1696
|
agentId,
|
|
1380
|
-
days
|
|
1697
|
+
days,
|
|
1698
|
+
tokenSymbol,
|
|
1699
|
+
chainId
|
|
1381
1700
|
}) {
|
|
1701
|
+
await this.ensureAgentsInitialized();
|
|
1702
|
+
const agentOptions = { tokenSymbol, chainId };
|
|
1382
1703
|
if (agentId) {
|
|
1383
|
-
return this.getAgent(agentId).getAgentApy(days);
|
|
1704
|
+
return this.getAgent(agentId).getAgentApy(days, agentOptions);
|
|
1384
1705
|
}
|
|
1385
1706
|
const results = {};
|
|
1386
|
-
|
|
1387
|
-
|
|
1707
|
+
const agentEntries = [...this.agents.entries()];
|
|
1708
|
+
const apyResults = await Promise.all(
|
|
1709
|
+
agentEntries.map(async ([id, agent]) => {
|
|
1710
|
+
const apy = await agent.getAgentApy(days, agentOptions);
|
|
1711
|
+
return [id, apy];
|
|
1712
|
+
})
|
|
1713
|
+
);
|
|
1714
|
+
for (const [id, apy] of apyResults) {
|
|
1715
|
+
results[id] = apy;
|
|
1388
1716
|
}
|
|
1389
1717
|
return {
|
|
1390
1718
|
agentApy: results
|
|
@@ -1400,10 +1728,26 @@ var OwneySDK = class {
|
|
|
1400
1728
|
const activeAgents = this.getActiveAgents();
|
|
1401
1729
|
const balances = {};
|
|
1402
1730
|
let totalBalance = 0;
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1731
|
+
const entries = [...activeAgents.entries()];
|
|
1732
|
+
const balanceResults = await Promise.allSettled(
|
|
1733
|
+
entries.map(async ([id, agent]) => {
|
|
1734
|
+
const b = await agent.getBalances(state, chainId);
|
|
1735
|
+
return [id, Number(b.totalBalance)];
|
|
1736
|
+
})
|
|
1737
|
+
);
|
|
1738
|
+
let successCount = 0;
|
|
1739
|
+
for (const settledResult of balanceResults) {
|
|
1740
|
+
if (settledResult.status === "fulfilled") {
|
|
1741
|
+
const [id, bal] = settledResult.value;
|
|
1742
|
+
balances[id] = bal;
|
|
1743
|
+
totalBalance += bal;
|
|
1744
|
+
successCount += 1;
|
|
1745
|
+
} else {
|
|
1746
|
+
console.error("getAgentAllocation agent failed:", settledResult.reason);
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
if (successCount === 0) {
|
|
1750
|
+
throw new Error("Failed to fetch allocation: all agents failed.");
|
|
1407
1751
|
}
|
|
1408
1752
|
const allocation = {};
|
|
1409
1753
|
if (totalBalance === 0) {
|