@owney/sdk 0.2.6 → 0.2.8
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 +76 -6
- package/dist/index.cjs +196 -208
- package/dist/index.d.cts +18 -4
- package/dist/index.d.ts +18 -4
- package/dist/index.js +195 -208
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26,11 +26,58 @@ var SupportedAssets = [
|
|
|
26
26
|
}
|
|
27
27
|
];
|
|
28
28
|
|
|
29
|
+
// src/errors.ts
|
|
30
|
+
var OwneyError = class extends Error {
|
|
31
|
+
code;
|
|
32
|
+
details;
|
|
33
|
+
constructor(code, message, details) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = "OwneyError";
|
|
36
|
+
this.code = code;
|
|
37
|
+
this.details = details;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var AgentNotFoundError = class extends OwneyError {
|
|
41
|
+
constructor(agentId, available) {
|
|
42
|
+
super(
|
|
43
|
+
"AGENT_NOT_FOUND",
|
|
44
|
+
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
45
|
+
{ agentId, available }
|
|
46
|
+
);
|
|
47
|
+
this.name = "AgentNotFoundError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var NotConnectedError = class extends OwneyError {
|
|
51
|
+
constructor() {
|
|
52
|
+
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
53
|
+
this.name = "NotConnectedError";
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var AgentChainIncompatibleError = class extends OwneyError {
|
|
57
|
+
incompatibleAgents;
|
|
58
|
+
connectedChainId;
|
|
59
|
+
constructor(incompatibleAgents, connectedChainId) {
|
|
60
|
+
const details = incompatibleAgents.map(
|
|
61
|
+
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
62
|
+
).join("; ");
|
|
63
|
+
super(
|
|
64
|
+
"AGENT_CHAIN_INCOMPATIBLE",
|
|
65
|
+
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
66
|
+
{ incompatibleAgents, connectedChainId }
|
|
67
|
+
);
|
|
68
|
+
this.name = "AgentChainIncompatibleError";
|
|
69
|
+
this.incompatibleAgents = incompatibleAgents;
|
|
70
|
+
this.connectedChainId = connectedChainId;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
29
74
|
// src/lib/utils.ts
|
|
30
75
|
var isValidChainId = (chainId) => {
|
|
31
76
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
32
|
-
throw new
|
|
33
|
-
|
|
77
|
+
throw new OwneyError(
|
|
78
|
+
"CHAIN_UNSUPPORTED",
|
|
79
|
+
`Unsupported chain ID: ${chainId}. Supported chains: ${SUPPORTED_CHAIN_IDS.join(", ")}`,
|
|
80
|
+
{ chainId, supportedChainIds: [...SUPPORTED_CHAIN_IDS] }
|
|
34
81
|
);
|
|
35
82
|
}
|
|
36
83
|
return chainId;
|
|
@@ -45,6 +92,15 @@ function hexToDecimal(hex, decimals = 6) {
|
|
|
45
92
|
const remainder = parsed % divisor;
|
|
46
93
|
return Number(whole) + Number(remainder) / Number(divisor);
|
|
47
94
|
}
|
|
95
|
+
function normalizeDecimalPlace(value, decimals = 6) {
|
|
96
|
+
const parsed = BigInt(value);
|
|
97
|
+
if (decimals <= 0)
|
|
98
|
+
return Number(parsed);
|
|
99
|
+
const divisor = BigInt(10 ** decimals);
|
|
100
|
+
const whole = parsed / divisor;
|
|
101
|
+
const remainder = parsed % divisor;
|
|
102
|
+
return Number(whole) + Number(remainder) / Number(divisor);
|
|
103
|
+
}
|
|
48
104
|
var DayFilterMapping = {
|
|
49
105
|
"30D": 30,
|
|
50
106
|
"14D": 14,
|
|
@@ -74,7 +130,7 @@ var CHAIN_NAME_TO_ID = {
|
|
|
74
130
|
BASE: 8453,
|
|
75
131
|
ARBITRUM: 42161
|
|
76
132
|
};
|
|
77
|
-
function mapBalances(raw, chainId) {
|
|
133
|
+
function mapBalances(raw, chainId, smartWallet) {
|
|
78
134
|
const portfolio = raw.portfolio;
|
|
79
135
|
const tokenMap = /* @__PURE__ */ new Map();
|
|
80
136
|
for (const p of portfolio.positions || []) {
|
|
@@ -85,18 +141,7 @@ function mapBalances(raw, chainId) {
|
|
|
85
141
|
tokenMap.set(key, {
|
|
86
142
|
symbol,
|
|
87
143
|
chainId: positionChainId,
|
|
88
|
-
amount: (current?.amount ?? 0) +
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
for (const s of portfolio.staleBalances || []) {
|
|
92
|
-
const symbol = s.tokenSymbol || "USDC";
|
|
93
|
-
const staleChainId = s.chainId ?? chainId;
|
|
94
|
-
const key = `${symbol}:${staleChainId}`;
|
|
95
|
-
const current = tokenMap.get(key);
|
|
96
|
-
tokenMap.set(key, {
|
|
97
|
-
symbol,
|
|
98
|
-
chainId: staleChainId,
|
|
99
|
-
amount: (current?.amount ?? 0) + hexToDecimal(s.balance || "0")
|
|
144
|
+
amount: (current?.amount ?? 0) + normalizeDecimalPlace(p.underlyingAmount || "0")
|
|
100
145
|
});
|
|
101
146
|
}
|
|
102
147
|
let totalBalance = 0;
|
|
@@ -111,7 +156,7 @@ function mapBalances(raw, chainId) {
|
|
|
111
156
|
});
|
|
112
157
|
}
|
|
113
158
|
return {
|
|
114
|
-
smartWallet
|
|
159
|
+
smartWallet,
|
|
115
160
|
totalBalance: String(totalBalance),
|
|
116
161
|
tokens
|
|
117
162
|
};
|
|
@@ -228,15 +273,6 @@ function mapApyByStrategy(raw) {
|
|
|
228
273
|
}
|
|
229
274
|
|
|
230
275
|
// 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
|
-
}
|
|
240
276
|
var ZyfaiAgent = class {
|
|
241
277
|
id = "zyfai";
|
|
242
278
|
supportedChainIds = [8453, 42161];
|
|
@@ -257,29 +293,27 @@ var ZyfaiAgent = class {
|
|
|
257
293
|
connectedChainId = null;
|
|
258
294
|
smartWalletCache = /* @__PURE__ */ new Map();
|
|
259
295
|
connectAuthPromise = null;
|
|
260
|
-
constructor(apiKey) {
|
|
261
|
-
this.sdk = new ZyfaiSDK({ apiKey });
|
|
296
|
+
constructor(apiKey, rpcUrls) {
|
|
297
|
+
this.sdk = new ZyfaiSDK({ apiKey, rpcUrls });
|
|
262
298
|
}
|
|
263
299
|
// --- Private helpers ---
|
|
264
300
|
getAddress() {
|
|
265
301
|
if (!this.connectedAddress) {
|
|
266
|
-
throw new
|
|
302
|
+
throw new OwneyError(
|
|
303
|
+
"NOT_CONNECTED",
|
|
304
|
+
"Wallet not connected. Call sdk.connect() first."
|
|
305
|
+
);
|
|
267
306
|
}
|
|
268
307
|
return this.connectedAddress;
|
|
269
308
|
}
|
|
270
309
|
/** Light connect: SIWE auth only. Re-auths if chain changed. */
|
|
271
310
|
async connectAuth(state, chainId) {
|
|
272
|
-
const startedAt = Date.now();
|
|
273
311
|
const validChainId = isValidChainId(chainId);
|
|
274
312
|
if (this.connectedAddress && this.connectedChainId === validChainId) {
|
|
275
|
-
logTiming("connectAuth cache-hit", startedAt, { chainId: validChainId });
|
|
276
313
|
return;
|
|
277
314
|
}
|
|
278
315
|
if (this.connectAuthPromise) {
|
|
279
316
|
await this.connectAuthPromise;
|
|
280
|
-
logTiming("connectAuth awaited-inflight", startedAt, {
|
|
281
|
-
chainId: validChainId
|
|
282
|
-
});
|
|
283
317
|
return;
|
|
284
318
|
}
|
|
285
319
|
this.connectAuthPromise = (async () => {
|
|
@@ -292,69 +326,40 @@ var ZyfaiAgent = class {
|
|
|
292
326
|
})();
|
|
293
327
|
try {
|
|
294
328
|
await this.connectAuthPromise;
|
|
295
|
-
logTiming("connectAuth success", startedAt, { chainId: validChainId });
|
|
296
329
|
} finally {
|
|
297
330
|
this.connectAuthPromise = null;
|
|
298
331
|
}
|
|
299
332
|
}
|
|
300
333
|
/** Full connect: SIWE auth + Safe deploy check + session key. */
|
|
301
334
|
async connectFull(state, chainId) {
|
|
302
|
-
const startedAt = Date.now();
|
|
303
335
|
await this.connectAuth(state, chainId);
|
|
304
336
|
const validChainId = isValidChainId(chainId);
|
|
305
337
|
const address = this.getAddress();
|
|
306
|
-
const walletLookupStart = Date.now();
|
|
307
338
|
const wallet = await this.sdk.getSmartWalletAddress(address, validChainId);
|
|
308
|
-
logTiming("connectFull getSmartWalletAddress", walletLookupStart, {
|
|
309
|
-
chainId: validChainId
|
|
310
|
-
});
|
|
311
339
|
this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
|
|
312
340
|
if (!wallet.isDeployed) {
|
|
313
|
-
const deployStart = Date.now();
|
|
314
341
|
await this.sdk.deploySafe(address, validChainId, "aggressive", true);
|
|
315
|
-
logTiming("connectFull deploySafe", deployStart, {
|
|
316
|
-
chainId: validChainId
|
|
317
|
-
});
|
|
318
342
|
}
|
|
319
|
-
const userDetailsStart = Date.now();
|
|
320
343
|
const user = await this.sdk.getUserDetails();
|
|
321
|
-
logTiming("connectFull getUserDetails", userDetailsStart, {
|
|
322
|
-
chainId: validChainId
|
|
323
|
-
});
|
|
324
344
|
if (!user.hasActiveSessionKey) {
|
|
325
|
-
const sessionKeyStart = Date.now();
|
|
326
345
|
await this.sdk.createSessionKey(address, validChainId);
|
|
327
|
-
logTiming("connectFull createSessionKey", sessionKeyStart, {
|
|
328
|
-
chainId: validChainId
|
|
329
|
-
});
|
|
330
346
|
}
|
|
331
|
-
logTiming("connectFull success", startedAt, { chainId: validChainId });
|
|
332
347
|
}
|
|
333
348
|
/** Connect + resolve smart wallet address for read operations. */
|
|
334
349
|
async resolveSmartWallet(state, chainId) {
|
|
335
|
-
const startedAt = Date.now();
|
|
336
350
|
await this.connectAuth(state, chainId);
|
|
337
351
|
const validChainId = isValidChainId(chainId);
|
|
338
352
|
const ownerAddress = this.getAddress();
|
|
339
353
|
const cacheKey = `${ownerAddress}_${validChainId}`;
|
|
340
354
|
let smartWallet = this.smartWalletCache.get(cacheKey);
|
|
341
355
|
if (!smartWallet) {
|
|
342
|
-
const lookupStart = Date.now();
|
|
343
356
|
const { address } = await this.sdk.getSmartWalletAddress(
|
|
344
357
|
ownerAddress,
|
|
345
358
|
validChainId
|
|
346
359
|
);
|
|
347
|
-
logTiming("resolveSmartWallet remote-lookup", lookupStart, {
|
|
348
|
-
chainId: validChainId
|
|
349
|
-
});
|
|
350
360
|
smartWallet = address;
|
|
351
361
|
this.smartWalletCache.set(cacheKey, smartWallet);
|
|
352
|
-
} else {
|
|
353
|
-
logTiming("resolveSmartWallet cache-hit", startedAt, {
|
|
354
|
-
chainId: validChainId
|
|
355
|
-
});
|
|
356
362
|
}
|
|
357
|
-
logTiming("resolveSmartWallet ready", startedAt, { chainId: validChainId });
|
|
358
363
|
return { smartWallet, chainId: validChainId };
|
|
359
364
|
}
|
|
360
365
|
// --- IAgent: Connection lifecycle ---
|
|
@@ -414,16 +419,9 @@ var ZyfaiAgent = class {
|
|
|
414
419
|
}
|
|
415
420
|
// --- IAgent: Portfolio reads ---
|
|
416
421
|
async getBalances(state, chainId) {
|
|
417
|
-
const
|
|
418
|
-
await this.
|
|
419
|
-
|
|
420
|
-
const positionsStart = Date.now();
|
|
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 });
|
|
426
|
-
return mapBalances(raw, validChainId);
|
|
422
|
+
const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
|
|
423
|
+
const raw = await this.sdk.getPortfolio(this.getAddress());
|
|
424
|
+
return mapBalances(raw, validChainId, smartWallet);
|
|
427
425
|
}
|
|
428
426
|
async getEarnings(state, chainId) {
|
|
429
427
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
@@ -487,13 +485,13 @@ function mapWithdraw2(raw) {
|
|
|
487
485
|
function mapPortfolioBalances(raw, smartWallet) {
|
|
488
486
|
let total = 0;
|
|
489
487
|
const tokens = [];
|
|
490
|
-
for (const item of raw.
|
|
491
|
-
total += item.
|
|
488
|
+
for (const item of raw.tokens) {
|
|
489
|
+
total += item.balanceFormatted;
|
|
492
490
|
tokens.push({
|
|
493
|
-
chain: item.chain
|
|
494
|
-
chainId: item.
|
|
495
|
-
asset: item.
|
|
496
|
-
amount:
|
|
491
|
+
chain: SUPPORTED_CHAINS[item.chain],
|
|
492
|
+
chainId: item.chain,
|
|
493
|
+
asset: item.symbol === "USD\u20AE0" ? "USDT" : item.symbol,
|
|
494
|
+
amount: item.balance
|
|
497
495
|
});
|
|
498
496
|
}
|
|
499
497
|
return {
|
|
@@ -676,16 +674,7 @@ function remapApyPerAssetToSymbols(raw) {
|
|
|
676
674
|
var SAIL_API_BASE = "https://app.sail.money";
|
|
677
675
|
var PROJECT_ID = "sail";
|
|
678
676
|
var PAGE_ID = "home";
|
|
679
|
-
var SAIL_TIMING_PREFIX = "[AgentTiming][sail]";
|
|
680
677
|
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
|
-
}
|
|
689
678
|
var SailAgent = class {
|
|
690
679
|
id = "sail";
|
|
691
680
|
supportedChainIds = [8453, 42161];
|
|
@@ -735,7 +724,11 @@ var SailAgent = class {
|
|
|
735
724
|
});
|
|
736
725
|
} catch (error) {
|
|
737
726
|
if (error instanceof Error && error.name === "AbortError" && timeoutMs) {
|
|
738
|
-
throw new
|
|
727
|
+
throw new OwneyError(
|
|
728
|
+
"API_SAIL_TIMEOUT",
|
|
729
|
+
`Sail API timeout ${timeoutMs}ms: ${method} ${path}`,
|
|
730
|
+
{ timeoutMs, method, path }
|
|
731
|
+
);
|
|
739
732
|
}
|
|
740
733
|
throw error;
|
|
741
734
|
} finally {
|
|
@@ -744,13 +737,16 @@ var SailAgent = class {
|
|
|
744
737
|
}
|
|
745
738
|
if (!res.ok) {
|
|
746
739
|
const text = await res.text().catch(() => "");
|
|
747
|
-
throw new
|
|
740
|
+
throw new OwneyError(
|
|
741
|
+
"API_SAIL_ERROR",
|
|
742
|
+
`Sail API error ${res.status}: ${text}`,
|
|
743
|
+
{ statusCode: res.status, method, path, responseBody: text }
|
|
744
|
+
);
|
|
748
745
|
}
|
|
749
746
|
return res.json();
|
|
750
747
|
}
|
|
751
748
|
/** Initiate SIWE and sign with the user's wallet. */
|
|
752
749
|
async signSiwe(state, chainId) {
|
|
753
|
-
const startedAt = Date.now();
|
|
754
750
|
const initiate = await this.request(
|
|
755
751
|
"POST",
|
|
756
752
|
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/auth/initiate`,
|
|
@@ -765,7 +761,6 @@ var SailAgent = class {
|
|
|
765
761
|
method: "personal_sign",
|
|
766
762
|
params: [initiate.message, state.walletAddress]
|
|
767
763
|
});
|
|
768
|
-
logTiming2("signSiwe success", startedAt, { chainId });
|
|
769
764
|
return {
|
|
770
765
|
sessionId: initiate.sessionId,
|
|
771
766
|
message: initiate.message,
|
|
@@ -774,18 +769,18 @@ var SailAgent = class {
|
|
|
774
769
|
}
|
|
775
770
|
/** Full connect: auth handles smart account creation via SIWE flow. */
|
|
776
771
|
async connectFull(state, chainId) {
|
|
777
|
-
const startedAt = Date.now();
|
|
778
772
|
if (this.connectedAddress && this.connectedChainId === chainId) {
|
|
779
|
-
logTiming2("connectFull cache-hit", startedAt, { chainId });
|
|
780
773
|
return;
|
|
781
774
|
}
|
|
782
775
|
if (this.connectPromise) {
|
|
783
776
|
await this.connectPromise;
|
|
784
|
-
logTiming2("connectFull awaited-inflight", startedAt, { chainId });
|
|
785
777
|
return;
|
|
786
778
|
}
|
|
787
779
|
if (!state.walletAddress) {
|
|
788
|
-
throw new
|
|
780
|
+
throw new OwneyError(
|
|
781
|
+
"WALLET_ADDRESS_REQUIRED",
|
|
782
|
+
"Wallet address is required. Call sdk.connect(provider) first."
|
|
783
|
+
);
|
|
789
784
|
}
|
|
790
785
|
this.connectPromise = (async () => {
|
|
791
786
|
const { sessionId, signature, message } = await this.signSiwe(
|
|
@@ -811,19 +806,19 @@ var SailAgent = class {
|
|
|
811
806
|
})();
|
|
812
807
|
try {
|
|
813
808
|
await this.connectPromise;
|
|
814
|
-
logTiming2("connectFull success", startedAt, { chainId });
|
|
815
809
|
} finally {
|
|
816
810
|
this.connectPromise = null;
|
|
817
811
|
}
|
|
818
812
|
}
|
|
819
813
|
async resolveSmartWallet(state, chainId) {
|
|
820
|
-
const startedAt = Date.now();
|
|
821
814
|
await this.connectFull(state, chainId);
|
|
822
815
|
const validChainId = isValidChainId(chainId);
|
|
823
816
|
if (!this.smartWalletAddress) {
|
|
824
|
-
throw new
|
|
817
|
+
throw new OwneyError(
|
|
818
|
+
"NOT_CONNECTED",
|
|
819
|
+
"Wallet not connected. Call sdk.connect() first."
|
|
820
|
+
);
|
|
825
821
|
}
|
|
826
|
-
logTiming2("resolveSmartWallet ready", startedAt, { chainId: validChainId });
|
|
827
822
|
return {
|
|
828
823
|
smartWallet: this.smartWalletAddress,
|
|
829
824
|
chainId: validChainId
|
|
@@ -848,7 +843,8 @@ var SailAgent = class {
|
|
|
848
843
|
}
|
|
849
844
|
async deposit(state, chainId, amount, depositCallback) {
|
|
850
845
|
if (!depositCallback) {
|
|
851
|
-
throw new
|
|
846
|
+
throw new OwneyError(
|
|
847
|
+
"DEPOSIT_CALLBACK_REQUIRED",
|
|
852
848
|
"depositCallback is required for Sail. Provide a callback that transfers tokens and returns the transaction hash."
|
|
853
849
|
);
|
|
854
850
|
}
|
|
@@ -857,12 +853,16 @@ var SailAgent = class {
|
|
|
857
853
|
const depositInfo = await this.getDepositInfo();
|
|
858
854
|
const resolvedTokenAddress = depositInfo.permittedTokens[0]?.address;
|
|
859
855
|
if (!resolvedTokenAddress) {
|
|
860
|
-
throw new
|
|
856
|
+
throw new OwneyError(
|
|
857
|
+
"DEPOSIT_NO_PERMITTED_TOKENS",
|
|
858
|
+
"No permitted tokens available for deposit."
|
|
859
|
+
);
|
|
861
860
|
}
|
|
862
861
|
await this.executePreHooks(resolvedTokenAddress, amount, chainId);
|
|
863
862
|
const txHash = await depositCallback(smartWallet, chainId, amount);
|
|
864
863
|
if (!txHash) {
|
|
865
|
-
throw new
|
|
864
|
+
throw new OwneyError(
|
|
865
|
+
"DEPOSIT_CALLBACK_INVALID",
|
|
866
866
|
"depositCallback must return a transaction hash (txHash) for Sail deposits."
|
|
867
867
|
);
|
|
868
868
|
}
|
|
@@ -916,7 +916,10 @@ var SailAgent = class {
|
|
|
916
916
|
const withdrawInfo = await this.getWithdrawInfo();
|
|
917
917
|
const tokenAddress = withdrawInfo.permittedTokens[0]?.address;
|
|
918
918
|
if (!tokenAddress) {
|
|
919
|
-
throw new
|
|
919
|
+
throw new OwneyError(
|
|
920
|
+
"WITHDRAW_NO_PERMITTED_TOKENS",
|
|
921
|
+
"No permitted tokens available for withdrawal."
|
|
922
|
+
);
|
|
920
923
|
}
|
|
921
924
|
const resolvedAmount = amount ?? withdrawInfo.currentBalance;
|
|
922
925
|
const { signature: adminWalletSignature, message: adminWalletPayload } = await this.signSiwe(state, chainId);
|
|
@@ -940,25 +943,20 @@ var SailAgent = class {
|
|
|
940
943
|
}
|
|
941
944
|
// --- IAgent: Portfolio reads ---
|
|
942
945
|
async getBalances(state, chainId) {
|
|
943
|
-
const startedAt = Date.now();
|
|
944
946
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
945
|
-
const portfolioStart = Date.now();
|
|
946
947
|
try {
|
|
947
|
-
const raw = await this.
|
|
948
|
-
logTiming2("getBalances getMetricsPortfolio", portfolioStart, { chainId });
|
|
949
|
-
logTiming2("getBalances success", startedAt, { chainId });
|
|
948
|
+
const raw = await this.getPortfolio();
|
|
950
949
|
return mapPortfolioBalances(raw, smartWallet);
|
|
951
950
|
} catch (error) {
|
|
952
|
-
if (error instanceof
|
|
951
|
+
if (error instanceof OwneyError && error.code === "API_SAIL_TIMEOUT") {
|
|
953
952
|
console.warn(
|
|
954
953
|
"Sail portfolio request timed out; using empty snapshot.",
|
|
955
954
|
{
|
|
956
955
|
chainId
|
|
957
956
|
}
|
|
958
957
|
);
|
|
959
|
-
logTiming2("getBalances timeout-fallback", startedAt, { chainId });
|
|
960
958
|
return mapPortfolioBalances(
|
|
961
|
-
{ message: "timeout",
|
|
959
|
+
{ message: "timeout", tokens: [] },
|
|
962
960
|
smartWallet
|
|
963
961
|
);
|
|
964
962
|
}
|
|
@@ -989,6 +987,14 @@ var SailAgent = class {
|
|
|
989
987
|
SAIL_PORTFOLIO_TIMEOUT_MS
|
|
990
988
|
);
|
|
991
989
|
}
|
|
990
|
+
async getPortfolio() {
|
|
991
|
+
return this.request(
|
|
992
|
+
"GET",
|
|
993
|
+
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/portfolio/tokens`,
|
|
994
|
+
void 0,
|
|
995
|
+
SAIL_PORTFOLIO_TIMEOUT_MS
|
|
996
|
+
);
|
|
997
|
+
}
|
|
992
998
|
async getMetricsEarnings(state, chainId) {
|
|
993
999
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
994
1000
|
return this.request(
|
|
@@ -996,7 +1002,7 @@ var SailAgent = class {
|
|
|
996
1002
|
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/earnings?smart_account=${smartWallet}`
|
|
997
1003
|
);
|
|
998
1004
|
}
|
|
999
|
-
async getMetricsBalance(state, chainId, currency) {
|
|
1005
|
+
async getMetricsBalance(state, chainId, currency = "usd") {
|
|
1000
1006
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1001
1007
|
return this.request(
|
|
1002
1008
|
"GET",
|
|
@@ -1033,8 +1039,10 @@ var SailAgent = class {
|
|
|
1033
1039
|
}
|
|
1034
1040
|
const dayCount = DayFilterMapping[days];
|
|
1035
1041
|
if (dayCount === void 0) {
|
|
1036
|
-
throw new
|
|
1037
|
-
|
|
1042
|
+
throw new OwneyError(
|
|
1043
|
+
"VALIDATION_INVALID_DAYS",
|
|
1044
|
+
`Invalid days value: "${days}". Expected one of: "7D", "14D", "30D".`,
|
|
1045
|
+
{ days }
|
|
1038
1046
|
);
|
|
1039
1047
|
}
|
|
1040
1048
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -1111,37 +1119,6 @@ var SailAgent = class {
|
|
|
1111
1119
|
}
|
|
1112
1120
|
};
|
|
1113
1121
|
|
|
1114
|
-
// src/errors.ts
|
|
1115
|
-
var AgentNotFoundError = class extends Error {
|
|
1116
|
-
constructor(agentId, available) {
|
|
1117
|
-
super(
|
|
1118
|
-
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`
|
|
1119
|
-
);
|
|
1120
|
-
this.name = "AgentNotFoundError";
|
|
1121
|
-
}
|
|
1122
|
-
};
|
|
1123
|
-
var NotConnectedError = class extends Error {
|
|
1124
|
-
constructor() {
|
|
1125
|
-
super("Not connected. Call sdk.connect(provider) first.");
|
|
1126
|
-
this.name = "NotConnectedError";
|
|
1127
|
-
}
|
|
1128
|
-
};
|
|
1129
|
-
var AgentChainIncompatibleError = class extends Error {
|
|
1130
|
-
incompatibleAgents;
|
|
1131
|
-
connectedChainId;
|
|
1132
|
-
constructor(incompatibleAgents, connectedChainId) {
|
|
1133
|
-
const details = incompatibleAgents.map(
|
|
1134
|
-
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
1135
|
-
).join("; ");
|
|
1136
|
-
super(
|
|
1137
|
-
`Chain ${connectedChainId} is not supported by the following agents: ${details}`
|
|
1138
|
-
);
|
|
1139
|
-
this.name = "AgentChainIncompatibleError";
|
|
1140
|
-
this.incompatibleAgents = incompatibleAgents;
|
|
1141
|
-
this.connectedChainId = connectedChainId;
|
|
1142
|
-
}
|
|
1143
|
-
};
|
|
1144
|
-
|
|
1145
1122
|
// src/lib/routing-api.ts
|
|
1146
1123
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1147
1124
|
async function fetchAgentKeys(apiKey) {
|
|
@@ -1155,37 +1132,34 @@ async function fetchAgentKeys(apiKey) {
|
|
|
1155
1132
|
});
|
|
1156
1133
|
if (!res.ok) {
|
|
1157
1134
|
const text = await res.text().catch(() => "");
|
|
1158
|
-
throw new
|
|
1135
|
+
throw new OwneyError(
|
|
1136
|
+
"API_ROUTING_ERROR",
|
|
1137
|
+
`Routing API error ${res.status}: ${text}`,
|
|
1138
|
+
{ statusCode: res.status, responseBody: text }
|
|
1139
|
+
);
|
|
1159
1140
|
}
|
|
1160
1141
|
const json = await res.json();
|
|
1161
1142
|
if (!json.success) {
|
|
1162
|
-
throw new
|
|
1143
|
+
throw new OwneyError(
|
|
1144
|
+
"API_ROUTING_FAILED",
|
|
1145
|
+
`Routing API request failed: ${json.message}`,
|
|
1146
|
+
{ message: json.message }
|
|
1147
|
+
);
|
|
1163
1148
|
}
|
|
1164
1149
|
return json.data;
|
|
1165
1150
|
}
|
|
1166
1151
|
|
|
1167
1152
|
// src/client.ts
|
|
1168
|
-
var AGENT_CONSTRUCTORS = {
|
|
1169
|
-
zyfai: ZyfaiAgent,
|
|
1170
|
-
sail: SailAgent
|
|
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
|
-
}
|
|
1181
1153
|
var OwneySDK = class {
|
|
1182
1154
|
agents = /* @__PURE__ */ new Map();
|
|
1183
1155
|
activeAgents = /* @__PURE__ */ new Set();
|
|
1184
1156
|
state = null;
|
|
1185
1157
|
apiKey;
|
|
1158
|
+
zyfaiRpcUrls;
|
|
1186
1159
|
initializingAgentsPromise = null;
|
|
1187
1160
|
constructor(config) {
|
|
1188
1161
|
this.apiKey = config.apiKey;
|
|
1162
|
+
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
1189
1163
|
}
|
|
1190
1164
|
/**
|
|
1191
1165
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -1199,7 +1173,8 @@ var OwneySDK = class {
|
|
|
1199
1173
|
});
|
|
1200
1174
|
const walletAddress = accounts[0];
|
|
1201
1175
|
if (!walletAddress) {
|
|
1202
|
-
throw new
|
|
1176
|
+
throw new OwneyError(
|
|
1177
|
+
"WALLET_NO_ACCOUNTS",
|
|
1203
1178
|
"No accounts found. Ensure the wallet is unlocked and connected."
|
|
1204
1179
|
);
|
|
1205
1180
|
}
|
|
@@ -1238,7 +1213,8 @@ var OwneySDK = class {
|
|
|
1238
1213
|
requireChainId() {
|
|
1239
1214
|
const chainId = this.state?.chainId ?? null;
|
|
1240
1215
|
if (chainId === null) {
|
|
1241
|
-
throw new
|
|
1216
|
+
throw new OwneyError(
|
|
1217
|
+
"NO_ACTIVE_CHAIN",
|
|
1242
1218
|
"No active chain. Call sdk.activateAgent(chainId) first."
|
|
1243
1219
|
);
|
|
1244
1220
|
}
|
|
@@ -1267,14 +1243,14 @@ var OwneySDK = class {
|
|
|
1267
1243
|
this.initializingAgentsPromise = (async () => {
|
|
1268
1244
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
1269
1245
|
for (const { key, agent_type } of agentKeys) {
|
|
1270
|
-
const
|
|
1271
|
-
if (!
|
|
1246
|
+
const agent = this.createAgent(agent_type, key);
|
|
1247
|
+
if (!agent)
|
|
1272
1248
|
continue;
|
|
1273
|
-
const agent = new AgentClass(key);
|
|
1274
1249
|
this.agents.set(agent_type, agent);
|
|
1275
1250
|
}
|
|
1276
1251
|
if (this.agents.size === 0) {
|
|
1277
|
-
throw new
|
|
1252
|
+
throw new OwneyError(
|
|
1253
|
+
"API_NO_AGENTS",
|
|
1278
1254
|
"No supported agents returned by the routing API. Check your API key and routing configuration."
|
|
1279
1255
|
);
|
|
1280
1256
|
}
|
|
@@ -1286,6 +1262,15 @@ var OwneySDK = class {
|
|
|
1286
1262
|
this.initializingAgentsPromise = null;
|
|
1287
1263
|
}
|
|
1288
1264
|
}
|
|
1265
|
+
createAgent(agentId, key) {
|
|
1266
|
+
if (agentId === "zyfai") {
|
|
1267
|
+
return new ZyfaiAgent(key, this.zyfaiRpcUrls);
|
|
1268
|
+
}
|
|
1269
|
+
if (agentId === "sail") {
|
|
1270
|
+
return new SailAgent(key);
|
|
1271
|
+
}
|
|
1272
|
+
return null;
|
|
1273
|
+
}
|
|
1289
1274
|
// --- Account lifecycle ---
|
|
1290
1275
|
/**
|
|
1291
1276
|
* Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted.
|
|
@@ -1298,12 +1283,12 @@ var OwneySDK = class {
|
|
|
1298
1283
|
* throws before activating any agent.
|
|
1299
1284
|
*/
|
|
1300
1285
|
async activateAgent(chainId, agentId) {
|
|
1301
|
-
const startedAt = Date.now();
|
|
1302
1286
|
const state = this.requireState();
|
|
1303
1287
|
await this.ensureAgentsInitialized();
|
|
1304
1288
|
if (agentId !== void 0) {
|
|
1305
1289
|
if (agentId.length === 0) {
|
|
1306
|
-
throw new
|
|
1290
|
+
throw new OwneyError(
|
|
1291
|
+
"AGENT_EMPTY_LIST",
|
|
1307
1292
|
"agentId array must not be empty. Omit the argument to activate all compatible agents."
|
|
1308
1293
|
);
|
|
1309
1294
|
}
|
|
@@ -1325,27 +1310,22 @@ var OwneySDK = class {
|
|
|
1325
1310
|
state.chainId = chainId;
|
|
1326
1311
|
Promise.all(
|
|
1327
1312
|
agents.map(async (agent) => {
|
|
1328
|
-
const agentStart = Date.now();
|
|
1329
1313
|
await agent.activateAgent(state, chainId);
|
|
1330
|
-
logTiming3("activateAgent background-agent-ready", agentStart, {
|
|
1331
|
-
chainId,
|
|
1332
|
-
agentId: agent.id
|
|
1333
|
-
});
|
|
1334
1314
|
})
|
|
1335
1315
|
).catch((error) => {
|
|
1336
1316
|
console.error("activateAgent background init failed:", error);
|
|
1337
1317
|
});
|
|
1338
|
-
logTiming3("activateAgent scheduled", startedAt, {
|
|
1339
|
-
chainId,
|
|
1340
|
-
agentIds: uniqueIds
|
|
1341
|
-
});
|
|
1342
1318
|
return;
|
|
1343
1319
|
}
|
|
1344
1320
|
const compatible = [...this.agents.values()].filter(
|
|
1345
1321
|
(agent) => agent.supportedChainIds.includes(chainId)
|
|
1346
1322
|
);
|
|
1347
1323
|
if (compatible.length === 0) {
|
|
1348
|
-
throw new
|
|
1324
|
+
throw new OwneyError(
|
|
1325
|
+
"CHAIN_NO_COMPATIBLE_AGENTS",
|
|
1326
|
+
`No agents support chain ${chainId}.`,
|
|
1327
|
+
{ chainId }
|
|
1328
|
+
);
|
|
1349
1329
|
}
|
|
1350
1330
|
this.activeAgents.clear();
|
|
1351
1331
|
for (const agent of compatible) {
|
|
@@ -1354,20 +1334,11 @@ var OwneySDK = class {
|
|
|
1354
1334
|
state.chainId = chainId;
|
|
1355
1335
|
Promise.all(
|
|
1356
1336
|
compatible.map(async (agent) => {
|
|
1357
|
-
const agentStart = Date.now();
|
|
1358
1337
|
await agent.activateAgent(state, chainId);
|
|
1359
|
-
logTiming3("activateAgent background-agent-ready", agentStart, {
|
|
1360
|
-
chainId,
|
|
1361
|
-
agentId: agent.id
|
|
1362
|
-
});
|
|
1363
1338
|
})
|
|
1364
1339
|
).catch((error) => {
|
|
1365
1340
|
console.error("activateAgent background init failed:", error);
|
|
1366
1341
|
});
|
|
1367
|
-
logTiming3("activateAgent scheduled", startedAt, {
|
|
1368
|
-
chainId,
|
|
1369
|
-
agentIds: compatible.map((agent) => agent.id)
|
|
1370
|
-
});
|
|
1371
1342
|
}
|
|
1372
1343
|
/**
|
|
1373
1344
|
* Deposit funds into a specific agent, or split equally across all agents if agentId is omitted.
|
|
@@ -1393,8 +1364,10 @@ var OwneySDK = class {
|
|
|
1393
1364
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
1394
1365
|
const totalAmount = BigInt(amount);
|
|
1395
1366
|
if (totalAmount < BigInt(eligibleAgents.length)) {
|
|
1396
|
-
throw new
|
|
1397
|
-
|
|
1367
|
+
throw new OwneyError(
|
|
1368
|
+
"DEPOSIT_AMOUNT_TOO_SMALL",
|
|
1369
|
+
`Amount "${amount}" is too small to split across ${eligibleAgents.length} agents.`,
|
|
1370
|
+
{ amount, agentCount: eligibleAgents.length }
|
|
1398
1371
|
);
|
|
1399
1372
|
}
|
|
1400
1373
|
const perAgent = totalAmount / BigInt(eligibleAgents.length);
|
|
@@ -1417,8 +1390,10 @@ var OwneySDK = class {
|
|
|
1417
1390
|
(sa) => sa.chainId === chainId
|
|
1418
1391
|
);
|
|
1419
1392
|
if (!chainAssets || !chainAssets.assets.includes(asset)) {
|
|
1420
|
-
throw new
|
|
1421
|
-
|
|
1393
|
+
throw new OwneyError(
|
|
1394
|
+
"ASSET_UNSUPPORTED",
|
|
1395
|
+
`Agent "${agent.id}" does not support asset "${asset}" on chain ${chainId}.`,
|
|
1396
|
+
{ agentId: agent.id, asset, chainId }
|
|
1422
1397
|
);
|
|
1423
1398
|
}
|
|
1424
1399
|
}
|
|
@@ -1430,8 +1405,10 @@ var OwneySDK = class {
|
|
|
1430
1405
|
return chainAssets && chainAssets.assets.includes(asset);
|
|
1431
1406
|
});
|
|
1432
1407
|
if (eligible.length === 0) {
|
|
1433
|
-
throw new
|
|
1434
|
-
|
|
1408
|
+
throw new OwneyError(
|
|
1409
|
+
"ASSET_NO_COMPATIBLE_AGENTS",
|
|
1410
|
+
`No agents support asset "${asset}" on chain ${chainId}.`,
|
|
1411
|
+
{ asset, chainId }
|
|
1435
1412
|
);
|
|
1436
1413
|
}
|
|
1437
1414
|
return eligible;
|
|
@@ -1456,10 +1433,25 @@ var OwneySDK = class {
|
|
|
1456
1433
|
return agent.withdraw(state, chainId, amount);
|
|
1457
1434
|
}
|
|
1458
1435
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
1436
|
+
if (!amount) {
|
|
1437
|
+
const results2 = {};
|
|
1438
|
+
for (const agent of eligibleAgents) {
|
|
1439
|
+
results2[agent.id] = await agent.withdraw(state, chainId);
|
|
1440
|
+
}
|
|
1441
|
+
return { agentResult: results2 };
|
|
1442
|
+
}
|
|
1459
1443
|
const results = {};
|
|
1444
|
+
let lastError;
|
|
1460
1445
|
for (const agent of eligibleAgents) {
|
|
1461
|
-
|
|
1446
|
+
try {
|
|
1447
|
+
results[agent.id] = await agent.withdraw(state, chainId, amount);
|
|
1448
|
+
return { agentResult: results };
|
|
1449
|
+
} catch (err) {
|
|
1450
|
+
lastError = err;
|
|
1451
|
+
}
|
|
1462
1452
|
}
|
|
1453
|
+
if (lastError)
|
|
1454
|
+
throw lastError;
|
|
1463
1455
|
return {
|
|
1464
1456
|
agentResult: results
|
|
1465
1457
|
};
|
|
@@ -1471,12 +1463,10 @@ var OwneySDK = class {
|
|
|
1471
1463
|
* @returns {AgentBalance} for a single agent, or {OwneyBalances} with totalBalance and per-agent breakdown
|
|
1472
1464
|
*/
|
|
1473
1465
|
async getBalances(agentId) {
|
|
1474
|
-
const startedAt = Date.now();
|
|
1475
1466
|
const state = this.requireState();
|
|
1476
1467
|
const chainId = this.requireChainId();
|
|
1477
1468
|
if (agentId) {
|
|
1478
1469
|
const result = await this.getAgent(agentId).getBalances(state, chainId);
|
|
1479
|
-
logTiming3("getBalances single-agent", startedAt, { chainId, agentId });
|
|
1480
1470
|
return result;
|
|
1481
1471
|
}
|
|
1482
1472
|
let totalBalance = 0;
|
|
@@ -1484,12 +1474,7 @@ var OwneySDK = class {
|
|
|
1484
1474
|
const entries = [...this.getActiveAgents().entries()];
|
|
1485
1475
|
const balanceResults = await Promise.allSettled(
|
|
1486
1476
|
entries.map(async ([id, agent]) => {
|
|
1487
|
-
const agentStartedAt = Date.now();
|
|
1488
1477
|
const b = await agent.getBalances(state, chainId);
|
|
1489
|
-
logTiming3("getBalances per-agent", agentStartedAt, {
|
|
1490
|
-
chainId,
|
|
1491
|
-
agentId: id
|
|
1492
|
-
});
|
|
1493
1478
|
return [id, b];
|
|
1494
1479
|
})
|
|
1495
1480
|
);
|
|
@@ -1505,13 +1490,11 @@ var OwneySDK = class {
|
|
|
1505
1490
|
console.error("getBalances agent failed:", settledResult.reason);
|
|
1506
1491
|
}
|
|
1507
1492
|
if (successCount === 0) {
|
|
1508
|
-
throw new
|
|
1493
|
+
throw new OwneyError(
|
|
1494
|
+
"BALANCE_ALL_FAILED",
|
|
1495
|
+
"Failed to fetch balances for all active agents."
|
|
1496
|
+
);
|
|
1509
1497
|
}
|
|
1510
|
-
logTiming3("getBalances aggregate", startedAt, {
|
|
1511
|
-
chainId,
|
|
1512
|
-
totalAgents: entries.length,
|
|
1513
|
-
successCount
|
|
1514
|
-
});
|
|
1515
1498
|
return {
|
|
1516
1499
|
totalBalance: String(totalBalance),
|
|
1517
1500
|
agentBalances: results
|
|
@@ -1747,7 +1730,10 @@ var OwneySDK = class {
|
|
|
1747
1730
|
}
|
|
1748
1731
|
}
|
|
1749
1732
|
if (successCount === 0) {
|
|
1750
|
-
throw new
|
|
1733
|
+
throw new OwneyError(
|
|
1734
|
+
"ALLOCATION_ALL_FAILED",
|
|
1735
|
+
"Failed to fetch allocation: all agents failed."
|
|
1736
|
+
);
|
|
1751
1737
|
}
|
|
1752
1738
|
const allocation = {};
|
|
1753
1739
|
if (totalBalance === 0) {
|
|
@@ -1775,5 +1761,6 @@ export {
|
|
|
1775
1761
|
AgentChainIncompatibleError,
|
|
1776
1762
|
AgentNotFoundError,
|
|
1777
1763
|
NotConnectedError,
|
|
1764
|
+
OwneyError,
|
|
1778
1765
|
OwneySDK
|
|
1779
1766
|
};
|