@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.cjs
CHANGED
|
@@ -37,6 +37,23 @@ var P_SUPPORTED_CHAINS = {
|
|
|
37
37
|
};
|
|
38
38
|
var SUPPORTED_CHAIN_IDS = P_SUPPORTED_CHAINS.chainIds;
|
|
39
39
|
var SUPPORTED_CHAINS = P_SUPPORTED_CHAINS.chains;
|
|
40
|
+
var SupportedAssets = [
|
|
41
|
+
{
|
|
42
|
+
address: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`,
|
|
43
|
+
symbol: "USDC",
|
|
44
|
+
chainId: 8453
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
address: `0xaf88d065e77c8cC2239327C5EDb3A432268e5831`,
|
|
48
|
+
symbol: "USDC",
|
|
49
|
+
chainId: 42161
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
address: `0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9`,
|
|
53
|
+
symbol: "USDT",
|
|
54
|
+
chainId: 42161
|
|
55
|
+
}
|
|
56
|
+
];
|
|
40
57
|
|
|
41
58
|
// src/lib/utils.ts
|
|
42
59
|
var isValidChainId = (chainId) => {
|
|
@@ -214,13 +231,41 @@ function mapUserProfile(raw, userAddress) {
|
|
|
214
231
|
};
|
|
215
232
|
}
|
|
216
233
|
function mapApyByStrategy(raw) {
|
|
217
|
-
const
|
|
234
|
+
const apyPerAsset = {};
|
|
235
|
+
let apySum = 0;
|
|
236
|
+
let apyCount = 0;
|
|
237
|
+
for (const entry of raw.data) {
|
|
238
|
+
const supported = SupportedAssets.find(
|
|
239
|
+
(asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
|
|
240
|
+
);
|
|
241
|
+
if (!supported)
|
|
242
|
+
continue;
|
|
243
|
+
const chainKey = supported.chainId;
|
|
244
|
+
const symbolKey = supported.symbol;
|
|
245
|
+
const bucket = apyPerAsset[chainKey] ?? {};
|
|
246
|
+
bucket[symbolKey] = entry.average_apy;
|
|
247
|
+
apyPerAsset[chainKey] = bucket;
|
|
248
|
+
apySum += entry.average_apy;
|
|
249
|
+
apyCount += 1;
|
|
250
|
+
}
|
|
251
|
+
const averageApy = apyCount > 0 ? apySum / apyCount : 0;
|
|
252
|
+
const hasDetails = Object.keys(apyPerAsset).length > 0;
|
|
218
253
|
return {
|
|
219
|
-
averageApy
|
|
254
|
+
averageApy,
|
|
255
|
+
detailedApys: hasDetails ? { apyPerAsset } : void 0
|
|
220
256
|
};
|
|
221
257
|
}
|
|
222
258
|
|
|
223
259
|
// src/agents/zyfai/zyfai.agent.ts
|
|
260
|
+
var ZYFAI_TIMING_PREFIX = "[AgentTiming][zyfai]";
|
|
261
|
+
function logTiming(label, startedAt, meta) {
|
|
262
|
+
const elapsedMs = Date.now() - startedAt;
|
|
263
|
+
if (meta) {
|
|
264
|
+
console.log(`${ZYFAI_TIMING_PREFIX} ${label} ${elapsedMs}ms`, meta);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
console.log(`${ZYFAI_TIMING_PREFIX} ${label} ${elapsedMs}ms`);
|
|
268
|
+
}
|
|
224
269
|
var ZyfaiAgent = class {
|
|
225
270
|
id = "zyfai";
|
|
226
271
|
supportedChainIds = [8453, 42161];
|
|
@@ -239,6 +284,8 @@ var ZyfaiAgent = class {
|
|
|
239
284
|
sdk;
|
|
240
285
|
connectedAddress = null;
|
|
241
286
|
connectedChainId = null;
|
|
287
|
+
smartWalletCache = /* @__PURE__ */ new Map();
|
|
288
|
+
connectAuthPromise = null;
|
|
242
289
|
constructor(apiKey) {
|
|
243
290
|
this.sdk = new import_sdk.ZyfaiSDK({ apiKey });
|
|
244
291
|
}
|
|
@@ -251,50 +298,105 @@ var ZyfaiAgent = class {
|
|
|
251
298
|
}
|
|
252
299
|
/** Light connect: SIWE auth only. Re-auths if chain changed. */
|
|
253
300
|
async connectAuth(state, chainId) {
|
|
301
|
+
const startedAt = Date.now();
|
|
254
302
|
const validChainId = isValidChainId(chainId);
|
|
255
|
-
if (
|
|
303
|
+
if (this.connectedAddress && this.connectedChainId === validChainId) {
|
|
304
|
+
logTiming("connectAuth cache-hit", startedAt, { chainId: validChainId });
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (this.connectAuthPromise) {
|
|
308
|
+
await this.connectAuthPromise;
|
|
309
|
+
logTiming("connectAuth awaited-inflight", startedAt, {
|
|
310
|
+
chainId: validChainId
|
|
311
|
+
});
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
this.connectAuthPromise = (async () => {
|
|
256
315
|
const address = await this.sdk.connectAccount(
|
|
257
316
|
state.provider,
|
|
258
317
|
validChainId
|
|
259
318
|
);
|
|
260
319
|
this.connectedAddress = address;
|
|
261
320
|
this.connectedChainId = validChainId;
|
|
321
|
+
})();
|
|
322
|
+
try {
|
|
323
|
+
await this.connectAuthPromise;
|
|
324
|
+
logTiming("connectAuth success", startedAt, { chainId: validChainId });
|
|
325
|
+
} finally {
|
|
326
|
+
this.connectAuthPromise = null;
|
|
262
327
|
}
|
|
263
328
|
}
|
|
264
329
|
/** Full connect: SIWE auth + Safe deploy check + session key. */
|
|
265
330
|
async connectFull(state, chainId) {
|
|
331
|
+
const startedAt = Date.now();
|
|
266
332
|
await this.connectAuth(state, chainId);
|
|
267
333
|
const validChainId = isValidChainId(chainId);
|
|
268
334
|
const address = this.getAddress();
|
|
335
|
+
const walletLookupStart = Date.now();
|
|
269
336
|
const wallet = await this.sdk.getSmartWalletAddress(address, validChainId);
|
|
337
|
+
logTiming("connectFull getSmartWalletAddress", walletLookupStart, {
|
|
338
|
+
chainId: validChainId
|
|
339
|
+
});
|
|
340
|
+
this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
|
|
270
341
|
if (!wallet.isDeployed) {
|
|
342
|
+
const deployStart = Date.now();
|
|
271
343
|
await this.sdk.deploySafe(address, validChainId, "aggressive", true);
|
|
344
|
+
logTiming("connectFull deploySafe", deployStart, {
|
|
345
|
+
chainId: validChainId
|
|
346
|
+
});
|
|
272
347
|
}
|
|
348
|
+
const userDetailsStart = Date.now();
|
|
273
349
|
const user = await this.sdk.getUserDetails();
|
|
350
|
+
logTiming("connectFull getUserDetails", userDetailsStart, {
|
|
351
|
+
chainId: validChainId
|
|
352
|
+
});
|
|
274
353
|
if (!user.hasActiveSessionKey) {
|
|
354
|
+
const sessionKeyStart = Date.now();
|
|
275
355
|
await this.sdk.createSessionKey(address, validChainId);
|
|
356
|
+
logTiming("connectFull createSessionKey", sessionKeyStart, {
|
|
357
|
+
chainId: validChainId
|
|
358
|
+
});
|
|
276
359
|
}
|
|
360
|
+
logTiming("connectFull success", startedAt, { chainId: validChainId });
|
|
277
361
|
}
|
|
278
362
|
/** Connect + resolve smart wallet address for read operations. */
|
|
279
363
|
async resolveSmartWallet(state, chainId) {
|
|
364
|
+
const startedAt = Date.now();
|
|
280
365
|
await this.connectAuth(state, chainId);
|
|
281
366
|
const validChainId = isValidChainId(chainId);
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
)
|
|
286
|
-
|
|
367
|
+
const ownerAddress = this.getAddress();
|
|
368
|
+
const cacheKey = `${ownerAddress}_${validChainId}`;
|
|
369
|
+
let smartWallet = this.smartWalletCache.get(cacheKey);
|
|
370
|
+
if (!smartWallet) {
|
|
371
|
+
const lookupStart = Date.now();
|
|
372
|
+
const { address } = await this.sdk.getSmartWalletAddress(
|
|
373
|
+
ownerAddress,
|
|
374
|
+
validChainId
|
|
375
|
+
);
|
|
376
|
+
logTiming("resolveSmartWallet remote-lookup", lookupStart, {
|
|
377
|
+
chainId: validChainId
|
|
378
|
+
});
|
|
379
|
+
smartWallet = address;
|
|
380
|
+
this.smartWalletCache.set(cacheKey, smartWallet);
|
|
381
|
+
} else {
|
|
382
|
+
logTiming("resolveSmartWallet cache-hit", startedAt, {
|
|
383
|
+
chainId: validChainId
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
logTiming("resolveSmartWallet ready", startedAt, { chainId: validChainId });
|
|
387
|
+
return { smartWallet, chainId: validChainId };
|
|
287
388
|
}
|
|
288
389
|
// --- IAgent: Connection lifecycle ---
|
|
289
390
|
async disconnect() {
|
|
290
391
|
await this.sdk.disconnectAccount();
|
|
291
392
|
this.connectedAddress = null;
|
|
292
393
|
this.connectedChainId = null;
|
|
394
|
+
this.smartWalletCache.clear();
|
|
293
395
|
}
|
|
294
396
|
// --- IAgent: Account lifecycle ---
|
|
295
397
|
async activateAgent(state, chainId) {
|
|
296
398
|
try {
|
|
297
|
-
await this.
|
|
399
|
+
await this.connectAuth(state, chainId);
|
|
298
400
|
} catch (error) {
|
|
299
401
|
await this.disconnect();
|
|
300
402
|
throw error;
|
|
@@ -341,9 +443,15 @@ var ZyfaiAgent = class {
|
|
|
341
443
|
}
|
|
342
444
|
// --- IAgent: Portfolio reads ---
|
|
343
445
|
async getBalances(state, chainId) {
|
|
446
|
+
const startedAt = Date.now();
|
|
344
447
|
await this.connectAuth(state, chainId);
|
|
345
448
|
const validChainId = isValidChainId(chainId);
|
|
449
|
+
const positionsStart = Date.now();
|
|
346
450
|
const raw = await this.sdk.getPositions(this.getAddress(), validChainId);
|
|
451
|
+
logTiming("getBalances getPositions", positionsStart, {
|
|
452
|
+
chainId: validChainId
|
|
453
|
+
});
|
|
454
|
+
logTiming("getBalances success", startedAt, { chainId: validChainId });
|
|
347
455
|
return mapBalances(raw, validChainId);
|
|
348
456
|
}
|
|
349
457
|
async getEarnings(state, chainId) {
|
|
@@ -378,11 +486,13 @@ var ZyfaiAgent = class {
|
|
|
378
486
|
return mapUserProfile(raw, this.connectedAddress);
|
|
379
487
|
}
|
|
380
488
|
// --- IAgent: Discovery (no wallet required) ---
|
|
381
|
-
async getAgentApy(days) {
|
|
489
|
+
async getAgentApy(days, options) {
|
|
382
490
|
const raw = await this.sdk.getAPYPerStrategy(
|
|
383
491
|
false,
|
|
384
492
|
DayFilterMapping[days],
|
|
385
|
-
"aggressive"
|
|
493
|
+
"aggressive",
|
|
494
|
+
options?.chainId,
|
|
495
|
+
options?.tokenSymbol
|
|
386
496
|
);
|
|
387
497
|
return mapApyByStrategy(raw);
|
|
388
498
|
}
|
|
@@ -428,9 +538,11 @@ function mapEarnings2(raw, smartWallet) {
|
|
|
428
538
|
};
|
|
429
539
|
}
|
|
430
540
|
function mapApyHistory2(raw, walletAddress) {
|
|
541
|
+
const apyPerAsset = remapApyPerAssetToSymbols(raw.result.apy_per_asset);
|
|
431
542
|
return {
|
|
432
543
|
walletAddress,
|
|
433
|
-
weightedApyAfterFee: raw.result
|
|
544
|
+
weightedApyAfterFee: raw.result.apy,
|
|
545
|
+
weightedApyAfterFeeDetails: apyPerAsset ? { apyPerAsset } : void 0
|
|
434
546
|
};
|
|
435
547
|
}
|
|
436
548
|
function mapSailTransaction(tx) {
|
|
@@ -564,15 +676,45 @@ function mapUserProfile2(raw) {
|
|
|
564
676
|
};
|
|
565
677
|
}
|
|
566
678
|
function mapApyByStrategy2(raw) {
|
|
679
|
+
const apyPerAsset = remapApyPerAssetToSymbols(raw.result.apy_per_asset);
|
|
567
680
|
return {
|
|
568
|
-
averageApy: raw.result
|
|
681
|
+
averageApy: raw.result.apy,
|
|
682
|
+
detailedApys: apyPerAsset ? { apyPerAsset } : void 0
|
|
569
683
|
};
|
|
570
684
|
}
|
|
685
|
+
function remapApyPerAssetToSymbols(raw) {
|
|
686
|
+
if (!raw)
|
|
687
|
+
return void 0;
|
|
688
|
+
const remapped = {};
|
|
689
|
+
for (const asset of SupportedAssets) {
|
|
690
|
+
const chainKey = asset.chainId;
|
|
691
|
+
const apyByAddress = raw[String(chainKey)];
|
|
692
|
+
if (!apyByAddress)
|
|
693
|
+
continue;
|
|
694
|
+
const apy = apyByAddress[asset.address] ?? apyByAddress[asset.address.toLowerCase()];
|
|
695
|
+
if (apy === void 0)
|
|
696
|
+
continue;
|
|
697
|
+
const bucket = remapped[chainKey] ?? {};
|
|
698
|
+
bucket[asset.symbol] = apy;
|
|
699
|
+
remapped[chainKey] = bucket;
|
|
700
|
+
}
|
|
701
|
+
return Object.keys(remapped).length > 0 ? remapped : void 0;
|
|
702
|
+
}
|
|
571
703
|
|
|
572
704
|
// src/agents/sail/sail.agent.ts
|
|
573
705
|
var SAIL_API_BASE = "https://app.sail.money";
|
|
574
706
|
var PROJECT_ID = "sail";
|
|
575
707
|
var PAGE_ID = "home";
|
|
708
|
+
var SAIL_TIMING_PREFIX = "[AgentTiming][sail]";
|
|
709
|
+
var SAIL_PORTFOLIO_TIMEOUT_MS = 8e3;
|
|
710
|
+
function logTiming2(label, startedAt, meta) {
|
|
711
|
+
const elapsedMs = Date.now() - startedAt;
|
|
712
|
+
if (meta) {
|
|
713
|
+
console.log(`${SAIL_TIMING_PREFIX} ${label} ${elapsedMs}ms`, meta);
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
console.log(`${SAIL_TIMING_PREFIX} ${label} ${elapsedMs}ms`);
|
|
717
|
+
}
|
|
576
718
|
var SailAgent = class {
|
|
577
719
|
id = "sail";
|
|
578
720
|
supportedChainIds = [8453, 42161];
|
|
@@ -594,11 +736,12 @@ var SailAgent = class {
|
|
|
594
736
|
connectedAddress = null;
|
|
595
737
|
smartWalletAddress = null;
|
|
596
738
|
connectedChainId = null;
|
|
739
|
+
connectPromise = null;
|
|
597
740
|
constructor(apiKey) {
|
|
598
741
|
this.apiKey = apiKey;
|
|
599
742
|
}
|
|
600
743
|
// --- Private helpers ---
|
|
601
|
-
async request(method, path, body) {
|
|
744
|
+
async request(method, path, body, timeoutMs) {
|
|
602
745
|
const headers = {
|
|
603
746
|
"Content-Type": "application/json",
|
|
604
747
|
"X-Business-API-Key": this.apiKey
|
|
@@ -609,11 +752,25 @@ var SailAgent = class {
|
|
|
609
752
|
if (this.accountToken) {
|
|
610
753
|
headers["X-Account-Token"] = this.accountToken;
|
|
611
754
|
}
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
755
|
+
const controller = new AbortController();
|
|
756
|
+
const timeoutId = typeof timeoutMs === "number" && timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
|
|
757
|
+
let res;
|
|
758
|
+
try {
|
|
759
|
+
res = await fetch(`${SAIL_API_BASE}${path}`, {
|
|
760
|
+
method,
|
|
761
|
+
headers,
|
|
762
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
763
|
+
signal: controller.signal
|
|
764
|
+
});
|
|
765
|
+
} catch (error) {
|
|
766
|
+
if (error instanceof Error && error.name === "AbortError" && timeoutMs) {
|
|
767
|
+
throw new Error(`Sail API timeout ${timeoutMs}ms: ${method} ${path}`);
|
|
768
|
+
}
|
|
769
|
+
throw error;
|
|
770
|
+
} finally {
|
|
771
|
+
if (timeoutId)
|
|
772
|
+
clearTimeout(timeoutId);
|
|
773
|
+
}
|
|
617
774
|
if (!res.ok) {
|
|
618
775
|
const text = await res.text().catch(() => "");
|
|
619
776
|
throw new Error(`Sail API error ${res.status}: ${text}`);
|
|
@@ -622,19 +779,22 @@ var SailAgent = class {
|
|
|
622
779
|
}
|
|
623
780
|
/** Initiate SIWE and sign with the user's wallet. */
|
|
624
781
|
async signSiwe(state, chainId) {
|
|
782
|
+
const startedAt = Date.now();
|
|
625
783
|
const initiate = await this.request(
|
|
626
784
|
"POST",
|
|
627
785
|
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/auth/initiate`,
|
|
628
786
|
{
|
|
629
787
|
method: "siwe",
|
|
630
788
|
address: state.walletAddress,
|
|
631
|
-
chainId
|
|
789
|
+
chainId,
|
|
790
|
+
identityMode: "byWallet"
|
|
632
791
|
}
|
|
633
792
|
);
|
|
634
793
|
const signature = await state.provider.request({
|
|
635
794
|
method: "personal_sign",
|
|
636
795
|
params: [initiate.message, state.walletAddress]
|
|
637
796
|
});
|
|
797
|
+
logTiming2("signSiwe success", startedAt, { chainId });
|
|
638
798
|
return {
|
|
639
799
|
sessionId: initiate.sessionId,
|
|
640
800
|
message: initiate.message,
|
|
@@ -643,38 +803,56 @@ var SailAgent = class {
|
|
|
643
803
|
}
|
|
644
804
|
/** Full connect: auth handles smart account creation via SIWE flow. */
|
|
645
805
|
async connectFull(state, chainId) {
|
|
806
|
+
const startedAt = Date.now();
|
|
646
807
|
if (this.connectedAddress && this.connectedChainId === chainId) {
|
|
808
|
+
logTiming2("connectFull cache-hit", startedAt, { chainId });
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
if (this.connectPromise) {
|
|
812
|
+
await this.connectPromise;
|
|
813
|
+
logTiming2("connectFull awaited-inflight", startedAt, { chainId });
|
|
647
814
|
return;
|
|
648
815
|
}
|
|
649
816
|
if (!state.walletAddress) {
|
|
650
817
|
throw new Error("Wallet address is required");
|
|
651
818
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
819
|
+
this.connectPromise = (async () => {
|
|
820
|
+
const { sessionId, signature, message } = await this.signSiwe(
|
|
821
|
+
state,
|
|
822
|
+
chainId
|
|
823
|
+
);
|
|
824
|
+
const complete = await this.request(
|
|
825
|
+
"POST",
|
|
826
|
+
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/auth/complete`,
|
|
827
|
+
{
|
|
828
|
+
method: "custom",
|
|
829
|
+
sessionId,
|
|
830
|
+
signature,
|
|
831
|
+
walletAddress: state.walletAddress,
|
|
832
|
+
identityMode: "byWallet"
|
|
833
|
+
}
|
|
834
|
+
);
|
|
835
|
+
this.authToken = complete.token;
|
|
836
|
+
this.accountToken = complete.accountToken;
|
|
837
|
+
this.connectedAddress = state.walletAddress;
|
|
838
|
+
this.smartWalletAddress = complete.walletAddress;
|
|
839
|
+
this.connectedChainId = chainId;
|
|
840
|
+
})();
|
|
841
|
+
try {
|
|
842
|
+
await this.connectPromise;
|
|
843
|
+
logTiming2("connectFull success", startedAt, { chainId });
|
|
844
|
+
} finally {
|
|
845
|
+
this.connectPromise = null;
|
|
846
|
+
}
|
|
671
847
|
}
|
|
672
848
|
async resolveSmartWallet(state, chainId) {
|
|
849
|
+
const startedAt = Date.now();
|
|
673
850
|
await this.connectFull(state, chainId);
|
|
674
851
|
const validChainId = isValidChainId(chainId);
|
|
675
852
|
if (!this.smartWalletAddress) {
|
|
676
853
|
throw new Error("Wallet not connected. Call sdk.connect() first.");
|
|
677
854
|
}
|
|
855
|
+
logTiming2("resolveSmartWallet ready", startedAt, { chainId: validChainId });
|
|
678
856
|
return {
|
|
679
857
|
smartWallet: this.smartWalletAddress,
|
|
680
858
|
chainId: validChainId
|
|
@@ -791,9 +969,30 @@ var SailAgent = class {
|
|
|
791
969
|
}
|
|
792
970
|
// --- IAgent: Portfolio reads ---
|
|
793
971
|
async getBalances(state, chainId) {
|
|
972
|
+
const startedAt = Date.now();
|
|
794
973
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
795
|
-
const
|
|
796
|
-
|
|
974
|
+
const portfolioStart = Date.now();
|
|
975
|
+
try {
|
|
976
|
+
const raw = await this.getMetricsPortfolio(state, chainId);
|
|
977
|
+
logTiming2("getBalances getMetricsPortfolio", portfolioStart, { chainId });
|
|
978
|
+
logTiming2("getBalances success", startedAt, { chainId });
|
|
979
|
+
return mapPortfolioBalances(raw, smartWallet);
|
|
980
|
+
} catch (error) {
|
|
981
|
+
if (error instanceof Error && error.message.startsWith("Sail API timeout")) {
|
|
982
|
+
console.warn(
|
|
983
|
+
"Sail portfolio request timed out; using empty snapshot.",
|
|
984
|
+
{
|
|
985
|
+
chainId
|
|
986
|
+
}
|
|
987
|
+
);
|
|
988
|
+
logTiming2("getBalances timeout-fallback", startedAt, { chainId });
|
|
989
|
+
return mapPortfolioBalances(
|
|
990
|
+
{ message: "timeout", result: [] },
|
|
991
|
+
smartWallet
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
throw error;
|
|
995
|
+
}
|
|
797
996
|
}
|
|
798
997
|
async getEarnings(state, chainId) {
|
|
799
998
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
@@ -814,7 +1013,9 @@ var SailAgent = class {
|
|
|
814
1013
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
815
1014
|
return this.request(
|
|
816
1015
|
"GET",
|
|
817
|
-
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/portfolio?${smartWallet ? `smart_account=${smartWallet}` : ""}
|
|
1016
|
+
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/portfolio?${smartWallet ? `smart_account=${smartWallet}` : ""}`,
|
|
1017
|
+
void 0,
|
|
1018
|
+
SAIL_PORTFOLIO_TIMEOUT_MS
|
|
818
1019
|
);
|
|
819
1020
|
}
|
|
820
1021
|
async getMetricsEarnings(state, chainId) {
|
|
@@ -933,7 +1134,7 @@ var SailAgent = class {
|
|
|
933
1134
|
return mapUserProfile2(raw);
|
|
934
1135
|
}
|
|
935
1136
|
// --- IAgent: Discovery (no wallet required) ---
|
|
936
|
-
async getAgentApy(days) {
|
|
1137
|
+
async getAgentApy(days, _options) {
|
|
937
1138
|
const raw = await this.getMetricsYield(days);
|
|
938
1139
|
return mapApyByStrategy2(raw);
|
|
939
1140
|
}
|
|
@@ -997,11 +1198,21 @@ var AGENT_CONSTRUCTORS = {
|
|
|
997
1198
|
zyfai: ZyfaiAgent,
|
|
998
1199
|
sail: SailAgent
|
|
999
1200
|
};
|
|
1201
|
+
var SDK_TIMING_PREFIX = "[OwneySDKTiming]";
|
|
1202
|
+
function logTiming3(label, startedAt, meta) {
|
|
1203
|
+
const elapsedMs = Date.now() - startedAt;
|
|
1204
|
+
if (meta) {
|
|
1205
|
+
console.log(`${SDK_TIMING_PREFIX} ${label} ${elapsedMs}ms`, meta);
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
console.log(`${SDK_TIMING_PREFIX} ${label} ${elapsedMs}ms`);
|
|
1209
|
+
}
|
|
1000
1210
|
var OwneySDK = class {
|
|
1001
1211
|
agents = /* @__PURE__ */ new Map();
|
|
1002
1212
|
activeAgents = /* @__PURE__ */ new Set();
|
|
1003
1213
|
state = null;
|
|
1004
1214
|
apiKey;
|
|
1215
|
+
initializingAgentsPromise = null;
|
|
1005
1216
|
constructor(config) {
|
|
1006
1217
|
this.apiKey = config.apiKey;
|
|
1007
1218
|
}
|
|
@@ -1078,6 +1289,32 @@ var OwneySDK = class {
|
|
|
1078
1289
|
}
|
|
1079
1290
|
return active;
|
|
1080
1291
|
}
|
|
1292
|
+
async ensureAgentsInitialized() {
|
|
1293
|
+
if (this.agents.size > 0)
|
|
1294
|
+
return;
|
|
1295
|
+
if (!this.initializingAgentsPromise) {
|
|
1296
|
+
this.initializingAgentsPromise = (async () => {
|
|
1297
|
+
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
1298
|
+
for (const { key, agent_type } of agentKeys) {
|
|
1299
|
+
const AgentClass = AGENT_CONSTRUCTORS[agent_type];
|
|
1300
|
+
if (!AgentClass)
|
|
1301
|
+
continue;
|
|
1302
|
+
const agent = new AgentClass(key);
|
|
1303
|
+
this.agents.set(agent_type, agent);
|
|
1304
|
+
}
|
|
1305
|
+
if (this.agents.size === 0) {
|
|
1306
|
+
throw new Error(
|
|
1307
|
+
"No supported agents returned by the routing API. Check your API key and routing configuration."
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
1310
|
+
})();
|
|
1311
|
+
}
|
|
1312
|
+
try {
|
|
1313
|
+
await this.initializingAgentsPromise;
|
|
1314
|
+
} finally {
|
|
1315
|
+
this.initializingAgentsPromise = null;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1081
1318
|
// --- Account lifecycle ---
|
|
1082
1319
|
/**
|
|
1083
1320
|
* Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted.
|
|
@@ -1090,22 +1327,9 @@ var OwneySDK = class {
|
|
|
1090
1327
|
* throws before activating any agent.
|
|
1091
1328
|
*/
|
|
1092
1329
|
async activateAgent(chainId, agentId) {
|
|
1330
|
+
const startedAt = Date.now();
|
|
1093
1331
|
const state = this.requireState();
|
|
1094
|
-
|
|
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
|
-
}
|
|
1332
|
+
await this.ensureAgentsInitialized();
|
|
1109
1333
|
if (agentId !== void 0) {
|
|
1110
1334
|
if (agentId.length === 0) {
|
|
1111
1335
|
throw new Error(
|
|
@@ -1123,14 +1347,27 @@ var OwneySDK = class {
|
|
|
1123
1347
|
if (incompatibleAgents.length > 0) {
|
|
1124
1348
|
throw new AgentChainIncompatibleError(incompatibleAgents, chainId);
|
|
1125
1349
|
}
|
|
1126
|
-
for (const agent of agents) {
|
|
1127
|
-
await agent.activateAgent(state, chainId);
|
|
1128
|
-
}
|
|
1129
1350
|
this.activeAgents.clear();
|
|
1130
1351
|
for (const id of uniqueIds) {
|
|
1131
1352
|
this.activeAgents.add(id);
|
|
1132
1353
|
}
|
|
1133
1354
|
state.chainId = chainId;
|
|
1355
|
+
Promise.all(
|
|
1356
|
+
agents.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: uniqueIds
|
|
1370
|
+
});
|
|
1134
1371
|
return;
|
|
1135
1372
|
}
|
|
1136
1373
|
const compatible = [...this.agents.values()].filter(
|
|
@@ -1139,14 +1376,27 @@ var OwneySDK = class {
|
|
|
1139
1376
|
if (compatible.length === 0) {
|
|
1140
1377
|
throw new Error(`No agents support chain ${chainId}.`);
|
|
1141
1378
|
}
|
|
1142
|
-
for (const agent of compatible) {
|
|
1143
|
-
await agent.activateAgent(state, chainId);
|
|
1144
|
-
}
|
|
1145
1379
|
this.activeAgents.clear();
|
|
1146
1380
|
for (const agent of compatible) {
|
|
1147
1381
|
this.activeAgents.add(agent.id);
|
|
1148
1382
|
}
|
|
1149
1383
|
state.chainId = chainId;
|
|
1384
|
+
Promise.all(
|
|
1385
|
+
compatible.map(async (agent) => {
|
|
1386
|
+
const agentStart = Date.now();
|
|
1387
|
+
await agent.activateAgent(state, chainId);
|
|
1388
|
+
logTiming3("activateAgent background-agent-ready", agentStart, {
|
|
1389
|
+
chainId,
|
|
1390
|
+
agentId: agent.id
|
|
1391
|
+
});
|
|
1392
|
+
})
|
|
1393
|
+
).catch((error) => {
|
|
1394
|
+
console.error("activateAgent background init failed:", error);
|
|
1395
|
+
});
|
|
1396
|
+
logTiming3("activateAgent scheduled", startedAt, {
|
|
1397
|
+
chainId,
|
|
1398
|
+
agentIds: compatible.map((agent) => agent.id)
|
|
1399
|
+
});
|
|
1150
1400
|
}
|
|
1151
1401
|
/**
|
|
1152
1402
|
* Deposit funds into a specific agent, or split equally across all agents if agentId is omitted.
|
|
@@ -1250,17 +1500,47 @@ var OwneySDK = class {
|
|
|
1250
1500
|
* @returns {AgentBalance} for a single agent, or {OwneyBalances} with totalBalance and per-agent breakdown
|
|
1251
1501
|
*/
|
|
1252
1502
|
async getBalances(agentId) {
|
|
1503
|
+
const startedAt = Date.now();
|
|
1253
1504
|
const state = this.requireState();
|
|
1254
1505
|
const chainId = this.requireChainId();
|
|
1255
1506
|
if (agentId) {
|
|
1256
|
-
|
|
1507
|
+
const result = await this.getAgent(agentId).getBalances(state, chainId);
|
|
1508
|
+
logTiming3("getBalances single-agent", startedAt, { chainId, agentId });
|
|
1509
|
+
return result;
|
|
1257
1510
|
}
|
|
1258
1511
|
let totalBalance = 0;
|
|
1259
1512
|
const results = {};
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1513
|
+
const entries = [...this.getActiveAgents().entries()];
|
|
1514
|
+
const balanceResults = await Promise.allSettled(
|
|
1515
|
+
entries.map(async ([id, agent]) => {
|
|
1516
|
+
const agentStartedAt = Date.now();
|
|
1517
|
+
const b = await agent.getBalances(state, chainId);
|
|
1518
|
+
logTiming3("getBalances per-agent", agentStartedAt, {
|
|
1519
|
+
chainId,
|
|
1520
|
+
agentId: id
|
|
1521
|
+
});
|
|
1522
|
+
return [id, b];
|
|
1523
|
+
})
|
|
1524
|
+
);
|
|
1525
|
+
let successCount = 0;
|
|
1526
|
+
for (const settledResult of balanceResults) {
|
|
1527
|
+
if (settledResult.status === "fulfilled") {
|
|
1528
|
+
const [id, b] = settledResult.value;
|
|
1529
|
+
results[id] = b;
|
|
1530
|
+
totalBalance += Number(b.totalBalance);
|
|
1531
|
+
successCount += 1;
|
|
1532
|
+
continue;
|
|
1533
|
+
}
|
|
1534
|
+
console.error("getBalances agent failed:", settledResult.reason);
|
|
1535
|
+
}
|
|
1536
|
+
if (successCount === 0) {
|
|
1537
|
+
throw new Error("Failed to fetch balances for all active agents.");
|
|
1263
1538
|
}
|
|
1539
|
+
logTiming3("getBalances aggregate", startedAt, {
|
|
1540
|
+
chainId,
|
|
1541
|
+
totalAgents: entries.length,
|
|
1542
|
+
successCount
|
|
1543
|
+
});
|
|
1264
1544
|
return {
|
|
1265
1545
|
totalBalance: String(totalBalance),
|
|
1266
1546
|
agentBalances: results
|
|
@@ -1279,9 +1559,16 @@ var OwneySDK = class {
|
|
|
1279
1559
|
}
|
|
1280
1560
|
let totalEarnings = 0;
|
|
1281
1561
|
const results = {};
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1562
|
+
const entries = [...this.getActiveAgents().entries()];
|
|
1563
|
+
const earningsResults = await Promise.all(
|
|
1564
|
+
entries.map(async ([id, agent]) => {
|
|
1565
|
+
const e = await agent.getEarnings(state, chainId);
|
|
1566
|
+
return [id, e];
|
|
1567
|
+
})
|
|
1568
|
+
);
|
|
1569
|
+
for (const [id, e] of earningsResults) {
|
|
1570
|
+
results[id] = e;
|
|
1571
|
+
totalEarnings += Number(e.lifetimeEarnings);
|
|
1285
1572
|
}
|
|
1286
1573
|
return {
|
|
1287
1574
|
totalEarnings: String(totalEarnings),
|
|
@@ -1306,16 +1593,30 @@ var OwneySDK = class {
|
|
|
1306
1593
|
return this.getAgent(agentId).getAccountApy(state, chainId, days);
|
|
1307
1594
|
}
|
|
1308
1595
|
const activeAgents = this.getActiveAgents();
|
|
1596
|
+
const entries = [...activeAgents.entries()];
|
|
1597
|
+
const [apyResults, balanceResults] = await Promise.all([
|
|
1598
|
+
Promise.all(
|
|
1599
|
+
entries.map(async ([id, agent]) => {
|
|
1600
|
+
const apy = await agent.getAccountApy(state, chainId, days);
|
|
1601
|
+
return [id, apy];
|
|
1602
|
+
})
|
|
1603
|
+
),
|
|
1604
|
+
Promise.all(
|
|
1605
|
+
entries.map(async ([id, agent]) => {
|
|
1606
|
+
const b = await agent.getBalances(state, chainId);
|
|
1607
|
+
return [id, Number(b.totalBalance)];
|
|
1608
|
+
})
|
|
1609
|
+
)
|
|
1610
|
+
]);
|
|
1309
1611
|
const results = {};
|
|
1310
|
-
for (const [id,
|
|
1311
|
-
results[id] =
|
|
1612
|
+
for (const [id, apy] of apyResults) {
|
|
1613
|
+
results[id] = apy;
|
|
1312
1614
|
}
|
|
1313
1615
|
const balances = {};
|
|
1314
1616
|
let totalBalance = 0;
|
|
1315
|
-
for (const [id,
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
totalBalance += balances[id];
|
|
1617
|
+
for (const [id, bal] of balanceResults) {
|
|
1618
|
+
balances[id] = bal;
|
|
1619
|
+
totalBalance += bal;
|
|
1319
1620
|
}
|
|
1320
1621
|
let totalApy = 0;
|
|
1321
1622
|
if (totalBalance > 0) {
|
|
@@ -1343,9 +1644,13 @@ var OwneySDK = class {
|
|
|
1343
1644
|
if (agentId) {
|
|
1344
1645
|
return this.getAgent(agentId).getHistory(state, chainId, filters);
|
|
1345
1646
|
}
|
|
1647
|
+
const historyResults = await Promise.all(
|
|
1648
|
+
[...this.getActiveAgents().values()].map(
|
|
1649
|
+
(agent) => agent.getHistory(state, chainId, filters)
|
|
1650
|
+
)
|
|
1651
|
+
);
|
|
1346
1652
|
let results = [];
|
|
1347
|
-
for (const
|
|
1348
|
-
const { data } = await agent.getHistory(state, chainId, filters);
|
|
1653
|
+
for (const { data } of historyResults) {
|
|
1349
1654
|
results = [...results, ...data];
|
|
1350
1655
|
}
|
|
1351
1656
|
results.sort(
|
|
@@ -1389,8 +1694,15 @@ var OwneySDK = class {
|
|
|
1389
1694
|
return this.getAgent(agentId).getUserProfile(state, chainId);
|
|
1390
1695
|
}
|
|
1391
1696
|
const results = {};
|
|
1392
|
-
|
|
1393
|
-
|
|
1697
|
+
const entries = [...this.getActiveAgents().entries()];
|
|
1698
|
+
const profileResults = await Promise.all(
|
|
1699
|
+
entries.map(async ([id, agent]) => {
|
|
1700
|
+
const p = await agent.getUserProfile(state, chainId);
|
|
1701
|
+
return [id, p];
|
|
1702
|
+
})
|
|
1703
|
+
);
|
|
1704
|
+
for (const [id, p] of profileResults) {
|
|
1705
|
+
results[id] = p;
|
|
1394
1706
|
}
|
|
1395
1707
|
return {
|
|
1396
1708
|
agentUserProfile: results
|
|
@@ -1402,18 +1714,34 @@ var OwneySDK = class {
|
|
|
1402
1714
|
* @param options - Contains agentId (optional) and days ("7D", "14D", or "30D")
|
|
1403
1715
|
* @param options.agentId - Optional. Agent to query. Omit for all agents.
|
|
1404
1716
|
* @param options.days - Lookback period: "7D", "14D", or "30D"
|
|
1717
|
+
* @param options.tokenSymbol - Optional asset symbol ("USDC" / "WETH") to
|
|
1718
|
+
* scope the APY to a specific asset+chain. Agents whose backends do not
|
|
1719
|
+
* support per-asset APY (currently Sail) ignore this.
|
|
1720
|
+
* @param options.chainId - Optional chain id for per-asset APY lookups.
|
|
1721
|
+
* Typically paired with `tokenSymbol`.
|
|
1405
1722
|
* @returns {AgentApy} for a single agent, or {OwneyAgentApy} with per-agent APY
|
|
1406
1723
|
*/
|
|
1407
1724
|
async getAgentApy({
|
|
1408
1725
|
agentId,
|
|
1409
|
-
days
|
|
1726
|
+
days,
|
|
1727
|
+
tokenSymbol,
|
|
1728
|
+
chainId
|
|
1410
1729
|
}) {
|
|
1730
|
+
await this.ensureAgentsInitialized();
|
|
1731
|
+
const agentOptions = { tokenSymbol, chainId };
|
|
1411
1732
|
if (agentId) {
|
|
1412
|
-
return this.getAgent(agentId).getAgentApy(days);
|
|
1733
|
+
return this.getAgent(agentId).getAgentApy(days, agentOptions);
|
|
1413
1734
|
}
|
|
1414
1735
|
const results = {};
|
|
1415
|
-
|
|
1416
|
-
|
|
1736
|
+
const agentEntries = [...this.agents.entries()];
|
|
1737
|
+
const apyResults = await Promise.all(
|
|
1738
|
+
agentEntries.map(async ([id, agent]) => {
|
|
1739
|
+
const apy = await agent.getAgentApy(days, agentOptions);
|
|
1740
|
+
return [id, apy];
|
|
1741
|
+
})
|
|
1742
|
+
);
|
|
1743
|
+
for (const [id, apy] of apyResults) {
|
|
1744
|
+
results[id] = apy;
|
|
1417
1745
|
}
|
|
1418
1746
|
return {
|
|
1419
1747
|
agentApy: results
|
|
@@ -1429,10 +1757,26 @@ var OwneySDK = class {
|
|
|
1429
1757
|
const activeAgents = this.getActiveAgents();
|
|
1430
1758
|
const balances = {};
|
|
1431
1759
|
let totalBalance = 0;
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1760
|
+
const entries = [...activeAgents.entries()];
|
|
1761
|
+
const balanceResults = await Promise.allSettled(
|
|
1762
|
+
entries.map(async ([id, agent]) => {
|
|
1763
|
+
const b = await agent.getBalances(state, chainId);
|
|
1764
|
+
return [id, Number(b.totalBalance)];
|
|
1765
|
+
})
|
|
1766
|
+
);
|
|
1767
|
+
let successCount = 0;
|
|
1768
|
+
for (const settledResult of balanceResults) {
|
|
1769
|
+
if (settledResult.status === "fulfilled") {
|
|
1770
|
+
const [id, bal] = settledResult.value;
|
|
1771
|
+
balances[id] = bal;
|
|
1772
|
+
totalBalance += bal;
|
|
1773
|
+
successCount += 1;
|
|
1774
|
+
} else {
|
|
1775
|
+
console.error("getAgentAllocation agent failed:", settledResult.reason);
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
if (successCount === 0) {
|
|
1779
|
+
throw new Error("Failed to fetch allocation: all agents failed.");
|
|
1436
1780
|
}
|
|
1437
1781
|
const allocation = {};
|
|
1438
1782
|
if (totalBalance === 0) {
|