@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.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(src_exports, {
|
|
|
23
23
|
AgentChainIncompatibleError: () => AgentChainIncompatibleError,
|
|
24
24
|
AgentNotFoundError: () => AgentNotFoundError,
|
|
25
25
|
NotConnectedError: () => NotConnectedError,
|
|
26
|
+
OwneyError: () => OwneyError,
|
|
26
27
|
OwneySDK: () => OwneySDK
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -55,11 +56,58 @@ var SupportedAssets = [
|
|
|
55
56
|
}
|
|
56
57
|
];
|
|
57
58
|
|
|
59
|
+
// src/errors.ts
|
|
60
|
+
var OwneyError = class extends Error {
|
|
61
|
+
code;
|
|
62
|
+
details;
|
|
63
|
+
constructor(code, message, details) {
|
|
64
|
+
super(message);
|
|
65
|
+
this.name = "OwneyError";
|
|
66
|
+
this.code = code;
|
|
67
|
+
this.details = details;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var AgentNotFoundError = class extends OwneyError {
|
|
71
|
+
constructor(agentId, available) {
|
|
72
|
+
super(
|
|
73
|
+
"AGENT_NOT_FOUND",
|
|
74
|
+
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
75
|
+
{ agentId, available }
|
|
76
|
+
);
|
|
77
|
+
this.name = "AgentNotFoundError";
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var NotConnectedError = class extends OwneyError {
|
|
81
|
+
constructor() {
|
|
82
|
+
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
83
|
+
this.name = "NotConnectedError";
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var AgentChainIncompatibleError = class extends OwneyError {
|
|
87
|
+
incompatibleAgents;
|
|
88
|
+
connectedChainId;
|
|
89
|
+
constructor(incompatibleAgents, connectedChainId) {
|
|
90
|
+
const details = incompatibleAgents.map(
|
|
91
|
+
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
92
|
+
).join("; ");
|
|
93
|
+
super(
|
|
94
|
+
"AGENT_CHAIN_INCOMPATIBLE",
|
|
95
|
+
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
96
|
+
{ incompatibleAgents, connectedChainId }
|
|
97
|
+
);
|
|
98
|
+
this.name = "AgentChainIncompatibleError";
|
|
99
|
+
this.incompatibleAgents = incompatibleAgents;
|
|
100
|
+
this.connectedChainId = connectedChainId;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
58
104
|
// src/lib/utils.ts
|
|
59
105
|
var isValidChainId = (chainId) => {
|
|
60
106
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
61
|
-
throw new
|
|
62
|
-
|
|
107
|
+
throw new OwneyError(
|
|
108
|
+
"CHAIN_UNSUPPORTED",
|
|
109
|
+
`Unsupported chain ID: ${chainId}. Supported chains: ${SUPPORTED_CHAIN_IDS.join(", ")}`,
|
|
110
|
+
{ chainId, supportedChainIds: [...SUPPORTED_CHAIN_IDS] }
|
|
63
111
|
);
|
|
64
112
|
}
|
|
65
113
|
return chainId;
|
|
@@ -74,6 +122,15 @@ function hexToDecimal(hex, decimals = 6) {
|
|
|
74
122
|
const remainder = parsed % divisor;
|
|
75
123
|
return Number(whole) + Number(remainder) / Number(divisor);
|
|
76
124
|
}
|
|
125
|
+
function normalizeDecimalPlace(value, decimals = 6) {
|
|
126
|
+
const parsed = BigInt(value);
|
|
127
|
+
if (decimals <= 0)
|
|
128
|
+
return Number(parsed);
|
|
129
|
+
const divisor = BigInt(10 ** decimals);
|
|
130
|
+
const whole = parsed / divisor;
|
|
131
|
+
const remainder = parsed % divisor;
|
|
132
|
+
return Number(whole) + Number(remainder) / Number(divisor);
|
|
133
|
+
}
|
|
77
134
|
var DayFilterMapping = {
|
|
78
135
|
"30D": 30,
|
|
79
136
|
"14D": 14,
|
|
@@ -103,7 +160,7 @@ var CHAIN_NAME_TO_ID = {
|
|
|
103
160
|
BASE: 8453,
|
|
104
161
|
ARBITRUM: 42161
|
|
105
162
|
};
|
|
106
|
-
function mapBalances(raw, chainId) {
|
|
163
|
+
function mapBalances(raw, chainId, smartWallet) {
|
|
107
164
|
const portfolio = raw.portfolio;
|
|
108
165
|
const tokenMap = /* @__PURE__ */ new Map();
|
|
109
166
|
for (const p of portfolio.positions || []) {
|
|
@@ -114,18 +171,7 @@ function mapBalances(raw, chainId) {
|
|
|
114
171
|
tokenMap.set(key, {
|
|
115
172
|
symbol,
|
|
116
173
|
chainId: positionChainId,
|
|
117
|
-
amount: (current?.amount ?? 0) +
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
for (const s of portfolio.staleBalances || []) {
|
|
121
|
-
const symbol = s.tokenSymbol || "USDC";
|
|
122
|
-
const staleChainId = s.chainId ?? chainId;
|
|
123
|
-
const key = `${symbol}:${staleChainId}`;
|
|
124
|
-
const current = tokenMap.get(key);
|
|
125
|
-
tokenMap.set(key, {
|
|
126
|
-
symbol,
|
|
127
|
-
chainId: staleChainId,
|
|
128
|
-
amount: (current?.amount ?? 0) + hexToDecimal(s.balance || "0")
|
|
174
|
+
amount: (current?.amount ?? 0) + normalizeDecimalPlace(p.underlyingAmount || "0")
|
|
129
175
|
});
|
|
130
176
|
}
|
|
131
177
|
let totalBalance = 0;
|
|
@@ -140,7 +186,7 @@ function mapBalances(raw, chainId) {
|
|
|
140
186
|
});
|
|
141
187
|
}
|
|
142
188
|
return {
|
|
143
|
-
smartWallet
|
|
189
|
+
smartWallet,
|
|
144
190
|
totalBalance: String(totalBalance),
|
|
145
191
|
tokens
|
|
146
192
|
};
|
|
@@ -257,15 +303,6 @@ function mapApyByStrategy(raw) {
|
|
|
257
303
|
}
|
|
258
304
|
|
|
259
305
|
// 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
|
-
}
|
|
269
306
|
var ZyfaiAgent = class {
|
|
270
307
|
id = "zyfai";
|
|
271
308
|
supportedChainIds = [8453, 42161];
|
|
@@ -286,29 +323,27 @@ var ZyfaiAgent = class {
|
|
|
286
323
|
connectedChainId = null;
|
|
287
324
|
smartWalletCache = /* @__PURE__ */ new Map();
|
|
288
325
|
connectAuthPromise = null;
|
|
289
|
-
constructor(apiKey) {
|
|
290
|
-
this.sdk = new import_sdk.ZyfaiSDK({ apiKey });
|
|
326
|
+
constructor(apiKey, rpcUrls) {
|
|
327
|
+
this.sdk = new import_sdk.ZyfaiSDK({ apiKey, rpcUrls });
|
|
291
328
|
}
|
|
292
329
|
// --- Private helpers ---
|
|
293
330
|
getAddress() {
|
|
294
331
|
if (!this.connectedAddress) {
|
|
295
|
-
throw new
|
|
332
|
+
throw new OwneyError(
|
|
333
|
+
"NOT_CONNECTED",
|
|
334
|
+
"Wallet not connected. Call sdk.connect() first."
|
|
335
|
+
);
|
|
296
336
|
}
|
|
297
337
|
return this.connectedAddress;
|
|
298
338
|
}
|
|
299
339
|
/** Light connect: SIWE auth only. Re-auths if chain changed. */
|
|
300
340
|
async connectAuth(state, chainId) {
|
|
301
|
-
const startedAt = Date.now();
|
|
302
341
|
const validChainId = isValidChainId(chainId);
|
|
303
342
|
if (this.connectedAddress && this.connectedChainId === validChainId) {
|
|
304
|
-
logTiming("connectAuth cache-hit", startedAt, { chainId: validChainId });
|
|
305
343
|
return;
|
|
306
344
|
}
|
|
307
345
|
if (this.connectAuthPromise) {
|
|
308
346
|
await this.connectAuthPromise;
|
|
309
|
-
logTiming("connectAuth awaited-inflight", startedAt, {
|
|
310
|
-
chainId: validChainId
|
|
311
|
-
});
|
|
312
347
|
return;
|
|
313
348
|
}
|
|
314
349
|
this.connectAuthPromise = (async () => {
|
|
@@ -321,69 +356,40 @@ var ZyfaiAgent = class {
|
|
|
321
356
|
})();
|
|
322
357
|
try {
|
|
323
358
|
await this.connectAuthPromise;
|
|
324
|
-
logTiming("connectAuth success", startedAt, { chainId: validChainId });
|
|
325
359
|
} finally {
|
|
326
360
|
this.connectAuthPromise = null;
|
|
327
361
|
}
|
|
328
362
|
}
|
|
329
363
|
/** Full connect: SIWE auth + Safe deploy check + session key. */
|
|
330
364
|
async connectFull(state, chainId) {
|
|
331
|
-
const startedAt = Date.now();
|
|
332
365
|
await this.connectAuth(state, chainId);
|
|
333
366
|
const validChainId = isValidChainId(chainId);
|
|
334
367
|
const address = this.getAddress();
|
|
335
|
-
const walletLookupStart = Date.now();
|
|
336
368
|
const wallet = await this.sdk.getSmartWalletAddress(address, validChainId);
|
|
337
|
-
logTiming("connectFull getSmartWalletAddress", walletLookupStart, {
|
|
338
|
-
chainId: validChainId
|
|
339
|
-
});
|
|
340
369
|
this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
|
|
341
370
|
if (!wallet.isDeployed) {
|
|
342
|
-
const deployStart = Date.now();
|
|
343
371
|
await this.sdk.deploySafe(address, validChainId, "aggressive", true);
|
|
344
|
-
logTiming("connectFull deploySafe", deployStart, {
|
|
345
|
-
chainId: validChainId
|
|
346
|
-
});
|
|
347
372
|
}
|
|
348
|
-
const userDetailsStart = Date.now();
|
|
349
373
|
const user = await this.sdk.getUserDetails();
|
|
350
|
-
logTiming("connectFull getUserDetails", userDetailsStart, {
|
|
351
|
-
chainId: validChainId
|
|
352
|
-
});
|
|
353
374
|
if (!user.hasActiveSessionKey) {
|
|
354
|
-
const sessionKeyStart = Date.now();
|
|
355
375
|
await this.sdk.createSessionKey(address, validChainId);
|
|
356
|
-
logTiming("connectFull createSessionKey", sessionKeyStart, {
|
|
357
|
-
chainId: validChainId
|
|
358
|
-
});
|
|
359
376
|
}
|
|
360
|
-
logTiming("connectFull success", startedAt, { chainId: validChainId });
|
|
361
377
|
}
|
|
362
378
|
/** Connect + resolve smart wallet address for read operations. */
|
|
363
379
|
async resolveSmartWallet(state, chainId) {
|
|
364
|
-
const startedAt = Date.now();
|
|
365
380
|
await this.connectAuth(state, chainId);
|
|
366
381
|
const validChainId = isValidChainId(chainId);
|
|
367
382
|
const ownerAddress = this.getAddress();
|
|
368
383
|
const cacheKey = `${ownerAddress}_${validChainId}`;
|
|
369
384
|
let smartWallet = this.smartWalletCache.get(cacheKey);
|
|
370
385
|
if (!smartWallet) {
|
|
371
|
-
const lookupStart = Date.now();
|
|
372
386
|
const { address } = await this.sdk.getSmartWalletAddress(
|
|
373
387
|
ownerAddress,
|
|
374
388
|
validChainId
|
|
375
389
|
);
|
|
376
|
-
logTiming("resolveSmartWallet remote-lookup", lookupStart, {
|
|
377
|
-
chainId: validChainId
|
|
378
|
-
});
|
|
379
390
|
smartWallet = address;
|
|
380
391
|
this.smartWalletCache.set(cacheKey, smartWallet);
|
|
381
|
-
} else {
|
|
382
|
-
logTiming("resolveSmartWallet cache-hit", startedAt, {
|
|
383
|
-
chainId: validChainId
|
|
384
|
-
});
|
|
385
392
|
}
|
|
386
|
-
logTiming("resolveSmartWallet ready", startedAt, { chainId: validChainId });
|
|
387
393
|
return { smartWallet, chainId: validChainId };
|
|
388
394
|
}
|
|
389
395
|
// --- IAgent: Connection lifecycle ---
|
|
@@ -443,16 +449,9 @@ var ZyfaiAgent = class {
|
|
|
443
449
|
}
|
|
444
450
|
// --- IAgent: Portfolio reads ---
|
|
445
451
|
async getBalances(state, chainId) {
|
|
446
|
-
const
|
|
447
|
-
await this.
|
|
448
|
-
|
|
449
|
-
const positionsStart = Date.now();
|
|
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 });
|
|
455
|
-
return mapBalances(raw, validChainId);
|
|
452
|
+
const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
|
|
453
|
+
const raw = await this.sdk.getPortfolio(this.getAddress());
|
|
454
|
+
return mapBalances(raw, validChainId, smartWallet);
|
|
456
455
|
}
|
|
457
456
|
async getEarnings(state, chainId) {
|
|
458
457
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
@@ -516,13 +515,13 @@ function mapWithdraw2(raw) {
|
|
|
516
515
|
function mapPortfolioBalances(raw, smartWallet) {
|
|
517
516
|
let total = 0;
|
|
518
517
|
const tokens = [];
|
|
519
|
-
for (const item of raw.
|
|
520
|
-
total += item.
|
|
518
|
+
for (const item of raw.tokens) {
|
|
519
|
+
total += item.balanceFormatted;
|
|
521
520
|
tokens.push({
|
|
522
|
-
chain: item.chain
|
|
523
|
-
chainId: item.
|
|
524
|
-
asset: item.
|
|
525
|
-
amount:
|
|
521
|
+
chain: SUPPORTED_CHAINS[item.chain],
|
|
522
|
+
chainId: item.chain,
|
|
523
|
+
asset: item.symbol === "USD\u20AE0" ? "USDT" : item.symbol,
|
|
524
|
+
amount: item.balance
|
|
526
525
|
});
|
|
527
526
|
}
|
|
528
527
|
return {
|
|
@@ -705,16 +704,7 @@ function remapApyPerAssetToSymbols(raw) {
|
|
|
705
704
|
var SAIL_API_BASE = "https://app.sail.money";
|
|
706
705
|
var PROJECT_ID = "sail";
|
|
707
706
|
var PAGE_ID = "home";
|
|
708
|
-
var SAIL_TIMING_PREFIX = "[AgentTiming][sail]";
|
|
709
707
|
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
|
-
}
|
|
718
708
|
var SailAgent = class {
|
|
719
709
|
id = "sail";
|
|
720
710
|
supportedChainIds = [8453, 42161];
|
|
@@ -764,7 +754,11 @@ var SailAgent = class {
|
|
|
764
754
|
});
|
|
765
755
|
} catch (error) {
|
|
766
756
|
if (error instanceof Error && error.name === "AbortError" && timeoutMs) {
|
|
767
|
-
throw new
|
|
757
|
+
throw new OwneyError(
|
|
758
|
+
"API_SAIL_TIMEOUT",
|
|
759
|
+
`Sail API timeout ${timeoutMs}ms: ${method} ${path}`,
|
|
760
|
+
{ timeoutMs, method, path }
|
|
761
|
+
);
|
|
768
762
|
}
|
|
769
763
|
throw error;
|
|
770
764
|
} finally {
|
|
@@ -773,13 +767,16 @@ var SailAgent = class {
|
|
|
773
767
|
}
|
|
774
768
|
if (!res.ok) {
|
|
775
769
|
const text = await res.text().catch(() => "");
|
|
776
|
-
throw new
|
|
770
|
+
throw new OwneyError(
|
|
771
|
+
"API_SAIL_ERROR",
|
|
772
|
+
`Sail API error ${res.status}: ${text}`,
|
|
773
|
+
{ statusCode: res.status, method, path, responseBody: text }
|
|
774
|
+
);
|
|
777
775
|
}
|
|
778
776
|
return res.json();
|
|
779
777
|
}
|
|
780
778
|
/** Initiate SIWE and sign with the user's wallet. */
|
|
781
779
|
async signSiwe(state, chainId) {
|
|
782
|
-
const startedAt = Date.now();
|
|
783
780
|
const initiate = await this.request(
|
|
784
781
|
"POST",
|
|
785
782
|
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/auth/initiate`,
|
|
@@ -794,7 +791,6 @@ var SailAgent = class {
|
|
|
794
791
|
method: "personal_sign",
|
|
795
792
|
params: [initiate.message, state.walletAddress]
|
|
796
793
|
});
|
|
797
|
-
logTiming2("signSiwe success", startedAt, { chainId });
|
|
798
794
|
return {
|
|
799
795
|
sessionId: initiate.sessionId,
|
|
800
796
|
message: initiate.message,
|
|
@@ -803,18 +799,18 @@ var SailAgent = class {
|
|
|
803
799
|
}
|
|
804
800
|
/** Full connect: auth handles smart account creation via SIWE flow. */
|
|
805
801
|
async connectFull(state, chainId) {
|
|
806
|
-
const startedAt = Date.now();
|
|
807
802
|
if (this.connectedAddress && this.connectedChainId === chainId) {
|
|
808
|
-
logTiming2("connectFull cache-hit", startedAt, { chainId });
|
|
809
803
|
return;
|
|
810
804
|
}
|
|
811
805
|
if (this.connectPromise) {
|
|
812
806
|
await this.connectPromise;
|
|
813
|
-
logTiming2("connectFull awaited-inflight", startedAt, { chainId });
|
|
814
807
|
return;
|
|
815
808
|
}
|
|
816
809
|
if (!state.walletAddress) {
|
|
817
|
-
throw new
|
|
810
|
+
throw new OwneyError(
|
|
811
|
+
"WALLET_ADDRESS_REQUIRED",
|
|
812
|
+
"Wallet address is required. Call sdk.connect(provider) first."
|
|
813
|
+
);
|
|
818
814
|
}
|
|
819
815
|
this.connectPromise = (async () => {
|
|
820
816
|
const { sessionId, signature, message } = await this.signSiwe(
|
|
@@ -840,19 +836,19 @@ var SailAgent = class {
|
|
|
840
836
|
})();
|
|
841
837
|
try {
|
|
842
838
|
await this.connectPromise;
|
|
843
|
-
logTiming2("connectFull success", startedAt, { chainId });
|
|
844
839
|
} finally {
|
|
845
840
|
this.connectPromise = null;
|
|
846
841
|
}
|
|
847
842
|
}
|
|
848
843
|
async resolveSmartWallet(state, chainId) {
|
|
849
|
-
const startedAt = Date.now();
|
|
850
844
|
await this.connectFull(state, chainId);
|
|
851
845
|
const validChainId = isValidChainId(chainId);
|
|
852
846
|
if (!this.smartWalletAddress) {
|
|
853
|
-
throw new
|
|
847
|
+
throw new OwneyError(
|
|
848
|
+
"NOT_CONNECTED",
|
|
849
|
+
"Wallet not connected. Call sdk.connect() first."
|
|
850
|
+
);
|
|
854
851
|
}
|
|
855
|
-
logTiming2("resolveSmartWallet ready", startedAt, { chainId: validChainId });
|
|
856
852
|
return {
|
|
857
853
|
smartWallet: this.smartWalletAddress,
|
|
858
854
|
chainId: validChainId
|
|
@@ -877,7 +873,8 @@ var SailAgent = class {
|
|
|
877
873
|
}
|
|
878
874
|
async deposit(state, chainId, amount, depositCallback) {
|
|
879
875
|
if (!depositCallback) {
|
|
880
|
-
throw new
|
|
876
|
+
throw new OwneyError(
|
|
877
|
+
"DEPOSIT_CALLBACK_REQUIRED",
|
|
881
878
|
"depositCallback is required for Sail. Provide a callback that transfers tokens and returns the transaction hash."
|
|
882
879
|
);
|
|
883
880
|
}
|
|
@@ -886,12 +883,16 @@ var SailAgent = class {
|
|
|
886
883
|
const depositInfo = await this.getDepositInfo();
|
|
887
884
|
const resolvedTokenAddress = depositInfo.permittedTokens[0]?.address;
|
|
888
885
|
if (!resolvedTokenAddress) {
|
|
889
|
-
throw new
|
|
886
|
+
throw new OwneyError(
|
|
887
|
+
"DEPOSIT_NO_PERMITTED_TOKENS",
|
|
888
|
+
"No permitted tokens available for deposit."
|
|
889
|
+
);
|
|
890
890
|
}
|
|
891
891
|
await this.executePreHooks(resolvedTokenAddress, amount, chainId);
|
|
892
892
|
const txHash = await depositCallback(smartWallet, chainId, amount);
|
|
893
893
|
if (!txHash) {
|
|
894
|
-
throw new
|
|
894
|
+
throw new OwneyError(
|
|
895
|
+
"DEPOSIT_CALLBACK_INVALID",
|
|
895
896
|
"depositCallback must return a transaction hash (txHash) for Sail deposits."
|
|
896
897
|
);
|
|
897
898
|
}
|
|
@@ -945,7 +946,10 @@ var SailAgent = class {
|
|
|
945
946
|
const withdrawInfo = await this.getWithdrawInfo();
|
|
946
947
|
const tokenAddress = withdrawInfo.permittedTokens[0]?.address;
|
|
947
948
|
if (!tokenAddress) {
|
|
948
|
-
throw new
|
|
949
|
+
throw new OwneyError(
|
|
950
|
+
"WITHDRAW_NO_PERMITTED_TOKENS",
|
|
951
|
+
"No permitted tokens available for withdrawal."
|
|
952
|
+
);
|
|
949
953
|
}
|
|
950
954
|
const resolvedAmount = amount ?? withdrawInfo.currentBalance;
|
|
951
955
|
const { signature: adminWalletSignature, message: adminWalletPayload } = await this.signSiwe(state, chainId);
|
|
@@ -969,25 +973,20 @@ var SailAgent = class {
|
|
|
969
973
|
}
|
|
970
974
|
// --- IAgent: Portfolio reads ---
|
|
971
975
|
async getBalances(state, chainId) {
|
|
972
|
-
const startedAt = Date.now();
|
|
973
976
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
974
|
-
const portfolioStart = Date.now();
|
|
975
977
|
try {
|
|
976
|
-
const raw = await this.
|
|
977
|
-
logTiming2("getBalances getMetricsPortfolio", portfolioStart, { chainId });
|
|
978
|
-
logTiming2("getBalances success", startedAt, { chainId });
|
|
978
|
+
const raw = await this.getPortfolio();
|
|
979
979
|
return mapPortfolioBalances(raw, smartWallet);
|
|
980
980
|
} catch (error) {
|
|
981
|
-
if (error instanceof
|
|
981
|
+
if (error instanceof OwneyError && error.code === "API_SAIL_TIMEOUT") {
|
|
982
982
|
console.warn(
|
|
983
983
|
"Sail portfolio request timed out; using empty snapshot.",
|
|
984
984
|
{
|
|
985
985
|
chainId
|
|
986
986
|
}
|
|
987
987
|
);
|
|
988
|
-
logTiming2("getBalances timeout-fallback", startedAt, { chainId });
|
|
989
988
|
return mapPortfolioBalances(
|
|
990
|
-
{ message: "timeout",
|
|
989
|
+
{ message: "timeout", tokens: [] },
|
|
991
990
|
smartWallet
|
|
992
991
|
);
|
|
993
992
|
}
|
|
@@ -1018,6 +1017,14 @@ var SailAgent = class {
|
|
|
1018
1017
|
SAIL_PORTFOLIO_TIMEOUT_MS
|
|
1019
1018
|
);
|
|
1020
1019
|
}
|
|
1020
|
+
async getPortfolio() {
|
|
1021
|
+
return this.request(
|
|
1022
|
+
"GET",
|
|
1023
|
+
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/portfolio/tokens`,
|
|
1024
|
+
void 0,
|
|
1025
|
+
SAIL_PORTFOLIO_TIMEOUT_MS
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1021
1028
|
async getMetricsEarnings(state, chainId) {
|
|
1022
1029
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1023
1030
|
return this.request(
|
|
@@ -1025,7 +1032,7 @@ var SailAgent = class {
|
|
|
1025
1032
|
`/api/v1/projects/${PROJECT_ID}/pages/${PAGE_ID}/metrics/earnings?smart_account=${smartWallet}`
|
|
1026
1033
|
);
|
|
1027
1034
|
}
|
|
1028
|
-
async getMetricsBalance(state, chainId, currency) {
|
|
1035
|
+
async getMetricsBalance(state, chainId, currency = "usd") {
|
|
1029
1036
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1030
1037
|
return this.request(
|
|
1031
1038
|
"GET",
|
|
@@ -1062,8 +1069,10 @@ var SailAgent = class {
|
|
|
1062
1069
|
}
|
|
1063
1070
|
const dayCount = DayFilterMapping[days];
|
|
1064
1071
|
if (dayCount === void 0) {
|
|
1065
|
-
throw new
|
|
1066
|
-
|
|
1072
|
+
throw new OwneyError(
|
|
1073
|
+
"VALIDATION_INVALID_DAYS",
|
|
1074
|
+
`Invalid days value: "${days}". Expected one of: "7D", "14D", "30D".`,
|
|
1075
|
+
{ days }
|
|
1067
1076
|
);
|
|
1068
1077
|
}
|
|
1069
1078
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -1140,37 +1149,6 @@ var SailAgent = class {
|
|
|
1140
1149
|
}
|
|
1141
1150
|
};
|
|
1142
1151
|
|
|
1143
|
-
// src/errors.ts
|
|
1144
|
-
var AgentNotFoundError = class extends Error {
|
|
1145
|
-
constructor(agentId, available) {
|
|
1146
|
-
super(
|
|
1147
|
-
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`
|
|
1148
|
-
);
|
|
1149
|
-
this.name = "AgentNotFoundError";
|
|
1150
|
-
}
|
|
1151
|
-
};
|
|
1152
|
-
var NotConnectedError = class extends Error {
|
|
1153
|
-
constructor() {
|
|
1154
|
-
super("Not connected. Call sdk.connect(provider) first.");
|
|
1155
|
-
this.name = "NotConnectedError";
|
|
1156
|
-
}
|
|
1157
|
-
};
|
|
1158
|
-
var AgentChainIncompatibleError = class extends Error {
|
|
1159
|
-
incompatibleAgents;
|
|
1160
|
-
connectedChainId;
|
|
1161
|
-
constructor(incompatibleAgents, connectedChainId) {
|
|
1162
|
-
const details = incompatibleAgents.map(
|
|
1163
|
-
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
1164
|
-
).join("; ");
|
|
1165
|
-
super(
|
|
1166
|
-
`Chain ${connectedChainId} is not supported by the following agents: ${details}`
|
|
1167
|
-
);
|
|
1168
|
-
this.name = "AgentChainIncompatibleError";
|
|
1169
|
-
this.incompatibleAgents = incompatibleAgents;
|
|
1170
|
-
this.connectedChainId = connectedChainId;
|
|
1171
|
-
}
|
|
1172
|
-
};
|
|
1173
|
-
|
|
1174
1152
|
// src/lib/routing-api.ts
|
|
1175
1153
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1176
1154
|
async function fetchAgentKeys(apiKey) {
|
|
@@ -1184,37 +1162,34 @@ async function fetchAgentKeys(apiKey) {
|
|
|
1184
1162
|
});
|
|
1185
1163
|
if (!res.ok) {
|
|
1186
1164
|
const text = await res.text().catch(() => "");
|
|
1187
|
-
throw new
|
|
1165
|
+
throw new OwneyError(
|
|
1166
|
+
"API_ROUTING_ERROR",
|
|
1167
|
+
`Routing API error ${res.status}: ${text}`,
|
|
1168
|
+
{ statusCode: res.status, responseBody: text }
|
|
1169
|
+
);
|
|
1188
1170
|
}
|
|
1189
1171
|
const json = await res.json();
|
|
1190
1172
|
if (!json.success) {
|
|
1191
|
-
throw new
|
|
1173
|
+
throw new OwneyError(
|
|
1174
|
+
"API_ROUTING_FAILED",
|
|
1175
|
+
`Routing API request failed: ${json.message}`,
|
|
1176
|
+
{ message: json.message }
|
|
1177
|
+
);
|
|
1192
1178
|
}
|
|
1193
1179
|
return json.data;
|
|
1194
1180
|
}
|
|
1195
1181
|
|
|
1196
1182
|
// src/client.ts
|
|
1197
|
-
var AGENT_CONSTRUCTORS = {
|
|
1198
|
-
zyfai: ZyfaiAgent,
|
|
1199
|
-
sail: SailAgent
|
|
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
|
-
}
|
|
1210
1183
|
var OwneySDK = class {
|
|
1211
1184
|
agents = /* @__PURE__ */ new Map();
|
|
1212
1185
|
activeAgents = /* @__PURE__ */ new Set();
|
|
1213
1186
|
state = null;
|
|
1214
1187
|
apiKey;
|
|
1188
|
+
zyfaiRpcUrls;
|
|
1215
1189
|
initializingAgentsPromise = null;
|
|
1216
1190
|
constructor(config) {
|
|
1217
1191
|
this.apiKey = config.apiKey;
|
|
1192
|
+
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
1218
1193
|
}
|
|
1219
1194
|
/**
|
|
1220
1195
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -1228,7 +1203,8 @@ var OwneySDK = class {
|
|
|
1228
1203
|
});
|
|
1229
1204
|
const walletAddress = accounts[0];
|
|
1230
1205
|
if (!walletAddress) {
|
|
1231
|
-
throw new
|
|
1206
|
+
throw new OwneyError(
|
|
1207
|
+
"WALLET_NO_ACCOUNTS",
|
|
1232
1208
|
"No accounts found. Ensure the wallet is unlocked and connected."
|
|
1233
1209
|
);
|
|
1234
1210
|
}
|
|
@@ -1267,7 +1243,8 @@ var OwneySDK = class {
|
|
|
1267
1243
|
requireChainId() {
|
|
1268
1244
|
const chainId = this.state?.chainId ?? null;
|
|
1269
1245
|
if (chainId === null) {
|
|
1270
|
-
throw new
|
|
1246
|
+
throw new OwneyError(
|
|
1247
|
+
"NO_ACTIVE_CHAIN",
|
|
1271
1248
|
"No active chain. Call sdk.activateAgent(chainId) first."
|
|
1272
1249
|
);
|
|
1273
1250
|
}
|
|
@@ -1296,14 +1273,14 @@ var OwneySDK = class {
|
|
|
1296
1273
|
this.initializingAgentsPromise = (async () => {
|
|
1297
1274
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
1298
1275
|
for (const { key, agent_type } of agentKeys) {
|
|
1299
|
-
const
|
|
1300
|
-
if (!
|
|
1276
|
+
const agent = this.createAgent(agent_type, key);
|
|
1277
|
+
if (!agent)
|
|
1301
1278
|
continue;
|
|
1302
|
-
const agent = new AgentClass(key);
|
|
1303
1279
|
this.agents.set(agent_type, agent);
|
|
1304
1280
|
}
|
|
1305
1281
|
if (this.agents.size === 0) {
|
|
1306
|
-
throw new
|
|
1282
|
+
throw new OwneyError(
|
|
1283
|
+
"API_NO_AGENTS",
|
|
1307
1284
|
"No supported agents returned by the routing API. Check your API key and routing configuration."
|
|
1308
1285
|
);
|
|
1309
1286
|
}
|
|
@@ -1315,6 +1292,15 @@ var OwneySDK = class {
|
|
|
1315
1292
|
this.initializingAgentsPromise = null;
|
|
1316
1293
|
}
|
|
1317
1294
|
}
|
|
1295
|
+
createAgent(agentId, key) {
|
|
1296
|
+
if (agentId === "zyfai") {
|
|
1297
|
+
return new ZyfaiAgent(key, this.zyfaiRpcUrls);
|
|
1298
|
+
}
|
|
1299
|
+
if (agentId === "sail") {
|
|
1300
|
+
return new SailAgent(key);
|
|
1301
|
+
}
|
|
1302
|
+
return null;
|
|
1303
|
+
}
|
|
1318
1304
|
// --- Account lifecycle ---
|
|
1319
1305
|
/**
|
|
1320
1306
|
* Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted.
|
|
@@ -1327,12 +1313,12 @@ var OwneySDK = class {
|
|
|
1327
1313
|
* throws before activating any agent.
|
|
1328
1314
|
*/
|
|
1329
1315
|
async activateAgent(chainId, agentId) {
|
|
1330
|
-
const startedAt = Date.now();
|
|
1331
1316
|
const state = this.requireState();
|
|
1332
1317
|
await this.ensureAgentsInitialized();
|
|
1333
1318
|
if (agentId !== void 0) {
|
|
1334
1319
|
if (agentId.length === 0) {
|
|
1335
|
-
throw new
|
|
1320
|
+
throw new OwneyError(
|
|
1321
|
+
"AGENT_EMPTY_LIST",
|
|
1336
1322
|
"agentId array must not be empty. Omit the argument to activate all compatible agents."
|
|
1337
1323
|
);
|
|
1338
1324
|
}
|
|
@@ -1354,27 +1340,22 @@ var OwneySDK = class {
|
|
|
1354
1340
|
state.chainId = chainId;
|
|
1355
1341
|
Promise.all(
|
|
1356
1342
|
agents.map(async (agent) => {
|
|
1357
|
-
const agentStart = Date.now();
|
|
1358
1343
|
await agent.activateAgent(state, chainId);
|
|
1359
|
-
logTiming3("activateAgent background-agent-ready", agentStart, {
|
|
1360
|
-
chainId,
|
|
1361
|
-
agentId: agent.id
|
|
1362
|
-
});
|
|
1363
1344
|
})
|
|
1364
1345
|
).catch((error) => {
|
|
1365
1346
|
console.error("activateAgent background init failed:", error);
|
|
1366
1347
|
});
|
|
1367
|
-
logTiming3("activateAgent scheduled", startedAt, {
|
|
1368
|
-
chainId,
|
|
1369
|
-
agentIds: uniqueIds
|
|
1370
|
-
});
|
|
1371
1348
|
return;
|
|
1372
1349
|
}
|
|
1373
1350
|
const compatible = [...this.agents.values()].filter(
|
|
1374
1351
|
(agent) => agent.supportedChainIds.includes(chainId)
|
|
1375
1352
|
);
|
|
1376
1353
|
if (compatible.length === 0) {
|
|
1377
|
-
throw new
|
|
1354
|
+
throw new OwneyError(
|
|
1355
|
+
"CHAIN_NO_COMPATIBLE_AGENTS",
|
|
1356
|
+
`No agents support chain ${chainId}.`,
|
|
1357
|
+
{ chainId }
|
|
1358
|
+
);
|
|
1378
1359
|
}
|
|
1379
1360
|
this.activeAgents.clear();
|
|
1380
1361
|
for (const agent of compatible) {
|
|
@@ -1383,20 +1364,11 @@ var OwneySDK = class {
|
|
|
1383
1364
|
state.chainId = chainId;
|
|
1384
1365
|
Promise.all(
|
|
1385
1366
|
compatible.map(async (agent) => {
|
|
1386
|
-
const agentStart = Date.now();
|
|
1387
1367
|
await agent.activateAgent(state, chainId);
|
|
1388
|
-
logTiming3("activateAgent background-agent-ready", agentStart, {
|
|
1389
|
-
chainId,
|
|
1390
|
-
agentId: agent.id
|
|
1391
|
-
});
|
|
1392
1368
|
})
|
|
1393
1369
|
).catch((error) => {
|
|
1394
1370
|
console.error("activateAgent background init failed:", error);
|
|
1395
1371
|
});
|
|
1396
|
-
logTiming3("activateAgent scheduled", startedAt, {
|
|
1397
|
-
chainId,
|
|
1398
|
-
agentIds: compatible.map((agent) => agent.id)
|
|
1399
|
-
});
|
|
1400
1372
|
}
|
|
1401
1373
|
/**
|
|
1402
1374
|
* Deposit funds into a specific agent, or split equally across all agents if agentId is omitted.
|
|
@@ -1422,8 +1394,10 @@ var OwneySDK = class {
|
|
|
1422
1394
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
1423
1395
|
const totalAmount = BigInt(amount);
|
|
1424
1396
|
if (totalAmount < BigInt(eligibleAgents.length)) {
|
|
1425
|
-
throw new
|
|
1426
|
-
|
|
1397
|
+
throw new OwneyError(
|
|
1398
|
+
"DEPOSIT_AMOUNT_TOO_SMALL",
|
|
1399
|
+
`Amount "${amount}" is too small to split across ${eligibleAgents.length} agents.`,
|
|
1400
|
+
{ amount, agentCount: eligibleAgents.length }
|
|
1427
1401
|
);
|
|
1428
1402
|
}
|
|
1429
1403
|
const perAgent = totalAmount / BigInt(eligibleAgents.length);
|
|
@@ -1446,8 +1420,10 @@ var OwneySDK = class {
|
|
|
1446
1420
|
(sa) => sa.chainId === chainId
|
|
1447
1421
|
);
|
|
1448
1422
|
if (!chainAssets || !chainAssets.assets.includes(asset)) {
|
|
1449
|
-
throw new
|
|
1450
|
-
|
|
1423
|
+
throw new OwneyError(
|
|
1424
|
+
"ASSET_UNSUPPORTED",
|
|
1425
|
+
`Agent "${agent.id}" does not support asset "${asset}" on chain ${chainId}.`,
|
|
1426
|
+
{ agentId: agent.id, asset, chainId }
|
|
1451
1427
|
);
|
|
1452
1428
|
}
|
|
1453
1429
|
}
|
|
@@ -1459,8 +1435,10 @@ var OwneySDK = class {
|
|
|
1459
1435
|
return chainAssets && chainAssets.assets.includes(asset);
|
|
1460
1436
|
});
|
|
1461
1437
|
if (eligible.length === 0) {
|
|
1462
|
-
throw new
|
|
1463
|
-
|
|
1438
|
+
throw new OwneyError(
|
|
1439
|
+
"ASSET_NO_COMPATIBLE_AGENTS",
|
|
1440
|
+
`No agents support asset "${asset}" on chain ${chainId}.`,
|
|
1441
|
+
{ asset, chainId }
|
|
1464
1442
|
);
|
|
1465
1443
|
}
|
|
1466
1444
|
return eligible;
|
|
@@ -1485,10 +1463,25 @@ var OwneySDK = class {
|
|
|
1485
1463
|
return agent.withdraw(state, chainId, amount);
|
|
1486
1464
|
}
|
|
1487
1465
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
1466
|
+
if (!amount) {
|
|
1467
|
+
const results2 = {};
|
|
1468
|
+
for (const agent of eligibleAgents) {
|
|
1469
|
+
results2[agent.id] = await agent.withdraw(state, chainId);
|
|
1470
|
+
}
|
|
1471
|
+
return { agentResult: results2 };
|
|
1472
|
+
}
|
|
1488
1473
|
const results = {};
|
|
1474
|
+
let lastError;
|
|
1489
1475
|
for (const agent of eligibleAgents) {
|
|
1490
|
-
|
|
1476
|
+
try {
|
|
1477
|
+
results[agent.id] = await agent.withdraw(state, chainId, amount);
|
|
1478
|
+
return { agentResult: results };
|
|
1479
|
+
} catch (err) {
|
|
1480
|
+
lastError = err;
|
|
1481
|
+
}
|
|
1491
1482
|
}
|
|
1483
|
+
if (lastError)
|
|
1484
|
+
throw lastError;
|
|
1492
1485
|
return {
|
|
1493
1486
|
agentResult: results
|
|
1494
1487
|
};
|
|
@@ -1500,12 +1493,10 @@ var OwneySDK = class {
|
|
|
1500
1493
|
* @returns {AgentBalance} for a single agent, or {OwneyBalances} with totalBalance and per-agent breakdown
|
|
1501
1494
|
*/
|
|
1502
1495
|
async getBalances(agentId) {
|
|
1503
|
-
const startedAt = Date.now();
|
|
1504
1496
|
const state = this.requireState();
|
|
1505
1497
|
const chainId = this.requireChainId();
|
|
1506
1498
|
if (agentId) {
|
|
1507
1499
|
const result = await this.getAgent(agentId).getBalances(state, chainId);
|
|
1508
|
-
logTiming3("getBalances single-agent", startedAt, { chainId, agentId });
|
|
1509
1500
|
return result;
|
|
1510
1501
|
}
|
|
1511
1502
|
let totalBalance = 0;
|
|
@@ -1513,12 +1504,7 @@ var OwneySDK = class {
|
|
|
1513
1504
|
const entries = [...this.getActiveAgents().entries()];
|
|
1514
1505
|
const balanceResults = await Promise.allSettled(
|
|
1515
1506
|
entries.map(async ([id, agent]) => {
|
|
1516
|
-
const agentStartedAt = Date.now();
|
|
1517
1507
|
const b = await agent.getBalances(state, chainId);
|
|
1518
|
-
logTiming3("getBalances per-agent", agentStartedAt, {
|
|
1519
|
-
chainId,
|
|
1520
|
-
agentId: id
|
|
1521
|
-
});
|
|
1522
1508
|
return [id, b];
|
|
1523
1509
|
})
|
|
1524
1510
|
);
|
|
@@ -1534,13 +1520,11 @@ var OwneySDK = class {
|
|
|
1534
1520
|
console.error("getBalances agent failed:", settledResult.reason);
|
|
1535
1521
|
}
|
|
1536
1522
|
if (successCount === 0) {
|
|
1537
|
-
throw new
|
|
1523
|
+
throw new OwneyError(
|
|
1524
|
+
"BALANCE_ALL_FAILED",
|
|
1525
|
+
"Failed to fetch balances for all active agents."
|
|
1526
|
+
);
|
|
1538
1527
|
}
|
|
1539
|
-
logTiming3("getBalances aggregate", startedAt, {
|
|
1540
|
-
chainId,
|
|
1541
|
-
totalAgents: entries.length,
|
|
1542
|
-
successCount
|
|
1543
|
-
});
|
|
1544
1528
|
return {
|
|
1545
1529
|
totalBalance: String(totalBalance),
|
|
1546
1530
|
agentBalances: results
|
|
@@ -1776,7 +1760,10 @@ var OwneySDK = class {
|
|
|
1776
1760
|
}
|
|
1777
1761
|
}
|
|
1778
1762
|
if (successCount === 0) {
|
|
1779
|
-
throw new
|
|
1763
|
+
throw new OwneyError(
|
|
1764
|
+
"ALLOCATION_ALL_FAILED",
|
|
1765
|
+
"Failed to fetch allocation: all agents failed."
|
|
1766
|
+
);
|
|
1780
1767
|
}
|
|
1781
1768
|
const allocation = {};
|
|
1782
1769
|
if (totalBalance === 0) {
|
|
@@ -1805,5 +1792,6 @@ var OwneySDK = class {
|
|
|
1805
1792
|
AgentChainIncompatibleError,
|
|
1806
1793
|
AgentNotFoundError,
|
|
1807
1794
|
NotConnectedError,
|
|
1795
|
+
OwneyError,
|
|
1808
1796
|
OwneySDK
|
|
1809
1797
|
});
|