@owney/sdk 0.7.16-beta.7 → 0.7.17-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +644 -1463
- package/dist/index.d.cts +26 -33
- package/dist/index.d.ts +26 -33
- package/dist/index.js +630 -211
- package/package.json +1 -4
- package/dist/chunk-5LU2SHO7.js +0 -50
- package/dist/chunk-DBRXNDSB.js +0 -87
- package/dist/chunk-GMNQBWUB.js +0 -55
- package/dist/chunk-QA7JUSDB.js +0 -92
- package/dist/chunk-V2LNMTE6.js +0 -222
- package/dist/chunk-VHQ4VXY7.js +0 -39
- package/dist/routing-api-KAILDWMD.js +0 -11
- package/dist/surfliquid.agent-5GY7A6HY.js +0 -532
- package/dist/surfliquid.smart-account-ZTZV7HUD.js +0 -125
- package/dist/surfliquid.sponsorship-BFAL2O3B.js +0 -14
package/dist/index.js
CHANGED
|
@@ -1,29 +1,164 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var OwneyError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
details;
|
|
5
|
+
agentId;
|
|
6
|
+
constructor(code, message, details, agentId) {
|
|
7
|
+
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
8
|
+
super(`${prefix} ${message}`);
|
|
9
|
+
this.name = "OwneyError";
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.details = details;
|
|
12
|
+
this.agentId = agentId;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var AgentNotFoundError = class extends OwneyError {
|
|
16
|
+
constructor(agentId, available) {
|
|
17
|
+
super(
|
|
18
|
+
"AGENT_NOT_FOUND",
|
|
19
|
+
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
20
|
+
{ agentId, available },
|
|
21
|
+
agentId
|
|
22
|
+
);
|
|
23
|
+
this.name = "AgentNotFoundError";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var NotConnectedError = class extends OwneyError {
|
|
27
|
+
constructor() {
|
|
28
|
+
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
29
|
+
this.name = "NotConnectedError";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var AgentChainIncompatibleError = class extends OwneyError {
|
|
33
|
+
incompatibleAgents;
|
|
34
|
+
connectedChainId;
|
|
35
|
+
constructor(incompatibleAgents, connectedChainId) {
|
|
36
|
+
const details = incompatibleAgents.map(
|
|
37
|
+
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
38
|
+
).join("; ");
|
|
39
|
+
super(
|
|
40
|
+
"AGENT_CHAIN_INCOMPATIBLE",
|
|
41
|
+
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
42
|
+
{ incompatibleAgents, connectedChainId }
|
|
43
|
+
);
|
|
44
|
+
this.name = "AgentChainIncompatibleError";
|
|
45
|
+
this.incompatibleAgents = incompatibleAgents;
|
|
46
|
+
this.connectedChainId = connectedChainId;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// src/lib/rate-limit.ts
|
|
51
|
+
function rateLimitDelay(error, now = Date.now()) {
|
|
52
|
+
const seen = /* @__PURE__ */ new Set();
|
|
53
|
+
let limited = false;
|
|
54
|
+
let delay = 0;
|
|
55
|
+
function visit(value, depth = 0) {
|
|
56
|
+
if (depth > 6 || value == null) return;
|
|
57
|
+
if (typeof value === "string") {
|
|
58
|
+
if (/rate[ _-]?limit|too many requests|HTTP_429|\b429\b/i.test(value))
|
|
59
|
+
limited = true;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (typeof value !== "object" || seen.has(value)) return;
|
|
63
|
+
seen.add(value);
|
|
64
|
+
const record = value;
|
|
65
|
+
if ([record.status, record.statusCode, record.code].some(
|
|
66
|
+
(code) => String(code) === "429"
|
|
67
|
+
)) {
|
|
68
|
+
limited = true;
|
|
69
|
+
}
|
|
70
|
+
for (const key2 of ["retryAfterSeconds", "retryAfter"]) {
|
|
71
|
+
const seconds = Number(record[key2]);
|
|
72
|
+
if (Number.isFinite(seconds) && seconds > 0)
|
|
73
|
+
delay = Math.max(delay, seconds * 1e3);
|
|
74
|
+
}
|
|
75
|
+
const retryAt = Number(record.retryAt);
|
|
76
|
+
if (Number.isFinite(retryAt) && retryAt > now)
|
|
77
|
+
delay = Math.max(delay, retryAt - now);
|
|
78
|
+
const headers = record.headers;
|
|
79
|
+
const header = typeof headers?.get === "function" ? headers.get("Retry-After") : headers?.["retry-after"] ?? headers?.["Retry-After"];
|
|
80
|
+
if (typeof header === "string" || typeof header === "number") {
|
|
81
|
+
const seconds = Number(header);
|
|
82
|
+
const ms = Number.isFinite(seconds) ? seconds * 1e3 : Date.parse(String(header)) - now;
|
|
83
|
+
if (Number.isFinite(ms) && ms > 0) delay = Math.max(delay, ms);
|
|
84
|
+
}
|
|
85
|
+
for (const key2 of [
|
|
86
|
+
"message",
|
|
87
|
+
"code",
|
|
88
|
+
"cause",
|
|
89
|
+
"details",
|
|
90
|
+
"response",
|
|
91
|
+
"data",
|
|
92
|
+
"fields"
|
|
93
|
+
]) {
|
|
94
|
+
visit(record[key2], depth + 1);
|
|
95
|
+
}
|
|
96
|
+
for (const key2 of ["agentErrors", "failures"]) {
|
|
97
|
+
const entries = record[key2];
|
|
98
|
+
if (entries && typeof entries === "object") {
|
|
99
|
+
for (const entry of Object.values(entries)) visit(entry, depth + 1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
visit(error);
|
|
104
|
+
return limited ? delay : void 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/lib/agent-reads.ts
|
|
108
|
+
var AgentReads = class {
|
|
109
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
110
|
+
cooldowns = /* @__PURE__ */ new Map();
|
|
111
|
+
// A reconnect must not reuse work started by the previous connection.
|
|
112
|
+
clearInFlight() {
|
|
113
|
+
this.inFlight.clear();
|
|
114
|
+
}
|
|
115
|
+
limited(agentId, until) {
|
|
116
|
+
return new OwneyError(
|
|
117
|
+
"AGENT_RATE_LIMITED",
|
|
118
|
+
"Too many requests. Please wait before trying again.",
|
|
119
|
+
{
|
|
120
|
+
statusCode: 429,
|
|
121
|
+
retryAt: until,
|
|
122
|
+
retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3))
|
|
123
|
+
},
|
|
124
|
+
agentId
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
run(agentId, key2, fetch2) {
|
|
128
|
+
const cooldown = this.cooldowns.get(agentId);
|
|
129
|
+
if (cooldown && cooldown.until > Date.now()) {
|
|
130
|
+
return Promise.reject(this.limited(agentId, cooldown.until));
|
|
131
|
+
}
|
|
132
|
+
const requestKey = JSON.stringify([agentId, key2]);
|
|
133
|
+
const existing = this.inFlight.get(requestKey);
|
|
134
|
+
if (existing) return existing;
|
|
135
|
+
const promise = Promise.resolve().then(fetch2).then(
|
|
136
|
+
(value) => {
|
|
137
|
+
if (this.cooldowns.get(agentId) === cooldown)
|
|
138
|
+
this.cooldowns.delete(agentId);
|
|
139
|
+
return value;
|
|
140
|
+
},
|
|
141
|
+
(error) => {
|
|
142
|
+
const requestedDelay = rateLimitDelay(error);
|
|
143
|
+
if (requestedDelay === void 0) throw error;
|
|
144
|
+
const previous = this.cooldowns.get(agentId);
|
|
145
|
+
const failures = previous && previous.until > Date.now() ? previous.failures : Math.min((previous?.failures ?? 0) + 1, 5);
|
|
146
|
+
const delay = Math.max(
|
|
147
|
+
requestedDelay,
|
|
148
|
+
Math.min(3e4 * 2 ** (failures - 1), 3e5)
|
|
149
|
+
);
|
|
150
|
+
const until = Math.max(previous?.until ?? 0, Date.now() + delay);
|
|
151
|
+
this.cooldowns.set(agentId, { until, failures });
|
|
152
|
+
throw this.limited(agentId, until);
|
|
153
|
+
}
|
|
154
|
+
).finally(() => {
|
|
155
|
+
if (this.inFlight.get(requestKey) === promise)
|
|
156
|
+
this.inFlight.delete(requestKey);
|
|
157
|
+
});
|
|
158
|
+
this.inFlight.set(requestKey, promise);
|
|
159
|
+
return promise;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
27
162
|
|
|
28
163
|
// src/agents/zyfai/zyfai.agent.ts
|
|
29
164
|
import { SMART_SESSIONS_VALIDATOR, ZyfaiSDK } from "@zyfai/sdk";
|
|
@@ -77,6 +212,23 @@ var SupportedAssets = [
|
|
|
77
212
|
}
|
|
78
213
|
];
|
|
79
214
|
|
|
215
|
+
// src/lib/debug.ts
|
|
216
|
+
var configuredDebug = false;
|
|
217
|
+
function setOwneyDebug(enabled) {
|
|
218
|
+
configuredDebug = enabled;
|
|
219
|
+
}
|
|
220
|
+
function isOwneyDebug() {
|
|
221
|
+
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
222
|
+
}
|
|
223
|
+
function debugLog(scope, message, data) {
|
|
224
|
+
if (!isOwneyDebug()) return;
|
|
225
|
+
if (data === void 0) {
|
|
226
|
+
console.log(`[${scope}] ${message}`);
|
|
227
|
+
} else {
|
|
228
|
+
console.log(`[${scope}] ${message}`, data);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
80
232
|
// src/lib/utils.ts
|
|
81
233
|
var isValidChainId = (chainId) => {
|
|
82
234
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
@@ -88,12 +240,6 @@ var isValidChainId = (chainId) => {
|
|
|
88
240
|
}
|
|
89
241
|
return chainId;
|
|
90
242
|
};
|
|
91
|
-
function isSameAsset(tokenSymbol, asset) {
|
|
92
|
-
const token = tokenSymbol.toLowerCase();
|
|
93
|
-
const target = asset.toLowerCase();
|
|
94
|
-
if (token === target) return true;
|
|
95
|
-
return target === "weth" && token === "eth" || target === "eth" && token === "weth";
|
|
96
|
-
}
|
|
97
243
|
function hexToDecimal(hex, decimals = 6) {
|
|
98
244
|
const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
|
|
99
245
|
const parsed = BigInt(normalized);
|
|
@@ -886,7 +1032,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
886
1032
|
// successful decode is cached forever; failures are NOT cached so a transient
|
|
887
1033
|
// RPC error retries on the next fetch.
|
|
888
1034
|
withdrawAmountCache = /* @__PURE__ */ new Map();
|
|
889
|
-
|
|
1035
|
+
earningsReads = /* @__PURE__ */ new Map();
|
|
1036
|
+
earningsRefreshes = /* @__PURE__ */ new Map();
|
|
1037
|
+
earningsSnapshot = null;
|
|
1038
|
+
earningsGeneration = 0;
|
|
890
1039
|
constructor(apiKey, rpcUrls, referralSource) {
|
|
891
1040
|
this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
|
|
892
1041
|
this.sdk = new ZyfaiSDK({
|
|
@@ -1131,6 +1280,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1131
1280
|
}
|
|
1132
1281
|
// --- IAgent: Connection lifecycle ---
|
|
1133
1282
|
async disconnect() {
|
|
1283
|
+
this.earningsGeneration++;
|
|
1284
|
+
this.earningsReads.clear();
|
|
1285
|
+
this.earningsRefreshes.clear();
|
|
1286
|
+
this.earningsSnapshot = null;
|
|
1134
1287
|
if (this.connectedAddress && this.connectedChainId !== null) {
|
|
1135
1288
|
clearSession(this.connectedAddress, this.connectedChainId);
|
|
1136
1289
|
}
|
|
@@ -1327,37 +1480,6 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1327
1480
|
);
|
|
1328
1481
|
}
|
|
1329
1482
|
}
|
|
1330
|
-
/**
|
|
1331
|
-
* Records the deposit with Zyfai, retrying transient failures.
|
|
1332
|
-
*
|
|
1333
|
-
* This runs AFTER the transfer has already landed on-chain, so it must never
|
|
1334
|
-
* fail the deposit — the funds moved. But it is also the ONLY source of the
|
|
1335
|
-
* "Top up wallet" entry the history is built from: Zyfai auto-deploys the
|
|
1336
|
-
* balance it detects either way, so when this call is lost the user's deposit
|
|
1337
|
-
* never appears in Activity (an earlier withdrawal stays the newest row) and
|
|
1338
|
-
* nothing ever backfills it. Retry, then log loudly enough to be recoverable.
|
|
1339
|
-
*/
|
|
1340
|
-
async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
|
|
1341
|
-
const ATTEMPTS = 3;
|
|
1342
|
-
const RETRY_DELAY_MS = 1e3;
|
|
1343
|
-
for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
|
|
1344
|
-
try {
|
|
1345
|
-
await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
|
|
1346
|
-
return;
|
|
1347
|
-
} catch (logError) {
|
|
1348
|
-
if (attempt === ATTEMPTS) {
|
|
1349
|
-
console.error(
|
|
1350
|
-
"[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
|
|
1351
|
-
{ txHash, chainId, amount, tokenAddress, error: logError }
|
|
1352
|
-
);
|
|
1353
|
-
return;
|
|
1354
|
-
}
|
|
1355
|
-
await new Promise(
|
|
1356
|
-
(resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
|
|
1357
|
-
);
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
1483
|
/**
|
|
1362
1484
|
* True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
|
|
1363
1485
|
* to this EOA — the "new wallet" kind that is predeployed on the chains it
|
|
@@ -1661,12 +1783,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1661
1783
|
);
|
|
1662
1784
|
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
1663
1785
|
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
1664
|
-
|
|
1665
|
-
validChainId,
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1786
|
+
try {
|
|
1787
|
+
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
1788
|
+
} catch (logError) {
|
|
1789
|
+
console.warn(
|
|
1790
|
+
"[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
|
|
1791
|
+
logError
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1670
1794
|
return { txHash, smartWallet, amount };
|
|
1671
1795
|
}
|
|
1672
1796
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
@@ -1708,26 +1832,59 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1708
1832
|
const raw = await this.sdk.getPortfolio(this.getAddress());
|
|
1709
1833
|
return mapBalances(raw, validChainId, smartWallet);
|
|
1710
1834
|
}
|
|
1835
|
+
earningsKey(state, chainId, smartWallet) {
|
|
1836
|
+
return JSON.stringify([
|
|
1837
|
+
state.walletAddress?.toLowerCase(),
|
|
1838
|
+
chainId,
|
|
1839
|
+
smartWallet.toLowerCase()
|
|
1840
|
+
]);
|
|
1841
|
+
}
|
|
1842
|
+
readEarnings(key2, smartWallet) {
|
|
1843
|
+
const existing = this.earningsReads.get(key2);
|
|
1844
|
+
if (existing) return existing;
|
|
1845
|
+
const generation = this.earningsGeneration;
|
|
1846
|
+
const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw) => {
|
|
1847
|
+
if (generation === this.earningsGeneration) {
|
|
1848
|
+
this.earningsSnapshot = { key: key2, raw, at: Date.now() };
|
|
1849
|
+
}
|
|
1850
|
+
return raw;
|
|
1851
|
+
}).finally(() => {
|
|
1852
|
+
if (this.earningsReads.get(key2) === pending)
|
|
1853
|
+
this.earningsReads.delete(key2);
|
|
1854
|
+
});
|
|
1855
|
+
this.earningsReads.set(key2, pending);
|
|
1856
|
+
return pending;
|
|
1857
|
+
}
|
|
1711
1858
|
async getEarnings(state, chainId) {
|
|
1712
1859
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1713
|
-
const raw = await this.
|
|
1860
|
+
const raw = await this.readEarnings(
|
|
1861
|
+
this.earningsKey(state, chainId, smartWallet),
|
|
1862
|
+
smartWallet
|
|
1863
|
+
);
|
|
1714
1864
|
return mapEarnings(raw, smartWallet);
|
|
1715
1865
|
}
|
|
1716
1866
|
async refreshEarnings(state, chainId) {
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1867
|
+
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1868
|
+
const key2 = this.earningsKey(state, chainId, smartWallet);
|
|
1869
|
+
const existing = this.earningsRefreshes.get(key2);
|
|
1870
|
+
if (existing) return existing;
|
|
1871
|
+
const generation = this.earningsGeneration;
|
|
1872
|
+
const pending = (async () => {
|
|
1873
|
+
const recent = this.earningsSnapshot;
|
|
1874
|
+
const current = recent?.key === key2 && Date.now() - recent.at < 5e3 ? recent.raw : await this.readEarnings(key2, smartWallet);
|
|
1721
1875
|
const lastCheck = current.data.lastCheckTimestamp ? Date.parse(current.data.lastCheckTimestamp) : Number.NaN;
|
|
1722
1876
|
const isFresh = Number.isFinite(lastCheck) && Date.now() - lastCheck < EARNINGS_REFRESH_COOLDOWN_MS;
|
|
1723
1877
|
const earnings = isFresh ? current : await this.sdk.calculateOnchainEarnings(smartWallet);
|
|
1878
|
+
if (!isFresh && generation === this.earningsGeneration) {
|
|
1879
|
+
this.earningsSnapshot = { key: key2, raw: earnings, at: Date.now() };
|
|
1880
|
+
}
|
|
1724
1881
|
return mapEarnings(earnings, smartWallet);
|
|
1725
|
-
})()
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
|
-
|
|
1882
|
+
})().finally(() => {
|
|
1883
|
+
if (this.earningsRefreshes.get(key2) === pending)
|
|
1884
|
+
this.earningsRefreshes.delete(key2);
|
|
1885
|
+
});
|
|
1886
|
+
this.earningsRefreshes.set(key2, pending);
|
|
1887
|
+
return pending;
|
|
1731
1888
|
}
|
|
1732
1889
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
1733
1890
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
@@ -1847,9 +2004,73 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1847
2004
|
}
|
|
1848
2005
|
};
|
|
1849
2006
|
|
|
1850
|
-
// src/lib/
|
|
2007
|
+
// src/lib/routing-api.ts
|
|
1851
2008
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1852
|
-
async function
|
|
2009
|
+
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2010
|
+
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
2011
|
+
try {
|
|
2012
|
+
const res = await fetch(url, {
|
|
2013
|
+
method: "GET",
|
|
2014
|
+
headers: {
|
|
2015
|
+
"Content-Type": "application/json",
|
|
2016
|
+
"x-owney-api-key": `${apiKey}`
|
|
2017
|
+
}
|
|
2018
|
+
});
|
|
2019
|
+
if (!res.ok) {
|
|
2020
|
+
if (res.status !== 404) {
|
|
2021
|
+
console.warn(
|
|
2022
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
2023
|
+
);
|
|
2024
|
+
}
|
|
2025
|
+
return null;
|
|
2026
|
+
}
|
|
2027
|
+
const json = await res.json();
|
|
2028
|
+
const policy = json.success ? json.data ?? null : null;
|
|
2029
|
+
debugLog(
|
|
2030
|
+
"owney-sdk",
|
|
2031
|
+
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
2032
|
+
policy ?? void 0
|
|
2033
|
+
);
|
|
2034
|
+
return policy;
|
|
2035
|
+
} catch (error) {
|
|
2036
|
+
console.warn(
|
|
2037
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
2038
|
+
error instanceof Error ? error.message : String(error)
|
|
2039
|
+
);
|
|
2040
|
+
return null;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2044
|
+
const url = `${baseUrl}/api/v1/agent/keys`;
|
|
2045
|
+
const res = await fetch(url, {
|
|
2046
|
+
method: "GET",
|
|
2047
|
+
headers: {
|
|
2048
|
+
"Content-Type": "application/json",
|
|
2049
|
+
"x-owney-api-key": `${apiKey}`
|
|
2050
|
+
}
|
|
2051
|
+
});
|
|
2052
|
+
if (!res.ok) {
|
|
2053
|
+
const text = await res.text().catch(() => "");
|
|
2054
|
+
throw new OwneyError(
|
|
2055
|
+
"API_ROUTING_ERROR",
|
|
2056
|
+
`Routing API error ${res.status}: ${text}`,
|
|
2057
|
+
{ statusCode: res.status, responseBody: text }
|
|
2058
|
+
);
|
|
2059
|
+
}
|
|
2060
|
+
const json = await res.json();
|
|
2061
|
+
if (!json.success) {
|
|
2062
|
+
throw new OwneyError(
|
|
2063
|
+
"API_ROUTING_FAILED",
|
|
2064
|
+
`Routing API request failed: ${json.message}`,
|
|
2065
|
+
{ message: json.message }
|
|
2066
|
+
);
|
|
2067
|
+
}
|
|
2068
|
+
return json.data;
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
// src/lib/health-report.ts
|
|
2072
|
+
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2073
|
+
async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
|
|
1853
2074
|
try {
|
|
1854
2075
|
await fetch(`${baseUrl}/api/v1/agent/health-report`, {
|
|
1855
2076
|
method: "POST",
|
|
@@ -1883,10 +2104,11 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
1883
2104
|
// src/lib/helpers/withdraw-helper.ts
|
|
1884
2105
|
import { parseUnits } from "viem";
|
|
1885
2106
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
2107
|
+
const target = asset.toUpperCase();
|
|
1886
2108
|
return agents.map((agent) => {
|
|
1887
2109
|
const agentBalance = aggregated[agent.id];
|
|
1888
2110
|
const tokenBalance = agentBalance?.tokens.find(
|
|
1889
|
-
(t) => t.chainId === chainId &&
|
|
2111
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
1890
2112
|
);
|
|
1891
2113
|
if (!tokenBalance) return { agent, balance: 0n };
|
|
1892
2114
|
return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
|
|
@@ -2003,10 +2225,46 @@ import {
|
|
|
2003
2225
|
} from "viem";
|
|
2004
2226
|
import { base as base2, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
|
|
2005
2227
|
|
|
2228
|
+
// src/lib/transfer-auth.ts
|
|
2229
|
+
import { bytesToHex } from "viem";
|
|
2230
|
+
var ERC20_META_ABI = [
|
|
2231
|
+
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
2232
|
+
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
2233
|
+
];
|
|
2234
|
+
function buildTransferWithAuthorizationTypedData(input) {
|
|
2235
|
+
return {
|
|
2236
|
+
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
2237
|
+
types: {
|
|
2238
|
+
TransferWithAuthorization: [
|
|
2239
|
+
{ name: "from", type: "address" },
|
|
2240
|
+
{ name: "to", type: "address" },
|
|
2241
|
+
{ name: "value", type: "uint256" },
|
|
2242
|
+
{ name: "validAfter", type: "uint256" },
|
|
2243
|
+
{ name: "validBefore", type: "uint256" },
|
|
2244
|
+
{ name: "nonce", type: "bytes32" }
|
|
2245
|
+
]
|
|
2246
|
+
},
|
|
2247
|
+
primaryType: "TransferWithAuthorization",
|
|
2248
|
+
message: input.message
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
async function readTokenMeta(publicClient, token) {
|
|
2252
|
+
const [tokenName, tokenVersion] = await Promise.all([
|
|
2253
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
2254
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
2255
|
+
]);
|
|
2256
|
+
return { tokenName, tokenVersion };
|
|
2257
|
+
}
|
|
2258
|
+
function randomAuthNonce() {
|
|
2259
|
+
const bytes = new Uint8Array(32);
|
|
2260
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
2261
|
+
return bytesToHex(bytes);
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2006
2264
|
// src/lib/sponsor-client.ts
|
|
2007
|
-
var
|
|
2265
|
+
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2008
2266
|
async function postSponsorTransferAuth(input) {
|
|
2009
|
-
const base3 = input.baseUrl ??
|
|
2267
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2010
2268
|
let res;
|
|
2011
2269
|
try {
|
|
2012
2270
|
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
@@ -2046,7 +2304,7 @@ async function postSponsorTransferAuth(input) {
|
|
|
2046
2304
|
return parsed.data;
|
|
2047
2305
|
}
|
|
2048
2306
|
async function postSponsorPermit2Transfer(input) {
|
|
2049
|
-
const base3 = input.baseUrl ??
|
|
2307
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2050
2308
|
let res;
|
|
2051
2309
|
try {
|
|
2052
2310
|
res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
|
|
@@ -2084,7 +2342,7 @@ async function postSponsorPermit2Transfer(input) {
|
|
|
2084
2342
|
return parsed.data;
|
|
2085
2343
|
}
|
|
2086
2344
|
async function getSponsorRelayerAddress(input) {
|
|
2087
|
-
const base3 = input.baseUrl ??
|
|
2345
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2088
2346
|
let res;
|
|
2089
2347
|
try {
|
|
2090
2348
|
res = await fetch(
|
|
@@ -2120,6 +2378,84 @@ async function getSponsorRelayerAddress(input) {
|
|
|
2120
2378
|
return parsed.data.relayer;
|
|
2121
2379
|
}
|
|
2122
2380
|
|
|
2381
|
+
// src/lib/permit2.ts
|
|
2382
|
+
import { bytesToHex as bytesToHex2 } from "viem";
|
|
2383
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2384
|
+
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
2385
|
+
var ERC20_ALLOWANCE_ABI = [
|
|
2386
|
+
{
|
|
2387
|
+
type: "function",
|
|
2388
|
+
name: "allowance",
|
|
2389
|
+
stateMutability: "view",
|
|
2390
|
+
inputs: [
|
|
2391
|
+
{ name: "owner", type: "address" },
|
|
2392
|
+
{ name: "spender", type: "address" }
|
|
2393
|
+
],
|
|
2394
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
2395
|
+
},
|
|
2396
|
+
{
|
|
2397
|
+
type: "function",
|
|
2398
|
+
name: "approve",
|
|
2399
|
+
stateMutability: "nonpayable",
|
|
2400
|
+
inputs: [
|
|
2401
|
+
{ name: "spender", type: "address" },
|
|
2402
|
+
{ name: "amount", type: "uint256" }
|
|
2403
|
+
],
|
|
2404
|
+
outputs: [{ name: "", type: "bool" }]
|
|
2405
|
+
},
|
|
2406
|
+
{
|
|
2407
|
+
type: "function",
|
|
2408
|
+
name: "balanceOf",
|
|
2409
|
+
stateMutability: "view",
|
|
2410
|
+
inputs: [{ name: "account", type: "address" }],
|
|
2411
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
2412
|
+
}
|
|
2413
|
+
];
|
|
2414
|
+
function buildPermitTransferFromTypedData(input) {
|
|
2415
|
+
return {
|
|
2416
|
+
domain: {
|
|
2417
|
+
name: "Permit2",
|
|
2418
|
+
chainId: input.chainId,
|
|
2419
|
+
verifyingContract: PERMIT2_ADDRESS
|
|
2420
|
+
},
|
|
2421
|
+
types: {
|
|
2422
|
+
PermitTransferFrom: [
|
|
2423
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
2424
|
+
{ name: "spender", type: "address" },
|
|
2425
|
+
{ name: "nonce", type: "uint256" },
|
|
2426
|
+
{ name: "deadline", type: "uint256" }
|
|
2427
|
+
],
|
|
2428
|
+
TokenPermissions: [
|
|
2429
|
+
{ name: "token", type: "address" },
|
|
2430
|
+
{ name: "amount", type: "uint256" }
|
|
2431
|
+
]
|
|
2432
|
+
},
|
|
2433
|
+
primaryType: "PermitTransferFrom",
|
|
2434
|
+
message: input.message
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
function randomPermit2Nonce() {
|
|
2438
|
+
const bytes = new Uint8Array(32);
|
|
2439
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
2440
|
+
return BigInt(bytesToHex2(bytes));
|
|
2441
|
+
}
|
|
2442
|
+
async function readPermit2Allowance(publicClient, token, owner) {
|
|
2443
|
+
return publicClient.readContract({
|
|
2444
|
+
address: token,
|
|
2445
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
2446
|
+
functionName: "allowance",
|
|
2447
|
+
args: [owner, PERMIT2_ADDRESS]
|
|
2448
|
+
});
|
|
2449
|
+
}
|
|
2450
|
+
async function readErc20Balance(publicClient, token, owner) {
|
|
2451
|
+
return publicClient.readContract({
|
|
2452
|
+
address: token,
|
|
2453
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
2454
|
+
functionName: "balanceOf",
|
|
2455
|
+
args: [owner]
|
|
2456
|
+
});
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2123
2459
|
// src/lib/chain-guard.ts
|
|
2124
2460
|
var CHAIN_NAMES = {
|
|
2125
2461
|
1: "Ethereum",
|
|
@@ -2438,7 +2774,6 @@ var VIEM_CHAIN2 = {
|
|
|
2438
2774
|
42161: arbitrum2,
|
|
2439
2775
|
1: mainnet2
|
|
2440
2776
|
};
|
|
2441
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai"];
|
|
2442
2777
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2443
2778
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2444
2779
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2467,11 +2802,21 @@ var OwneySDK = class {
|
|
|
2467
2802
|
zyfaiRpcUrls;
|
|
2468
2803
|
routingApiBaseUrl;
|
|
2469
2804
|
referralSource;
|
|
2470
|
-
surfliquidApiBaseUrl;
|
|
2471
2805
|
cachedSponsoredCallback = null;
|
|
2472
2806
|
cachedWethSponsoredCallback = null;
|
|
2473
2807
|
paymasterServiceUrl;
|
|
2474
2808
|
cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
|
|
2809
|
+
agentReads = new AgentReads();
|
|
2810
|
+
activationChecks = /* @__PURE__ */ new Map();
|
|
2811
|
+
readAgent(agent, method, fetch2, params = null) {
|
|
2812
|
+
const key2 = JSON.stringify([
|
|
2813
|
+
this.state?.walletAddress.toLowerCase() ?? null,
|
|
2814
|
+
this.state?.chainId ?? null,
|
|
2815
|
+
method,
|
|
2816
|
+
params
|
|
2817
|
+
]);
|
|
2818
|
+
return this.agentReads.run(agent.id, key2, fetch2);
|
|
2819
|
+
}
|
|
2475
2820
|
initializingAgentsPromise = null;
|
|
2476
2821
|
constructor(config) {
|
|
2477
2822
|
this.apiKey = config.apiKey;
|
|
@@ -2480,7 +2825,6 @@ var OwneySDK = class {
|
|
|
2480
2825
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2481
2826
|
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
2482
2827
|
this.referralSource = config.referralSource;
|
|
2483
|
-
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
2484
2828
|
}
|
|
2485
2829
|
/**
|
|
2486
2830
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2499,6 +2843,8 @@ var OwneySDK = class {
|
|
|
2499
2843
|
"No accounts found. Ensure the wallet is unlocked and connected."
|
|
2500
2844
|
);
|
|
2501
2845
|
}
|
|
2846
|
+
this.agentReads.clearInFlight();
|
|
2847
|
+
this.activationChecks.clear();
|
|
2502
2848
|
this.state = { provider, walletAddress, chainId: null };
|
|
2503
2849
|
this.cachedSponsoredCallback = null;
|
|
2504
2850
|
this.cachedWethSponsoredCallback = null;
|
|
@@ -2514,6 +2860,8 @@ var OwneySDK = class {
|
|
|
2514
2860
|
}
|
|
2515
2861
|
this.activeAgents.clear();
|
|
2516
2862
|
this.disabledAgents.clear();
|
|
2863
|
+
this.agentReads.clearInFlight();
|
|
2864
|
+
this.activationChecks.clear();
|
|
2517
2865
|
this.state = null;
|
|
2518
2866
|
this.cachedSponsoredCallback = null;
|
|
2519
2867
|
this.cachedWethSponsoredCallback = null;
|
|
@@ -2716,8 +3064,8 @@ var OwneySDK = class {
|
|
|
2716
3064
|
this.routingApiBaseUrl
|
|
2717
3065
|
);
|
|
2718
3066
|
this.disabledAgents.clear();
|
|
2719
|
-
for (const { key: key2, agent_type,
|
|
2720
|
-
const agent =
|
|
3067
|
+
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
3068
|
+
const agent = this.createAgent(agent_type, key2);
|
|
2721
3069
|
if (!agent) continue;
|
|
2722
3070
|
this.agents.set(agent_type, agent);
|
|
2723
3071
|
if (is_enabled === false) {
|
|
@@ -2738,25 +3086,42 @@ var OwneySDK = class {
|
|
|
2738
3086
|
this.initializingAgentsPromise = null;
|
|
2739
3087
|
}
|
|
2740
3088
|
}
|
|
2741
|
-
|
|
3089
|
+
createAgent(agentId, key2) {
|
|
2742
3090
|
if (agentId === "zyfai") {
|
|
2743
3091
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
2744
3092
|
}
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
3093
|
+
return null;
|
|
3094
|
+
}
|
|
3095
|
+
/**
|
|
3096
|
+
* Discover the agents actually returned by routing for this organization.
|
|
3097
|
+
* Consumers should use this instead of hardcoding a global agent roster.
|
|
3098
|
+
*/
|
|
3099
|
+
async getAvailableAgents(options = {}) {
|
|
3100
|
+
await this.ensureAgentsInitialized();
|
|
3101
|
+
const { chainId, asset, includeDisabled = false } = options;
|
|
3102
|
+
const available = [];
|
|
3103
|
+
for (const [id, agent] of this.agents) {
|
|
3104
|
+
const isEnabled = !this.isAgentDisabled(id);
|
|
3105
|
+
if (!includeDisabled && !isEnabled) continue;
|
|
3106
|
+
if (chainId !== void 0 && !agent.supportedChainIds.includes(chainId)) {
|
|
3107
|
+
continue;
|
|
3108
|
+
}
|
|
3109
|
+
if (asset !== void 0) {
|
|
3110
|
+
const supportsAsset = agent.supportedAssets.some(
|
|
3111
|
+
(entry) => (chainId === void 0 || entry.chainId === chainId) && entry.assets.some((candidate) => candidate.symbol === asset)
|
|
3112
|
+
);
|
|
3113
|
+
if (!supportsAsset) {
|
|
3114
|
+
continue;
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
available.push({
|
|
3118
|
+
id,
|
|
3119
|
+
isEnabled,
|
|
3120
|
+
supportedChainIds: agent.supportedChainIds,
|
|
3121
|
+
supportedAssets: agent.supportedAssets
|
|
2757
3122
|
});
|
|
2758
3123
|
}
|
|
2759
|
-
return
|
|
3124
|
+
return available;
|
|
2760
3125
|
}
|
|
2761
3126
|
// --- Account lifecycle ---
|
|
2762
3127
|
/**
|
|
@@ -2805,9 +3170,7 @@ var OwneySDK = class {
|
|
|
2805
3170
|
this.activeAgents.add(id);
|
|
2806
3171
|
}
|
|
2807
3172
|
state.chainId = chainId;
|
|
2808
|
-
this.activateAgentsInTurn(agents, state, chainId)
|
|
2809
|
-
console.error("activateAgent background init failed:", error);
|
|
2810
|
-
});
|
|
3173
|
+
await this.activateAgentsInTurn(agents, state, chainId);
|
|
2811
3174
|
return;
|
|
2812
3175
|
}
|
|
2813
3176
|
const compatible = [...this.agents.values()].filter(
|
|
@@ -2828,11 +3191,7 @@ var OwneySDK = class {
|
|
|
2828
3191
|
const enabledCompatible = compatible.filter(
|
|
2829
3192
|
(agent) => !this.isAgentDisabled(agent.id)
|
|
2830
3193
|
);
|
|
2831
|
-
this.activateAgentsInTurn(enabledCompatible, state, chainId)
|
|
2832
|
-
(error) => {
|
|
2833
|
-
console.error("activateAgent background init failed:", error);
|
|
2834
|
-
}
|
|
2835
|
-
);
|
|
3194
|
+
await this.activateAgentsInTurn(enabledCompatible, state, chainId);
|
|
2836
3195
|
}
|
|
2837
3196
|
/**
|
|
2838
3197
|
* Activate agents ONE AT A TIME, each followed by its org policy.
|
|
@@ -2869,7 +3228,7 @@ var OwneySDK = class {
|
|
|
2869
3228
|
if (firstError !== null) throw firstError;
|
|
2870
3229
|
}
|
|
2871
3230
|
/**
|
|
2872
|
-
* Deposit
|
|
3231
|
+
* Deposit into a specific agent, or distribute across all eligible agents.
|
|
2873
3232
|
* Validates that the asset is supported and amount meets minimums for the target agent(s).
|
|
2874
3233
|
* @param options - Deposit parameters
|
|
2875
3234
|
* @param options.amount - Amount to deposit in smallest unit (e.g. "100000000" for 100 USDC)
|
|
@@ -2877,7 +3236,8 @@ var OwneySDK = class {
|
|
|
2877
3236
|
* @param options.depositCallback - Callback that performs the token transfer and returns a tx hash.
|
|
2878
3237
|
* When agentId is omitted, this callback is invoked once per eligible agent with that agent's
|
|
2879
3238
|
* split amount and smart wallet address — expect multiple wallet prompts.
|
|
2880
|
-
* @param options.agentId - Optional
|
|
3239
|
+
* @param options.agentId - Optional explicit target. Otherwise split equally,
|
|
3240
|
+
* or fund remaining agents when a recovery deposit cannot meet every minimum.
|
|
2881
3241
|
* @returns {OwneyDepositResult} for a single agent, or {OwneyMultiDepositResult} with per-agent results
|
|
2882
3242
|
*/
|
|
2883
3243
|
async deposit(options) {
|
|
@@ -2915,7 +3275,7 @@ var OwneySDK = class {
|
|
|
2915
3275
|
});
|
|
2916
3276
|
const exemptFlags = await Promise.all(
|
|
2917
3277
|
eligibleAgents.map(
|
|
2918
|
-
(a) => this.hasExistingBalance(a, state, chainId, asset)
|
|
3278
|
+
(a) => this.hasExistingBalance(a, state, chainId, asset, true)
|
|
2919
3279
|
)
|
|
2920
3280
|
);
|
|
2921
3281
|
const exempt = new Set(
|
|
@@ -2929,15 +3289,42 @@ var OwneySDK = class {
|
|
|
2929
3289
|
exempt
|
|
2930
3290
|
);
|
|
2931
3291
|
if (agentAmounts.length === 0) {
|
|
3292
|
+
const agentsRequiringActivation = eligibleAgents.filter(
|
|
3293
|
+
(agent) => !exempt.has(agent.id)
|
|
3294
|
+
);
|
|
3295
|
+
const perAgentMinimum = agentsRequiringActivation.reduce(
|
|
3296
|
+
(highest, agent) => {
|
|
3297
|
+
const minimum = this.getMinDepositAmount(agent, chainId, asset);
|
|
3298
|
+
return minimum > highest ? minimum : highest;
|
|
3299
|
+
},
|
|
3300
|
+
0n
|
|
3301
|
+
);
|
|
3302
|
+
const minimumRequired = agentsRequiringActivation.length > 0 ? (perAgentMinimum > 0n ? perAgentMinimum : 1n) * BigInt(agentsRequiringActivation.length) : BigInt(eligibleAgents.length);
|
|
2932
3303
|
throw new OwneyError(
|
|
2933
3304
|
"DEPOSIT_AMOUNT_BELOW_MINIMUM",
|
|
2934
|
-
`Amount "${amount}" cannot
|
|
2935
|
-
{
|
|
3305
|
+
`Amount "${amount}" cannot activate every eligible agent. The combined minimum is "${minimumRequired.toString()}" for ${asset}.`,
|
|
3306
|
+
{
|
|
3307
|
+
amount,
|
|
3308
|
+
asset,
|
|
3309
|
+
chainId,
|
|
3310
|
+
minDepositAmount: minimumRequired.toString(),
|
|
3311
|
+
perAgentDepositAmount: perAgentMinimum.toString(),
|
|
3312
|
+
agentMinimums: agentsRequiringActivation.map((agent) => ({
|
|
3313
|
+
agentId: agent.id,
|
|
3314
|
+
minDepositAmount: this.getMinDepositAmount(
|
|
3315
|
+
agent,
|
|
3316
|
+
chainId,
|
|
3317
|
+
asset
|
|
3318
|
+
).toString()
|
|
3319
|
+
}))
|
|
3320
|
+
}
|
|
2936
3321
|
);
|
|
2937
3322
|
}
|
|
2938
3323
|
const agentResults = {};
|
|
2939
|
-
const
|
|
2940
|
-
|
|
3324
|
+
for (const [
|
|
3325
|
+
index,
|
|
3326
|
+
{ agent, amount: agentAmount }
|
|
3327
|
+
] of agentAmounts.entries()) {
|
|
2941
3328
|
try {
|
|
2942
3329
|
agentResults[agent.id] = await this.depositWithFallback(
|
|
2943
3330
|
agent,
|
|
@@ -2949,17 +3336,22 @@ var OwneySDK = class {
|
|
|
2949
3336
|
depositCallback
|
|
2950
3337
|
);
|
|
2951
3338
|
} catch (error) {
|
|
2952
|
-
|
|
3339
|
+
if (Object.keys(agentResults).length === 0) throw error;
|
|
3340
|
+
throw new OwneyError(
|
|
3341
|
+
"DEPOSIT_PARTIAL_FAILURE",
|
|
3342
|
+
"Some deposits completed before another agent failed. Check activity and balances before depositing again; the failed transfer may still settle.",
|
|
3343
|
+
{
|
|
3344
|
+
agentResults,
|
|
3345
|
+
failedAgentId: agent.id,
|
|
3346
|
+
failedAmount: agentAmount,
|
|
3347
|
+
unattemptedAgentIds: agentAmounts.slice(index + 1).map(({ agent: agent2 }) => agent2.id),
|
|
3348
|
+
cause: error
|
|
3349
|
+
},
|
|
3350
|
+
agent.id
|
|
3351
|
+
);
|
|
2953
3352
|
}
|
|
2954
3353
|
}
|
|
2955
|
-
|
|
2956
|
-
throw new OwneyError(
|
|
2957
|
-
"DEPOSIT_ALL_FAILED",
|
|
2958
|
-
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
2959
|
-
{ agentErrors }
|
|
2960
|
-
);
|
|
2961
|
-
}
|
|
2962
|
-
return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
|
|
3354
|
+
return { agentResults };
|
|
2963
3355
|
}
|
|
2964
3356
|
/**
|
|
2965
3357
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -3030,6 +3422,17 @@ var OwneySDK = class {
|
|
|
3030
3422
|
}
|
|
3031
3423
|
splitDepositAmount(totalAmount, agents, chainId, asset, exempt = /* @__PURE__ */ new Set()) {
|
|
3032
3424
|
if (agents.length === 0) return [];
|
|
3425
|
+
const agentsRequiringActivation = agents.filter(
|
|
3426
|
+
(agent) => !exempt.has(agent.id)
|
|
3427
|
+
);
|
|
3428
|
+
if (agentsRequiringActivation.length === agents.length) {
|
|
3429
|
+
const highestMinimum2 = agents.reduce((highest, agent) => {
|
|
3430
|
+
const minimum = this.getMinDepositAmount(agent, chainId, asset);
|
|
3431
|
+
return minimum > highest ? minimum : highest;
|
|
3432
|
+
}, 0n);
|
|
3433
|
+
const minimumRequired2 = (highestMinimum2 > 0n ? highestMinimum2 : 1n) * BigInt(agents.length);
|
|
3434
|
+
if (totalAmount < minimumRequired2) return [];
|
|
3435
|
+
}
|
|
3033
3436
|
const perAgent = totalAmount / BigInt(agents.length);
|
|
3034
3437
|
const remainder = totalAmount % BigInt(agents.length);
|
|
3035
3438
|
const splits = agents.map((agent, i) => ({
|
|
@@ -3037,18 +3440,26 @@ var OwneySDK = class {
|
|
|
3037
3440
|
amount: i === agents.length - 1 ? perAgent + remainder : perAgent
|
|
3038
3441
|
}));
|
|
3039
3442
|
const valid = splits.filter(
|
|
3040
|
-
(s) => exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset)
|
|
3443
|
+
(s) => s.amount > 0n && (exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset))
|
|
3041
3444
|
);
|
|
3042
3445
|
if (valid.length === agents.length) {
|
|
3043
3446
|
return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
|
|
3044
3447
|
}
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
);
|
|
3448
|
+
const targets = agentsRequiringActivation.length > 0 ? agentsRequiringActivation : agents;
|
|
3449
|
+
const highestMinimum = targets.reduce((highest, agent) => {
|
|
3450
|
+
const minimum = this.getMinDepositAmount(agent, chainId, asset);
|
|
3451
|
+
return minimum > highest ? minimum : highest;
|
|
3452
|
+
}, 0n);
|
|
3453
|
+
const minimumRequired = (highestMinimum > 0n ? highestMinimum : 1n) * BigInt(targets.length);
|
|
3454
|
+
if (totalAmount < minimumRequired) return [];
|
|
3455
|
+
const targetShare = totalAmount / BigInt(targets.length);
|
|
3456
|
+
const targetRemainder = totalAmount % BigInt(targets.length);
|
|
3457
|
+
return targets.map((agent, index) => ({
|
|
3458
|
+
agent,
|
|
3459
|
+
amount: String(
|
|
3460
|
+
targetShare + (index === targets.length - 1 ? targetRemainder : 0n)
|
|
3461
|
+
)
|
|
3462
|
+
}));
|
|
3052
3463
|
}
|
|
3053
3464
|
async validateMinDepositAmount(agent, state, chainId, asset, amount) {
|
|
3054
3465
|
const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
|
|
@@ -3073,14 +3484,29 @@ var OwneySDK = class {
|
|
|
3073
3484
|
* per-agent minimum. Fails closed: any error reading balances returns
|
|
3074
3485
|
* false, so the minimum is enforced as today.
|
|
3075
3486
|
*/
|
|
3076
|
-
async hasExistingBalance(agent, state, chainId, asset) {
|
|
3487
|
+
async hasExistingBalance(agent, state, chainId, asset, requireReliableRead = false) {
|
|
3077
3488
|
try {
|
|
3078
3489
|
const balance = await agent.getBalances(state, chainId);
|
|
3490
|
+
const target = asset.toLowerCase();
|
|
3079
3491
|
const token = balance.tokens.find(
|
|
3080
|
-
(t) => t.chainId === chainId &&
|
|
3492
|
+
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
3081
3493
|
);
|
|
3082
|
-
|
|
3083
|
-
|
|
3494
|
+
const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
|
|
3495
|
+
const position = (balance.positions ?? []).find((p) => {
|
|
3496
|
+
const positionChain = p.chain.trim().toUpperCase();
|
|
3497
|
+
const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
|
|
3498
|
+
return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
|
|
3499
|
+
});
|
|
3500
|
+
return !!token && Number(token.amount) > 0 || !!position;
|
|
3501
|
+
} catch (error) {
|
|
3502
|
+
if (requireReliableRead) {
|
|
3503
|
+
throw new OwneyError(
|
|
3504
|
+
"DEPOSIT_BALANCE_UNAVAILABLE",
|
|
3505
|
+
"Could not verify every agent balance. No deposit was submitted. Try again once balances are available.",
|
|
3506
|
+
{ agentId: agent.id, chainId, asset, cause: error },
|
|
3507
|
+
agent.id
|
|
3508
|
+
);
|
|
3509
|
+
}
|
|
3084
3510
|
return false;
|
|
3085
3511
|
}
|
|
3086
3512
|
}
|
|
@@ -3116,34 +3542,6 @@ var OwneySDK = class {
|
|
|
3116
3542
|
}
|
|
3117
3543
|
return eligible;
|
|
3118
3544
|
}
|
|
3119
|
-
/**
|
|
3120
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
3121
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
3122
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
3123
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
3124
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
3125
|
-
*
|
|
3126
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
3127
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
3128
|
-
*/
|
|
3129
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
3130
|
-
try {
|
|
3131
|
-
await this.ensureAgentsInitialized();
|
|
3132
|
-
} catch (error) {
|
|
3133
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
3134
|
-
return [];
|
|
3135
|
-
}
|
|
3136
|
-
throw error;
|
|
3137
|
-
}
|
|
3138
|
-
return [...this.agents.values()].filter((agent) => {
|
|
3139
|
-
const chainAssets = agent.supportedAssets.find(
|
|
3140
|
-
(sa) => sa.chainId === chainId
|
|
3141
|
-
);
|
|
3142
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
3143
|
-
}).map((agent) => agent.id).sort(
|
|
3144
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
3145
|
-
);
|
|
3146
|
-
}
|
|
3147
3545
|
// --- Fund operations ---
|
|
3148
3546
|
/**
|
|
3149
3547
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -3180,17 +3578,9 @@ var OwneySDK = class {
|
|
|
3180
3578
|
}
|
|
3181
3579
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
3182
3580
|
if (!amount) {
|
|
3183
|
-
const aggregated2 = await this.getBalances();
|
|
3184
|
-
const funded = projectAgentBalancesForAsset(
|
|
3185
|
-
eligibleAgents,
|
|
3186
|
-
aggregated2.agentBalances,
|
|
3187
|
-
chainId,
|
|
3188
|
-
asset,
|
|
3189
|
-
assetInfo.decimals
|
|
3190
|
-
).filter((b) => b.balance > 0n);
|
|
3191
3581
|
const results2 = {};
|
|
3192
3582
|
const agentErrors2 = {};
|
|
3193
|
-
for (const
|
|
3583
|
+
for (const agent of eligibleAgents) {
|
|
3194
3584
|
try {
|
|
3195
3585
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
3196
3586
|
} catch (err) {
|
|
@@ -3212,10 +3602,9 @@ var OwneySDK = class {
|
|
|
3212
3602
|
{ asset, agentErrors: agentErrors2 }
|
|
3213
3603
|
);
|
|
3214
3604
|
}
|
|
3215
|
-
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
3216
3605
|
return {
|
|
3217
3606
|
agentResult: results2,
|
|
3218
|
-
totalWithdrawn:
|
|
3607
|
+
totalWithdrawn: sumWithdrawnAmount(results2).toString()
|
|
3219
3608
|
};
|
|
3220
3609
|
}
|
|
3221
3610
|
const requested = BigInt(amount);
|
|
@@ -3320,7 +3709,8 @@ var OwneySDK = class {
|
|
|
3320
3709
|
const state = this.requireState();
|
|
3321
3710
|
const chainId = this.requireChainId();
|
|
3322
3711
|
if (agentId) {
|
|
3323
|
-
const
|
|
3712
|
+
const agent = this.getAgent(agentId);
|
|
3713
|
+
const result = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
3324
3714
|
return result;
|
|
3325
3715
|
}
|
|
3326
3716
|
let totalBalance = 0;
|
|
@@ -3328,12 +3718,13 @@ var OwneySDK = class {
|
|
|
3328
3718
|
const entries = [...this.getActiveAgents().entries()];
|
|
3329
3719
|
const balanceResults = await Promise.allSettled(
|
|
3330
3720
|
entries.map(async ([id, agent]) => {
|
|
3331
|
-
const b = await agent.getBalances(state, chainId);
|
|
3721
|
+
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
3332
3722
|
return [id, b];
|
|
3333
3723
|
})
|
|
3334
3724
|
);
|
|
3335
3725
|
let successCount = 0;
|
|
3336
3726
|
const agentErrors = {};
|
|
3727
|
+
const agentFailures = [];
|
|
3337
3728
|
for (let i = 0; i < balanceResults.length; i++) {
|
|
3338
3729
|
const settledResult = balanceResults[i];
|
|
3339
3730
|
const [agentId2] = entries[i];
|
|
@@ -3345,13 +3736,14 @@ var OwneySDK = class {
|
|
|
3345
3736
|
continue;
|
|
3346
3737
|
}
|
|
3347
3738
|
const reason = settledResult.reason;
|
|
3739
|
+
agentFailures.push(reason);
|
|
3348
3740
|
agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
|
|
3349
3741
|
}
|
|
3350
3742
|
if (successCount === 0) {
|
|
3351
3743
|
throw new OwneyError(
|
|
3352
3744
|
"BALANCE_ALL_FAILED",
|
|
3353
3745
|
"Failed to fetch balances for all active agents.",
|
|
3354
|
-
{ agentErrors }
|
|
3746
|
+
{ agentErrors, failures: agentFailures }
|
|
3355
3747
|
);
|
|
3356
3748
|
}
|
|
3357
3749
|
return {
|
|
@@ -3369,14 +3761,15 @@ var OwneySDK = class {
|
|
|
3369
3761
|
const state = this.requireState();
|
|
3370
3762
|
const chainId = this.requireChainId();
|
|
3371
3763
|
if (agentId) {
|
|
3372
|
-
|
|
3764
|
+
const agent = this.getAgent(agentId);
|
|
3765
|
+
return this.readAgent(agent, "earnings", () => agent.getEarnings(state, chainId));
|
|
3373
3766
|
}
|
|
3374
3767
|
let totalEarnings = 0;
|
|
3375
3768
|
const results = {};
|
|
3376
3769
|
const entries = [...this.getActiveAgents().entries()];
|
|
3377
3770
|
const earningsResults = await Promise.all(
|
|
3378
3771
|
entries.map(async ([id, agent]) => {
|
|
3379
|
-
const e = await agent.getEarnings(state, chainId);
|
|
3772
|
+
const e = await this.readAgent(agent, "earnings", () => agent.getEarnings(state, chainId));
|
|
3380
3773
|
return [id, e];
|
|
3381
3774
|
})
|
|
3382
3775
|
);
|
|
@@ -3396,7 +3789,11 @@ var OwneySDK = class {
|
|
|
3396
3789
|
async refreshEarnings(agentId) {
|
|
3397
3790
|
const state = this.requireState();
|
|
3398
3791
|
const chainId = this.requireChainId();
|
|
3399
|
-
const refreshAgent = (agent) =>
|
|
3792
|
+
const refreshAgent = (agent) => this.readAgent(
|
|
3793
|
+
agent,
|
|
3794
|
+
agent.refreshEarnings ? "refreshEarnings" : "earnings",
|
|
3795
|
+
() => agent.refreshEarnings?.(state, chainId) ?? agent.getEarnings(state, chainId)
|
|
3796
|
+
);
|
|
3400
3797
|
if (agentId) return refreshAgent(this.getAgent(agentId));
|
|
3401
3798
|
let totalEarnings = 0;
|
|
3402
3799
|
const agentEarnings = {};
|
|
@@ -3427,11 +3824,12 @@ var OwneySDK = class {
|
|
|
3427
3824
|
const state = this.requireState();
|
|
3428
3825
|
const chainId = this.requireChainId();
|
|
3429
3826
|
if (agentId) {
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
tokenSymbol
|
|
3827
|
+
const agent = this.getAgent(agentId);
|
|
3828
|
+
return this.readAgent(
|
|
3829
|
+
agent,
|
|
3830
|
+
"accountApy",
|
|
3831
|
+
() => agent.getAccountApy(state, chainId, days, tokenSymbol),
|
|
3832
|
+
{ days, tokenSymbol }
|
|
3435
3833
|
);
|
|
3436
3834
|
}
|
|
3437
3835
|
const activeAgents = this.getActiveAgents();
|
|
@@ -3439,18 +3837,18 @@ var OwneySDK = class {
|
|
|
3439
3837
|
const [apyResults, balanceResults] = await Promise.all([
|
|
3440
3838
|
Promise.all(
|
|
3441
3839
|
entries.map(async ([id, agent]) => {
|
|
3442
|
-
const apy = await
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
days,
|
|
3446
|
-
tokenSymbol
|
|
3840
|
+
const apy = await this.readAgent(
|
|
3841
|
+
agent,
|
|
3842
|
+
"accountApy",
|
|
3843
|
+
() => agent.getAccountApy(state, chainId, days, tokenSymbol),
|
|
3844
|
+
{ days, tokenSymbol }
|
|
3447
3845
|
);
|
|
3448
3846
|
return [id, apy];
|
|
3449
3847
|
})
|
|
3450
3848
|
),
|
|
3451
3849
|
Promise.all(
|
|
3452
3850
|
entries.map(async ([id, agent]) => {
|
|
3453
|
-
const b = await agent.getBalances(state, chainId);
|
|
3851
|
+
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
3454
3852
|
return [id, Number(b.totalBalance)];
|
|
3455
3853
|
})
|
|
3456
3854
|
)
|
|
@@ -3507,7 +3905,8 @@ var OwneySDK = class {
|
|
|
3507
3905
|
const chainId = this.requireChainId();
|
|
3508
3906
|
const { agentId, filters } = options ?? {};
|
|
3509
3907
|
if (agentId) {
|
|
3510
|
-
|
|
3908
|
+
const agent = this.getAgent(agentId);
|
|
3909
|
+
return this.readAgent(agent, "history", () => agent.getHistory(state, chainId, filters), filters);
|
|
3511
3910
|
}
|
|
3512
3911
|
const activeAgents = [...this.getActiveAgents().values()];
|
|
3513
3912
|
const cursorMap = filters?.cursor ? decodeMultiAgentCursor(filters.cursor) : {};
|
|
@@ -3517,10 +3916,13 @@ var OwneySDK = class {
|
|
|
3517
3916
|
if (filters?.cursor && agentCursor === void 0) {
|
|
3518
3917
|
return { agentId: agent.id, page: null };
|
|
3519
3918
|
}
|
|
3520
|
-
const
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3919
|
+
const agentFilters = { ...filters, cursor: agentCursor };
|
|
3920
|
+
const page = await this.readAgent(
|
|
3921
|
+
agent,
|
|
3922
|
+
"history",
|
|
3923
|
+
() => agent.getHistory(state, chainId, agentFilters),
|
|
3924
|
+
agentFilters
|
|
3925
|
+
);
|
|
3524
3926
|
return { agentId: agent.id, page };
|
|
3525
3927
|
})
|
|
3526
3928
|
);
|
|
@@ -3560,13 +3962,14 @@ var OwneySDK = class {
|
|
|
3560
3962
|
const state = this.requireState();
|
|
3561
3963
|
const chainId = this.requireChainId();
|
|
3562
3964
|
if (agentId) {
|
|
3563
|
-
|
|
3965
|
+
const agent = this.getAgent(agentId);
|
|
3966
|
+
return this.readAgent(agent, "profile", () => agent.getUserProfile(state, chainId));
|
|
3564
3967
|
}
|
|
3565
3968
|
const results = {};
|
|
3566
3969
|
const entries = [...this.getActiveAgents().entries()];
|
|
3567
3970
|
const profileResults = await Promise.all(
|
|
3568
3971
|
entries.map(async ([id, agent]) => {
|
|
3569
|
-
const p = await agent.getUserProfile(state, chainId);
|
|
3972
|
+
const p = await this.readAgent(agent, "profile", () => agent.getUserProfile(state, chainId));
|
|
3570
3973
|
return [id, p];
|
|
3571
3974
|
})
|
|
3572
3975
|
);
|
|
@@ -3589,7 +3992,20 @@ var OwneySDK = class {
|
|
|
3589
3992
|
const chainId = this.requireChainId();
|
|
3590
3993
|
const agent = this.getAgent(agentId);
|
|
3591
3994
|
if (typeof agent.ensureAutoSelectProtocols !== "function") return false;
|
|
3592
|
-
|
|
3995
|
+
const key2 = JSON.stringify([
|
|
3996
|
+
state.walletAddress.toLowerCase(),
|
|
3997
|
+
agentId,
|
|
3998
|
+
chainId,
|
|
3999
|
+
asset
|
|
4000
|
+
]);
|
|
4001
|
+
const existing = this.activationChecks.get(key2);
|
|
4002
|
+
if (existing) return existing;
|
|
4003
|
+
const pending = Promise.resolve().then(() => agent.ensureAutoSelectProtocols(state, chainId, asset)).finally(() => {
|
|
4004
|
+
if (this.activationChecks.get(key2) === pending)
|
|
4005
|
+
this.activationChecks.delete(key2);
|
|
4006
|
+
});
|
|
4007
|
+
this.activationChecks.set(key2, pending);
|
|
4008
|
+
return pending;
|
|
3593
4009
|
}
|
|
3594
4010
|
/**
|
|
3595
4011
|
* One-time, user-paid approval of Permit2 on the sponsored WETH token for
|
|
@@ -3660,13 +4076,14 @@ var OwneySDK = class {
|
|
|
3660
4076
|
await this.ensureAgentsInitialized();
|
|
3661
4077
|
const agentOptions = { tokenSymbol, chainId };
|
|
3662
4078
|
if (agentId) {
|
|
3663
|
-
|
|
4079
|
+
const agent = this.getAgent(agentId);
|
|
4080
|
+
return this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
|
|
3664
4081
|
}
|
|
3665
4082
|
const results = {};
|
|
3666
4083
|
const agentEntries = [...this.agents.entries()];
|
|
3667
4084
|
const apyResults = await Promise.all(
|
|
3668
4085
|
agentEntries.map(async ([id, agent]) => {
|
|
3669
|
-
const apy = await agent.getAgentApy(days, agentOptions);
|
|
4086
|
+
const apy = await this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
|
|
3670
4087
|
return [id, apy];
|
|
3671
4088
|
})
|
|
3672
4089
|
);
|
|
@@ -3693,7 +4110,7 @@ var OwneySDK = class {
|
|
|
3693
4110
|
const entries = [...activeAgents.entries()];
|
|
3694
4111
|
const balanceResults = await Promise.allSettled(
|
|
3695
4112
|
entries.map(async ([id, agent]) => {
|
|
3696
|
-
const b = await agent.getBalances(state, chainId);
|
|
4113
|
+
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
3697
4114
|
return [id, b.positions ?? []];
|
|
3698
4115
|
})
|
|
3699
4116
|
);
|
|
@@ -3701,6 +4118,7 @@ var OwneySDK = class {
|
|
|
3701
4118
|
const allPositions = [];
|
|
3702
4119
|
let successCount = 0;
|
|
3703
4120
|
const agentErrors = {};
|
|
4121
|
+
const agentFailures = [];
|
|
3704
4122
|
for (let i = 0; i < balanceResults.length; i++) {
|
|
3705
4123
|
const settled = balanceResults[i];
|
|
3706
4124
|
const [aid] = entries[i];
|
|
@@ -3715,6 +4133,7 @@ var OwneySDK = class {
|
|
|
3715
4133
|
successCount += 1;
|
|
3716
4134
|
} else {
|
|
3717
4135
|
const reason = settled.reason;
|
|
4136
|
+
agentFailures.push(reason);
|
|
3718
4137
|
agentErrors[aid] = reason instanceof Error ? reason.message : String(reason);
|
|
3719
4138
|
console.error(`getAllocationApy agent "${aid}" failed:`, reason);
|
|
3720
4139
|
}
|
|
@@ -3723,7 +4142,7 @@ var OwneySDK = class {
|
|
|
3723
4142
|
throw new OwneyError(
|
|
3724
4143
|
"ALLOCATION_ALL_FAILED",
|
|
3725
4144
|
"Failed to fetch allocation APY: all agents failed.",
|
|
3726
|
-
{ agentErrors }
|
|
4145
|
+
{ agentErrors, failures: agentFailures }
|
|
3727
4146
|
);
|
|
3728
4147
|
}
|
|
3729
4148
|
const overall = computeAllocationApy(allPositions);
|