@owney/sdk 0.7.22-beta.1 → 0.7.23
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 +352 -1471
- package/dist/index.d.cts +60 -20
- package/dist/index.d.ts +60 -20
- package/dist/index.js +310 -119
- package/package.json +3 -5
- package/dist/chunk-3HL52KM7.js +0 -283
- package/dist/chunk-AURO3C3R.js +0 -58
- package/dist/chunk-XBDJWZXY.js +0 -141
- package/dist/surfliquid.agent-AE7RZ66F.js +0 -638
- package/dist/surfliquid.smart-account-C535356J.js +0 -135
package/dist/index.cjs
CHANGED
|
@@ -3,1317 +3,19 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
for (var name in all)
|
|
16
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
-
};
|
|
18
|
-
var __copyProps = (to, from, except, desc) => {
|
|
19
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
-
for (let key2 of __getOwnPropNames(from))
|
|
21
|
-
if (!__hasOwnProp.call(to, key2) && key2 !== except)
|
|
22
|
-
__defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
|
|
23
|
-
}
|
|
24
|
-
return to;
|
|
25
|
-
};
|
|
26
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
-
|
|
28
|
-
// src/errors.ts
|
|
29
|
-
var OwneyError, AgentNotFoundError, NotConnectedError, AgentChainIncompatibleError;
|
|
30
|
-
var init_errors = __esm({
|
|
31
|
-
"src/errors.ts"() {
|
|
32
|
-
"use strict";
|
|
33
|
-
OwneyError = class extends Error {
|
|
34
|
-
code;
|
|
35
|
-
details;
|
|
36
|
-
agentId;
|
|
37
|
-
constructor(code, message, details, agentId) {
|
|
38
|
-
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
39
|
-
super(`${prefix} ${message}`);
|
|
40
|
-
this.name = "OwneyError";
|
|
41
|
-
this.code = code;
|
|
42
|
-
this.details = details;
|
|
43
|
-
this.agentId = agentId;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
AgentNotFoundError = class extends OwneyError {
|
|
47
|
-
constructor(agentId, available) {
|
|
48
|
-
super(
|
|
49
|
-
"AGENT_NOT_FOUND",
|
|
50
|
-
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
51
|
-
{ agentId, available },
|
|
52
|
-
agentId
|
|
53
|
-
);
|
|
54
|
-
this.name = "AgentNotFoundError";
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
NotConnectedError = class extends OwneyError {
|
|
58
|
-
constructor() {
|
|
59
|
-
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
60
|
-
this.name = "NotConnectedError";
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
AgentChainIncompatibleError = class extends OwneyError {
|
|
64
|
-
incompatibleAgents;
|
|
65
|
-
connectedChainId;
|
|
66
|
-
constructor(incompatibleAgents, connectedChainId) {
|
|
67
|
-
const details = incompatibleAgents.map(
|
|
68
|
-
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
69
|
-
).join("; ");
|
|
70
|
-
super(
|
|
71
|
-
"AGENT_CHAIN_INCOMPATIBLE",
|
|
72
|
-
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
73
|
-
{ incompatibleAgents, connectedChainId }
|
|
74
|
-
);
|
|
75
|
-
this.name = "AgentChainIncompatibleError";
|
|
76
|
-
this.incompatibleAgents = incompatibleAgents;
|
|
77
|
-
this.connectedChainId = connectedChainId;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// src/lib/debug.ts
|
|
84
|
-
function setOwneyDebug(enabled) {
|
|
85
|
-
configuredDebug = enabled;
|
|
86
|
-
}
|
|
87
|
-
function isOwneyDebug() {
|
|
88
|
-
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
89
|
-
}
|
|
90
|
-
function debugLog(scope, message, data) {
|
|
91
|
-
if (!isOwneyDebug()) return;
|
|
92
|
-
if (data === void 0) {
|
|
93
|
-
console.log(`[${scope}] ${message}`);
|
|
94
|
-
} else {
|
|
95
|
-
console.log(`[${scope}] ${message}`, data);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
var configuredDebug;
|
|
99
|
-
var init_debug = __esm({
|
|
100
|
-
"src/lib/debug.ts"() {
|
|
101
|
-
"use strict";
|
|
102
|
-
configuredDebug = false;
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// src/lib/routing-api.ts
|
|
107
|
-
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
108
|
-
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
109
|
-
try {
|
|
110
|
-
const res = await fetch(url, {
|
|
111
|
-
method: "GET",
|
|
112
|
-
headers: {
|
|
113
|
-
"Content-Type": "application/json",
|
|
114
|
-
"x-owney-api-key": `${apiKey}`
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
if (!res.ok) {
|
|
118
|
-
if (res.status !== 404) {
|
|
119
|
-
console.warn(
|
|
120
|
-
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
const json = await res.json();
|
|
126
|
-
const policy = json.success ? json.data ?? null : null;
|
|
127
|
-
debugLog(
|
|
128
|
-
"owney-sdk",
|
|
129
|
-
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
130
|
-
policy ?? void 0
|
|
131
|
-
);
|
|
132
|
-
return policy;
|
|
133
|
-
} catch (error) {
|
|
134
|
-
console.warn(
|
|
135
|
-
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
136
|
-
error instanceof Error ? error.message : String(error)
|
|
137
|
-
);
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
142
|
-
const url = `${baseUrl}/api/v1/agent/keys`;
|
|
143
|
-
const res = await fetch(url, {
|
|
144
|
-
method: "GET",
|
|
145
|
-
headers: {
|
|
146
|
-
"Content-Type": "application/json",
|
|
147
|
-
"x-owney-api-key": `${apiKey}`
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
if (!res.ok) {
|
|
151
|
-
const text = await res.text().catch(() => "");
|
|
152
|
-
throw new OwneyError(
|
|
153
|
-
"API_ROUTING_ERROR",
|
|
154
|
-
`Routing API error ${res.status}: ${text}`,
|
|
155
|
-
{ statusCode: res.status, responseBody: text }
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
const json = await res.json();
|
|
159
|
-
if (!json.success) {
|
|
160
|
-
throw new OwneyError(
|
|
161
|
-
"API_ROUTING_FAILED",
|
|
162
|
-
`Routing API request failed: ${json.message}`,
|
|
163
|
-
{ message: json.message }
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
return json.data;
|
|
167
|
-
}
|
|
168
|
-
var ROUTING_API_BASE_URL;
|
|
169
|
-
var init_routing_api = __esm({
|
|
170
|
-
"src/lib/routing-api.ts"() {
|
|
171
|
-
"use strict";
|
|
172
|
-
init_errors();
|
|
173
|
-
init_debug();
|
|
174
|
-
ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// src/lib/transfer-auth.ts
|
|
179
|
-
function buildTransferWithAuthorizationTypedData(input) {
|
|
180
|
-
return {
|
|
181
|
-
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
182
|
-
types: {
|
|
183
|
-
TransferWithAuthorization: [
|
|
184
|
-
{ name: "from", type: "address" },
|
|
185
|
-
{ name: "to", type: "address" },
|
|
186
|
-
{ name: "value", type: "uint256" },
|
|
187
|
-
{ name: "validAfter", type: "uint256" },
|
|
188
|
-
{ name: "validBefore", type: "uint256" },
|
|
189
|
-
{ name: "nonce", type: "bytes32" }
|
|
190
|
-
]
|
|
191
|
-
},
|
|
192
|
-
primaryType: "TransferWithAuthorization",
|
|
193
|
-
message: input.message
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
async function readTokenMeta(publicClient, token) {
|
|
197
|
-
const [tokenName, tokenVersion] = await Promise.all([
|
|
198
|
-
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
199
|
-
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
200
|
-
]);
|
|
201
|
-
return { tokenName, tokenVersion };
|
|
202
|
-
}
|
|
203
|
-
function randomAuthNonce() {
|
|
204
|
-
const bytes = new Uint8Array(32);
|
|
205
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
206
|
-
return (0, import_viem3.bytesToHex)(bytes);
|
|
207
|
-
}
|
|
208
|
-
function buildPermitTypedData(input) {
|
|
209
|
-
return {
|
|
210
|
-
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
211
|
-
types: {
|
|
212
|
-
Permit: [
|
|
213
|
-
{ name: "owner", type: "address" },
|
|
214
|
-
{ name: "spender", type: "address" },
|
|
215
|
-
{ name: "value", type: "uint256" },
|
|
216
|
-
{ name: "nonce", type: "uint256" },
|
|
217
|
-
{ name: "deadline", type: "uint256" }
|
|
218
|
-
]
|
|
219
|
-
},
|
|
220
|
-
primaryType: "Permit",
|
|
221
|
-
message: input.message
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
var import_viem3, ERC20_META_ABI;
|
|
225
|
-
var init_transfer_auth = __esm({
|
|
226
|
-
"src/lib/transfer-auth.ts"() {
|
|
227
|
-
"use strict";
|
|
228
|
-
import_viem3 = require("viem");
|
|
229
|
-
ERC20_META_ABI = [
|
|
230
|
-
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
231
|
-
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
232
|
-
];
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
// src/agents/surfliquid/surfliquid.constants.ts
|
|
237
|
-
var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_PERMIT_CAP, SURFLIQUID_PERMIT_TTL_SECONDS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
|
|
238
|
-
var init_surfliquid_constants = __esm({
|
|
239
|
-
"src/agents/surfliquid/surfliquid.constants.ts"() {
|
|
240
|
-
"use strict";
|
|
241
|
-
SURFLIQUID_CHAIN_ID = 8453;
|
|
242
|
-
SURFLIQUID_CHAIN_NAME = "BASE";
|
|
243
|
-
SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
244
|
-
SURFLIQUID_PERMIT_CAP = 10000000000n;
|
|
245
|
-
SURFLIQUID_PERMIT_TTL_SECONDS = 3600n;
|
|
246
|
-
SURFLIQUID_MIN_DEPOSIT = "0";
|
|
247
|
-
SURFLIQUID_SUPPORTED_ASSETS = [
|
|
248
|
-
{
|
|
249
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
250
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
251
|
-
assets: [{ symbol: "USDC", minDepositAmount: SURFLIQUID_MIN_DEPOSIT }]
|
|
252
|
-
}
|
|
253
|
-
];
|
|
254
|
-
SURFLIQUID_ACTION_MAP = {
|
|
255
|
-
// INITIAL_DEPOSIT is the user's real first deposit, so surface it like any
|
|
256
|
-
// other funding ("Top up"). The mini-app intentionally hides the "Deposit"
|
|
257
|
-
// action (it marks Zyfai's smart-account-creation event), which would
|
|
258
|
-
// otherwise drop a SurfLiquid user's only history row.
|
|
259
|
-
INITIAL_DEPOSIT: "Top up",
|
|
260
|
-
DEPOSIT: "Top up",
|
|
261
|
-
USER_DEPOSIT: "Top up",
|
|
262
|
-
WITHDRAWAL: "Withdraw",
|
|
263
|
-
USER_WITHDRAWAL: "Withdraw",
|
|
264
|
-
REBALANCE: "Rebalance",
|
|
265
|
-
REBALANCE_COMPLETED: "Rebalance",
|
|
266
|
-
CROSS_CHAIN_REBALANCE: "Rebalance",
|
|
267
|
-
MERKL_CLAIM: "Earned"
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// src/agents/surfliquid/surfliquid.session-store.ts
|
|
273
|
-
var KEY_PREFIX2, EXPIRY_SKEW_MS, memorySessions2, storage2, buildKey2, isFresh, readSurfSession, writeSurfSession, clearSurfSession;
|
|
274
|
-
var init_surfliquid_session_store = __esm({
|
|
275
|
-
"src/agents/surfliquid/surfliquid.session-store.ts"() {
|
|
276
|
-
"use strict";
|
|
277
|
-
KEY_PREFIX2 = "owney.surfliquid.session";
|
|
278
|
-
EXPIRY_SKEW_MS = 3e4;
|
|
279
|
-
memorySessions2 = /* @__PURE__ */ new Map();
|
|
280
|
-
storage2 = () => {
|
|
281
|
-
if (typeof window === "undefined") return null;
|
|
282
|
-
try {
|
|
283
|
-
return window.localStorage;
|
|
284
|
-
} catch {
|
|
285
|
-
return null;
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
buildKey2 = (apiKey, wallet) => `${KEY_PREFIX2}:${apiKey}:${wallet.toLowerCase()}`;
|
|
289
|
-
isFresh = (session) => {
|
|
290
|
-
if (!session?.token) return false;
|
|
291
|
-
if (!session.expiresAt) return true;
|
|
292
|
-
const expiresAt = Date.parse(session.expiresAt);
|
|
293
|
-
if (Number.isNaN(expiresAt)) return true;
|
|
294
|
-
return Date.now() < expiresAt - EXPIRY_SKEW_MS;
|
|
295
|
-
};
|
|
296
|
-
readSurfSession = (apiKey, wallet) => {
|
|
297
|
-
const key2 = buildKey2(apiKey, wallet);
|
|
298
|
-
let raw = null;
|
|
299
|
-
try {
|
|
300
|
-
raw = storage2()?.getItem(key2) ?? null;
|
|
301
|
-
} catch {
|
|
302
|
-
raw = null;
|
|
303
|
-
}
|
|
304
|
-
if (raw) {
|
|
305
|
-
try {
|
|
306
|
-
const parsed = JSON.parse(raw);
|
|
307
|
-
if (isFresh(parsed)) return parsed;
|
|
308
|
-
} catch {
|
|
309
|
-
}
|
|
310
|
-
clearSurfSession(apiKey, wallet);
|
|
311
|
-
return null;
|
|
312
|
-
}
|
|
313
|
-
const cached = memorySessions2.get(key2);
|
|
314
|
-
if (isFresh(cached)) return cached;
|
|
315
|
-
if (cached) memorySessions2.delete(key2);
|
|
316
|
-
return null;
|
|
317
|
-
};
|
|
318
|
-
writeSurfSession = (apiKey, wallet, session) => {
|
|
319
|
-
const key2 = buildKey2(apiKey, wallet);
|
|
320
|
-
memorySessions2.set(key2, session);
|
|
321
|
-
try {
|
|
322
|
-
storage2()?.setItem(key2, JSON.stringify(session));
|
|
323
|
-
} catch {
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
clearSurfSession = (apiKey, wallet) => {
|
|
327
|
-
const key2 = buildKey2(apiKey, wallet);
|
|
328
|
-
memorySessions2.delete(key2);
|
|
329
|
-
try {
|
|
330
|
-
storage2()?.removeItem(key2);
|
|
331
|
-
} catch {
|
|
332
|
-
}
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
// src/agents/surfliquid/surfliquid.broker.ts
|
|
338
|
-
function parseJson(text) {
|
|
339
|
-
try {
|
|
340
|
-
return JSON.parse(text);
|
|
341
|
-
} catch {
|
|
342
|
-
return void 0;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
function normalizeVault(json) {
|
|
346
|
-
const root = asRecord(json);
|
|
347
|
-
const data = asRecord(root.data);
|
|
348
|
-
const vault = asRecord(root.vault ?? data.vault ?? root.data ?? root);
|
|
349
|
-
const userVaultAddress = vault.userVaultAddress ?? null;
|
|
350
|
-
return {
|
|
351
|
-
userVaultAddress,
|
|
352
|
-
deploymentSalt: vault.deploymentSalt ?? null,
|
|
353
|
-
exists: Boolean(userVaultAddress),
|
|
354
|
-
walletAddress: vault.walletAddress ?? null,
|
|
355
|
-
homeChainId: vault.homeChainId ?? null,
|
|
356
|
-
vaultVersion: vault.vaultVersion ?? null,
|
|
357
|
-
isActive: vault.isActive,
|
|
358
|
-
totalValueUSD: vault.totalValueUSD ?? null,
|
|
359
|
-
totalDepositedUSD: vault.totalDepositedUSD ?? null,
|
|
360
|
-
earned: vault.earned ?? null,
|
|
361
|
-
apyBreakdown: vault.apyBreakdown ?? null,
|
|
362
|
-
league: vault.league ?? null,
|
|
363
|
-
assets: vault.assets ?? [],
|
|
364
|
-
chainAddresses: vault.chainAddresses ?? []
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
function normalizeSupportedAssets(json, chainId) {
|
|
368
|
-
const root = asRecord(json);
|
|
369
|
-
const data = asRecord(root.data);
|
|
370
|
-
const vault = asRecord(root.vault ?? data.vault ?? root.data ?? root);
|
|
371
|
-
const source = vault.assets ?? vault.defaultAssets ?? root.defaultAssets ?? data.defaultAssets ?? [];
|
|
372
|
-
const assets = source.map((asset) => ({
|
|
373
|
-
assetAddress: asset.assetAddress,
|
|
374
|
-
assetSymbol: asset.assetSymbol,
|
|
375
|
-
assetDecimals: asset.assetDecimals,
|
|
376
|
-
chainId: asset.chainId,
|
|
377
|
-
chainStatus: asset.chainStatus,
|
|
378
|
-
currentAPY: asset.currentAPY,
|
|
379
|
-
nativeAPY: asset.nativeAPY,
|
|
380
|
-
merklAPY: asset.merklAPY,
|
|
381
|
-
leagueAPY: asset.leagueAPY,
|
|
382
|
-
apy7d: asset.apy7d ?? null,
|
|
383
|
-
apy14d: asset.apy14d ?? null,
|
|
384
|
-
apy30d: asset.apy30d ?? null
|
|
385
|
-
}));
|
|
386
|
-
return chainId === void 0 ? assets : assets.filter((asset) => asset.chainId === chainId);
|
|
387
|
-
}
|
|
388
|
-
function createSurfBroker(options) {
|
|
389
|
-
const fetchImpl = options.fetchImpl ?? fetch;
|
|
390
|
-
const now = options.now ?? Date.now;
|
|
391
|
-
const base5 = `${options.routingApiBaseUrl.replace(/\/$/, "")}/api/v1/surf`;
|
|
392
|
-
const wallet = options.walletAddress;
|
|
393
|
-
let session = readSurfSession(options.apiKey, wallet);
|
|
394
|
-
const vaultMemo = /* @__PURE__ */ new Map();
|
|
395
|
-
const storeSession = (next) => {
|
|
396
|
-
session = next;
|
|
397
|
-
writeSurfSession(options.apiKey, wallet, next);
|
|
398
|
-
};
|
|
399
|
-
const dropSession = () => {
|
|
400
|
-
session = null;
|
|
401
|
-
clearSurfSession(options.apiKey, wallet);
|
|
402
|
-
};
|
|
403
|
-
async function call2(method, path, body, isAuthCall = false) {
|
|
404
|
-
const headers = { "x-owney-api-key": options.apiKey };
|
|
405
|
-
if (session?.token) headers[SURF_SESSION_HEADER] = session.token;
|
|
406
|
-
if (body !== void 0) headers["content-type"] = "application/json";
|
|
407
|
-
if (options.origin) headers["origin"] = options.origin;
|
|
408
|
-
let response;
|
|
409
|
-
try {
|
|
410
|
-
response = await fetchImpl(`${base5}${path}`, {
|
|
411
|
-
method,
|
|
412
|
-
headers,
|
|
413
|
-
body: body === void 0 ? void 0 : JSON.stringify(body),
|
|
414
|
-
signal: AbortSignal.timeout(SURF_BROKER_TIMEOUT_MS)
|
|
415
|
-
});
|
|
416
|
-
} catch (error) {
|
|
417
|
-
throw unavailable(
|
|
418
|
-
`SurfLiquid broker unreachable: ${error instanceof Error ? error.message : String(error)}`,
|
|
419
|
-
{ path }
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
const rotated = response.headers.get(SURF_SESSION_HEADER);
|
|
423
|
-
if (rotated && rotated !== session?.token) {
|
|
424
|
-
storeSession({ token: rotated, expiresAt: session?.expiresAt ?? null });
|
|
425
|
-
}
|
|
426
|
-
if (response.status === 401 && !isAuthCall) {
|
|
427
|
-
dropSession();
|
|
428
|
-
throw new SurfSessionExpiredError();
|
|
429
|
-
}
|
|
430
|
-
const text = await response.text();
|
|
431
|
-
const json = parseJson(text);
|
|
432
|
-
if (!response.ok) {
|
|
433
|
-
throw unavailable(`SurfLiquid broker responded ${response.status} on ${path}`, {
|
|
434
|
-
status: response.status,
|
|
435
|
-
body: json ?? text
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
return json;
|
|
439
|
-
}
|
|
440
|
-
const sessionFrom = (json) => {
|
|
441
|
-
const body = asRecord(json);
|
|
442
|
-
if (typeof body.token !== "string") throw unavailable("SurfLiquid login returned no session token");
|
|
443
|
-
const next = { token: body.token, expiresAt: typeof body.expiresAt === "string" ? body.expiresAt : null };
|
|
444
|
-
storeSession(next);
|
|
445
|
-
return next;
|
|
446
|
-
};
|
|
447
|
-
return {
|
|
448
|
-
hasSession: () => session !== null,
|
|
449
|
-
clearSession: dropSession,
|
|
450
|
-
nonce: async () => {
|
|
451
|
-
const json = await call2("POST", "/auth/nonce", { walletAddress: wallet }, true);
|
|
452
|
-
const message = json?.data?.message;
|
|
453
|
-
if (typeof message !== "string") throw unavailable("SurfLiquid nonce response had no message");
|
|
454
|
-
return message;
|
|
455
|
-
},
|
|
456
|
-
login: async (message, signature) => sessionFrom(await call2("POST", "/auth/login", { walletAddress: wallet, message, signature }, true)),
|
|
457
|
-
getVault: (walletAddress) => {
|
|
458
|
-
const key2 = walletAddress.toLowerCase();
|
|
459
|
-
const hit = vaultMemo.get(key2);
|
|
460
|
-
if (hit && now() - hit.at < VAULT_MEMO_TTL_MS) return hit.value;
|
|
461
|
-
const query = new URLSearchParams({ walletAddress });
|
|
462
|
-
const value = (async () => normalizeVault(await call2("GET", `/vault?${query.toString()}`)))();
|
|
463
|
-
vaultMemo.set(key2, { at: now(), value });
|
|
464
|
-
value.catch(() => vaultMemo.delete(key2));
|
|
465
|
-
return value;
|
|
466
|
-
},
|
|
467
|
-
invalidateVault: () => vaultMemo.clear(),
|
|
468
|
-
prepare: async (homeChainId) => {
|
|
469
|
-
const json = asRecord(await call2("POST", "/vault/prepare", { homeChainId }));
|
|
470
|
-
const prepared = asRecord(json.data ?? json);
|
|
471
|
-
if (typeof prepared.salt !== "string") throw unavailable("SurfLiquid prepare returned no salt");
|
|
472
|
-
return { salt: prepared.salt };
|
|
473
|
-
},
|
|
474
|
-
confirm: async (input) => {
|
|
475
|
-
await call2("POST", "/vault/confirm", input);
|
|
476
|
-
vaultMemo.clear();
|
|
477
|
-
},
|
|
478
|
-
getBestVault: async (assetSymbol) => {
|
|
479
|
-
const json = await call2("GET", `/vaults/best?assetSymbol=${encodeURIComponent(assetSymbol)}`);
|
|
480
|
-
const root = asRecord(json);
|
|
481
|
-
const list = root.vaults ?? root.data ?? json;
|
|
482
|
-
return Array.isArray(list) ? list : [];
|
|
483
|
-
},
|
|
484
|
-
getAgentMessages: async (walletAddress, page, limit, fromDate, toDate) => {
|
|
485
|
-
const query = new URLSearchParams({ walletAddress, page: String(page), limit: String(limit) });
|
|
486
|
-
if (fromDate) query.set("from", fromDate);
|
|
487
|
-
if (toDate) query.set("to", toDate);
|
|
488
|
-
const json = asRecord(await call2("GET", `/agent-messages?${query.toString()}`));
|
|
489
|
-
const data = asRecord(json.data ?? json);
|
|
490
|
-
return {
|
|
491
|
-
page: data.page ?? page,
|
|
492
|
-
limit: data.limit ?? limit,
|
|
493
|
-
total: data.total ?? 0,
|
|
494
|
-
pages: data.pages ?? 1,
|
|
495
|
-
messages: data.messages ?? []
|
|
496
|
-
};
|
|
497
|
-
},
|
|
498
|
-
getSupportedAssets: async (chainId) => normalizeSupportedAssets(
|
|
499
|
-
await call2("GET", `/vault?${new URLSearchParams({ walletAddress: DISCOVERY_WALLET }).toString()}`),
|
|
500
|
-
chainId
|
|
501
|
-
)
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
var SURF_SESSION_HEADER, SURF_BROKER_TIMEOUT_MS, VAULT_MEMO_TTL_MS, AGENT_ID, DISCOVERY_WALLET, SurfSessionExpiredError, asRecord, unavailable;
|
|
505
|
-
var init_surfliquid_broker = __esm({
|
|
506
|
-
"src/agents/surfliquid/surfliquid.broker.ts"() {
|
|
507
|
-
"use strict";
|
|
508
|
-
init_errors();
|
|
509
|
-
init_surfliquid_session_store();
|
|
510
|
-
SURF_SESSION_HEADER = "x-surf-session";
|
|
511
|
-
SURF_BROKER_TIMEOUT_MS = 7e4;
|
|
512
|
-
VAULT_MEMO_TTL_MS = 1e4;
|
|
513
|
-
AGENT_ID = "surfliquid";
|
|
514
|
-
DISCOVERY_WALLET = "0x";
|
|
515
|
-
SurfSessionExpiredError = class extends Error {
|
|
516
|
-
constructor() {
|
|
517
|
-
super("SurfLiquid session expired");
|
|
518
|
-
this.name = "SurfSessionExpiredError";
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
asRecord = (value) => value && typeof value === "object" ? value : {};
|
|
522
|
-
unavailable = (message, details) => new OwneyError("SURF_UNAVAILABLE", message, details, AGENT_ID);
|
|
523
|
-
}
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
// src/agents/surfliquid/surfliquid.mapper.ts
|
|
527
|
-
function mapMessage(message) {
|
|
528
|
-
const action = SURFLIQUID_ACTION_MAP[message.transactionType];
|
|
529
|
-
if (!action) return null;
|
|
530
|
-
return {
|
|
531
|
-
agent: "surfliquid",
|
|
532
|
-
action,
|
|
533
|
-
date: message.timestamp,
|
|
534
|
-
oldApy: message.apyBefore != null ? String(message.apyBefore) : null,
|
|
535
|
-
newApy: message.apyAfter != null ? String(message.apyAfter) : null,
|
|
536
|
-
transactions: [
|
|
537
|
-
{
|
|
538
|
-
txHashes: [message.txHash],
|
|
539
|
-
chainId: message.chainId,
|
|
540
|
-
tokenSymbol: message.token ?? void 0,
|
|
541
|
-
amount: message.amount != null ? String(message.amount) : void 0
|
|
542
|
-
}
|
|
543
|
-
],
|
|
544
|
-
rebalanceLog: []
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
function mapHistory(result, _chainId) {
|
|
548
|
-
const data = result.messages.map(mapMessage).filter((entry) => entry !== null);
|
|
549
|
-
const hasMore = result.page < result.pages;
|
|
550
|
-
return {
|
|
551
|
-
data,
|
|
552
|
-
hasMore,
|
|
553
|
-
nextCursor: hasMore ? String(result.page + 1) : void 0
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
function mapBalances2(vault, chainId, morphoStats) {
|
|
557
|
-
const assets = (vault.assets ?? []).filter(
|
|
558
|
-
(asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId
|
|
559
|
-
);
|
|
560
|
-
const tokens = assets.map((asset) => ({
|
|
561
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
562
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
563
|
-
asset: "USDC",
|
|
564
|
-
amount: String(asset.currentValueUSD)
|
|
565
|
-
}));
|
|
566
|
-
const positions = assets.map((asset) => {
|
|
567
|
-
const stats = morphoStats?.get(asset.morphoVaultAddress?.toLowerCase() ?? "");
|
|
568
|
-
return {
|
|
569
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
570
|
-
protocol: "Morpho",
|
|
571
|
-
// The specific MetaMorpho vault (e.g. "Gauntlet USDC Frontier"), read from
|
|
572
|
-
// Morpho — renders as "Morpho <vault>" alongside zyfai's vault detail.
|
|
573
|
-
pool: stats?.name ?? void 0,
|
|
574
|
-
asset: "USDC",
|
|
575
|
-
amount: String(asset.currentValueUSD),
|
|
576
|
-
apy: asset.currentAPY,
|
|
577
|
-
// TVL + liquidity come straight from Morpho (SurfLiquid's API omits them).
|
|
578
|
-
tvl: stats?.tvlUsd,
|
|
579
|
-
liquidity: stats?.liquidityUsd
|
|
580
|
-
};
|
|
581
|
-
});
|
|
582
|
-
const total = assets.reduce(
|
|
583
|
-
(sum, asset) => sum + asset.currentValueUSD,
|
|
584
|
-
0
|
|
585
|
-
);
|
|
586
|
-
return {
|
|
587
|
-
smartWallet: vault.userVaultAddress ?? void 0,
|
|
588
|
-
totalBalance: String(total),
|
|
589
|
-
totalBalanceAsset: "usdc",
|
|
590
|
-
tokens,
|
|
591
|
-
positions
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
function mapAccountApy(vault, days) {
|
|
595
|
-
const breakdown = vault.apyBreakdown;
|
|
596
|
-
const windowed = breakdown ? breakdown[APY_WINDOW_KEY[days]] : void 0;
|
|
597
|
-
const apy = windowed != null ? windowed : breakdown?.currentAPY ?? 0;
|
|
598
|
-
return {
|
|
599
|
-
walletAddress: vault.walletAddress ?? "",
|
|
600
|
-
weightedApyAfterFee: apy,
|
|
601
|
-
apyByChainAndAsset: { [SURFLIQUID_CHAIN_ID]: { USDC: apy } },
|
|
602
|
-
// Parity with Sail: SurfLiquid's core-sdk exposes no daily net-APY series.
|
|
603
|
-
history: []
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
function mapEarnings2(vault, vaultAddress) {
|
|
607
|
-
return {
|
|
608
|
-
smartWallet: vaultAddress,
|
|
609
|
-
lifetimeEarnings: vault.earned?.totalEarningsUSD ?? 0,
|
|
610
|
-
tokens: []
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
function mapUserProfile2(vault, address) {
|
|
614
|
-
return {
|
|
615
|
-
address,
|
|
616
|
-
smartWallet: vault.userVaultAddress ?? "",
|
|
617
|
-
chains: [SURFLIQUID_CHAIN_ID],
|
|
618
|
-
// SurfLiquid uses cookie-based session auth — no session-key concept.
|
|
619
|
-
hasActiveSessionKey: false,
|
|
620
|
-
protocols: ["SurfLiquid"]
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
var APY_WINDOW_KEY;
|
|
624
|
-
var init_surfliquid_mapper = __esm({
|
|
625
|
-
"src/agents/surfliquid/surfliquid.mapper.ts"() {
|
|
626
|
-
"use strict";
|
|
627
|
-
init_surfliquid_constants();
|
|
628
|
-
APY_WINDOW_KEY = {
|
|
629
|
-
"7D": "apy7d",
|
|
630
|
-
"14D": "apy14d",
|
|
631
|
-
"30D": "apy30d"
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
// src/agents/surfliquid/surfliquid.contracts.ts
|
|
637
|
-
var import_viem6, SURFLIQUID_FACTORY_ADDRESS, SURFLIQUID_FACTORY_ABI, SURFLIQUID_VAULT_ABI, USDC_ABI;
|
|
638
|
-
var init_surfliquid_contracts = __esm({
|
|
639
|
-
"src/agents/surfliquid/surfliquid.contracts.ts"() {
|
|
640
|
-
"use strict";
|
|
641
|
-
import_viem6 = require("viem");
|
|
642
|
-
SURFLIQUID_FACTORY_ADDRESS = "0x8fa50DeA8DB10987D7d22ac092001c3613C18779";
|
|
643
|
-
SURFLIQUID_FACTORY_ABI = (0, import_viem6.parseAbi)([
|
|
644
|
-
"function deployVault(address vaultOwner, bytes32 salt) returns (address)",
|
|
645
|
-
"function computeVaultAddress(address vaultOwner, bytes32 salt) view returns (address)"
|
|
646
|
-
]);
|
|
647
|
-
SURFLIQUID_VAULT_ABI = (0, import_viem6.parseAbi)([
|
|
648
|
-
"function initialDeposit(address asset, address vault, uint256 amount)",
|
|
649
|
-
"function userDeposit(address asset, uint256 amount)",
|
|
650
|
-
// amount 0 withdraws everything; proceeds go to the vault's owner.
|
|
651
|
-
"function withdraw(address asset, uint256 amount)",
|
|
652
|
-
"function assetHasInitialDeposit(address asset) view returns (bool)",
|
|
653
|
-
"function owner() view returns (address)"
|
|
654
|
-
]);
|
|
655
|
-
USDC_ABI = (0, import_viem6.parseAbi)([
|
|
656
|
-
"function approve(address spender, uint256 amount)",
|
|
657
|
-
"function transfer(address to, uint256 amount)",
|
|
658
|
-
"function transferFrom(address from, address to, uint256 value)",
|
|
659
|
-
"function balanceOf(address account) view returns (uint256)",
|
|
660
|
-
"function allowance(address owner, address spender) view returns (uint256)",
|
|
661
|
-
"function nonces(address owner) view returns (uint256)",
|
|
662
|
-
"function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)"
|
|
663
|
-
]);
|
|
664
|
-
}
|
|
665
|
-
});
|
|
666
|
-
|
|
667
|
-
// src/agents/surfliquid/surfliquid.calls.ts
|
|
668
|
-
function buildDepositCalls(input) {
|
|
669
|
-
const { smartAccount, owner, vault, amount, permit, deploySalt } = input;
|
|
670
|
-
if (permit && permit.owner.toLowerCase() !== owner.toLowerCase()) {
|
|
671
|
-
throw new Error("Permit must be signed by the smart account's owner");
|
|
672
|
-
}
|
|
673
|
-
if (permit && permit.value < amount) {
|
|
674
|
-
throw new Error("Permit allowance is worth less than the deposit");
|
|
675
|
-
}
|
|
676
|
-
if (!input.hasInitialDeposit && !input.morphoVault) {
|
|
677
|
-
throw new Error("A first deposit needs a target morpho vault");
|
|
678
|
-
}
|
|
679
|
-
const calls = [];
|
|
680
|
-
if (deploySalt) {
|
|
681
|
-
calls.push(
|
|
682
|
-
call(SURFLIQUID_FACTORY_ADDRESS, SURFLIQUID_FACTORY_ABI, "deployVault", [
|
|
683
|
-
smartAccount,
|
|
684
|
-
deploySalt
|
|
685
|
-
])
|
|
686
|
-
);
|
|
687
|
-
}
|
|
688
|
-
if (permit) {
|
|
689
|
-
calls.push(
|
|
690
|
-
call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "permit", [
|
|
691
|
-
permit.owner,
|
|
692
|
-
smartAccount,
|
|
693
|
-
permit.value,
|
|
694
|
-
permit.deadline,
|
|
695
|
-
permit.v,
|
|
696
|
-
permit.r,
|
|
697
|
-
permit.s
|
|
698
|
-
])
|
|
699
|
-
);
|
|
700
|
-
}
|
|
701
|
-
calls.push(
|
|
702
|
-
call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "transferFrom", [owner, smartAccount, amount]),
|
|
703
|
-
call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "approve", [vault, amount]),
|
|
704
|
-
input.hasInitialDeposit ? call(vault, SURFLIQUID_VAULT_ABI, "userDeposit", [SURFLIQUID_USDC_ADDRESS, amount]) : call(vault, SURFLIQUID_VAULT_ABI, "initialDeposit", [
|
|
705
|
-
SURFLIQUID_USDC_ADDRESS,
|
|
706
|
-
input.morphoVault,
|
|
707
|
-
amount
|
|
708
|
-
])
|
|
709
|
-
);
|
|
710
|
-
return calls;
|
|
711
|
-
}
|
|
712
|
-
function buildWithdrawCalls(input) {
|
|
713
|
-
return [
|
|
714
|
-
call(input.vault, SURFLIQUID_VAULT_ABI, "withdraw", [
|
|
715
|
-
SURFLIQUID_USDC_ADDRESS,
|
|
716
|
-
input.amount ?? 0n
|
|
717
|
-
])
|
|
718
|
-
];
|
|
719
|
-
}
|
|
720
|
-
function buildSweepCalls(input) {
|
|
721
|
-
return [call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "transfer", [input.owner, input.amount])];
|
|
722
|
-
}
|
|
723
|
-
var import_viem7, call;
|
|
724
|
-
var init_surfliquid_calls = __esm({
|
|
725
|
-
"src/agents/surfliquid/surfliquid.calls.ts"() {
|
|
726
|
-
"use strict";
|
|
727
|
-
import_viem7 = require("viem");
|
|
728
|
-
init_surfliquid_constants();
|
|
729
|
-
init_surfliquid_contracts();
|
|
730
|
-
call = (to, abi, functionName, args) => ({
|
|
731
|
-
to,
|
|
732
|
-
data: (0, import_viem7.encodeFunctionData)({ abi, functionName, args })
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
});
|
|
736
|
-
|
|
737
|
-
// src/agents/surfliquid/surfliquid.sponsorship.ts
|
|
738
|
-
async function resolveVault(ctx) {
|
|
739
|
-
const registered = await ctx.api.getVault(ctx.wallet.ownerAddress);
|
|
740
|
-
const smartAccount = ctx.wallet.smartAccountAddress;
|
|
741
|
-
if (!registered.userVaultAddress) {
|
|
742
|
-
const salt2 = registered.deploymentSalt ?? (await ctx.api.prepare(SURFLIQUID_CHAIN_ID)).salt;
|
|
743
|
-
return {
|
|
744
|
-
vault: await ctx.chain.computeVaultAddress(smartAccount, salt2),
|
|
745
|
-
deploySalt: salt2,
|
|
746
|
-
registerAfterDeposit: true
|
|
747
|
-
};
|
|
748
|
-
}
|
|
749
|
-
const vault = registered.userVaultAddress;
|
|
750
|
-
if (await ctx.chain.isDeployed(vault)) {
|
|
751
|
-
const owner = await ctx.chain.readVaultOwner(vault);
|
|
752
|
-
if (owner.toLowerCase() !== smartAccount.toLowerCase()) {
|
|
753
|
-
throw new VaultNotSponsorableError(`SurfLiquid vault ${vault} is not owned by the smart account`);
|
|
754
|
-
}
|
|
755
|
-
return { vault, registerAfterDeposit: false };
|
|
756
|
-
}
|
|
757
|
-
const salt = registered.deploymentSalt;
|
|
758
|
-
const deployable = salt ? await ctx.chain.computeVaultAddress(smartAccount, salt) : void 0;
|
|
759
|
-
if (!salt || deployable?.toLowerCase() !== vault.toLowerCase()) {
|
|
760
|
-
throw new VaultNotSponsorableError(`Registered SurfLiquid vault ${vault} does not match this smart account`);
|
|
761
|
-
}
|
|
762
|
-
return { vault, deploySalt: salt, registerAfterDeposit: false };
|
|
763
|
-
}
|
|
764
|
-
async function pickMorphoVault(api) {
|
|
765
|
-
const candidates = await api.getBestVault("USDC");
|
|
766
|
-
const candidate = candidates.find((option) => option.chainId === SURFLIQUID_CHAIN_ID);
|
|
767
|
-
if (!candidate) {
|
|
768
|
-
throw new Error(`SurfLiquid has no morpho vault for USDC on chain ${SURFLIQUID_CHAIN_ID}`);
|
|
769
|
-
}
|
|
770
|
-
return candidate.vaultAddress;
|
|
771
|
-
}
|
|
772
|
-
async function permitIfShort(input) {
|
|
773
|
-
const { chain, wallet, amount } = input;
|
|
774
|
-
const allowance = await chain.readAllowance(wallet.ownerAddress, wallet.smartAccountAddress);
|
|
775
|
-
if (allowance >= amount) return void 0;
|
|
776
|
-
const [{ tokenName, tokenVersion }, nonce] = await Promise.all([
|
|
777
|
-
chain.readTokenMeta(),
|
|
778
|
-
chain.readPermitNonce(wallet.ownerAddress)
|
|
779
|
-
]);
|
|
780
|
-
const message = {
|
|
781
|
-
owner: wallet.ownerAddress,
|
|
782
|
-
spender: wallet.smartAccountAddress,
|
|
783
|
-
value: amount > SURFLIQUID_PERMIT_CAP ? amount : SURFLIQUID_PERMIT_CAP,
|
|
784
|
-
nonce,
|
|
785
|
-
deadline: BigInt(Math.floor(Date.now() / 1e3)) + SURFLIQUID_PERMIT_TTL_SECONDS
|
|
786
|
-
};
|
|
787
|
-
const signature = await wallet.signPermit(
|
|
788
|
-
buildPermitTypedData({
|
|
789
|
-
token: SURFLIQUID_USDC_ADDRESS,
|
|
790
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
791
|
-
tokenName,
|
|
792
|
-
tokenVersion,
|
|
793
|
-
message
|
|
794
|
-
})
|
|
795
|
-
);
|
|
796
|
-
const { r, s, v, yParity } = (0, import_viem8.parseSignature)(signature);
|
|
797
|
-
return {
|
|
798
|
-
owner: message.owner,
|
|
799
|
-
value: message.value,
|
|
800
|
-
deadline: message.deadline,
|
|
801
|
-
v: Number(v ?? BigInt(yParity + 27)),
|
|
802
|
-
r,
|
|
803
|
-
s
|
|
804
|
-
};
|
|
805
|
-
}
|
|
806
|
-
async function depositSponsored(input) {
|
|
807
|
-
const { api, chain, wallet, amount } = input;
|
|
808
|
-
const { vault, deploySalt, registerAfterDeposit } = await resolveVault(input);
|
|
809
|
-
const hasInitialDeposit = deploySalt ? false : await chain.hasInitialDeposit(vault, SURFLIQUID_USDC_ADDRESS);
|
|
810
|
-
const morphoVault = hasInitialDeposit ? void 0 : await pickMorphoVault(api);
|
|
811
|
-
const permit = await permitIfShort({ chain, wallet, amount });
|
|
812
|
-
const txHash = await wallet.sendCalls(
|
|
813
|
-
buildDepositCalls({
|
|
814
|
-
smartAccount: wallet.smartAccountAddress,
|
|
815
|
-
owner: wallet.ownerAddress,
|
|
816
|
-
vault,
|
|
817
|
-
amount,
|
|
818
|
-
permit,
|
|
819
|
-
hasInitialDeposit,
|
|
820
|
-
morphoVault,
|
|
821
|
-
deploySalt
|
|
822
|
-
})
|
|
823
|
-
);
|
|
824
|
-
if (registerAfterDeposit && deploySalt) {
|
|
825
|
-
try {
|
|
826
|
-
await api.confirm({
|
|
827
|
-
userVaultAddress: vault,
|
|
828
|
-
homeChainId: SURFLIQUID_CHAIN_ID,
|
|
829
|
-
deploymentSalt: deploySalt,
|
|
830
|
-
initialAssets: []
|
|
831
|
-
});
|
|
832
|
-
} catch (error) {
|
|
833
|
-
console.warn(
|
|
834
|
-
"[owney-sdk] SurfLiquid vault registration failed after a successful deposit:",
|
|
835
|
-
error instanceof Error ? error.message : String(error)
|
|
836
|
-
);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
return { txHash, vault };
|
|
840
|
-
}
|
|
841
|
-
async function withdrawSponsored(input) {
|
|
842
|
-
const { api, chain, wallet, amount } = input;
|
|
843
|
-
const registered = await api.getVault(wallet.ownerAddress);
|
|
844
|
-
if (!registered.userVaultAddress) {
|
|
845
|
-
throw new Error("SurfLiquid has no vault registered for this wallet");
|
|
846
|
-
}
|
|
847
|
-
const vault = registered.userVaultAddress;
|
|
848
|
-
const owner = await chain.readVaultOwner(vault);
|
|
849
|
-
if (owner.toLowerCase() !== wallet.smartAccountAddress.toLowerCase()) {
|
|
850
|
-
throw new VaultNotSponsorableError(`SurfLiquid vault ${vault} is not owned by the smart account`);
|
|
851
|
-
}
|
|
852
|
-
const withdrawHash = await wallet.sendCalls(buildWithdrawCalls({ vault, amount }));
|
|
853
|
-
try {
|
|
854
|
-
const proceeds = await chain.usdcBalanceOf(wallet.smartAccountAddress);
|
|
855
|
-
if (proceeds === 0n) return { txHash: withdrawHash, amount: "0" };
|
|
856
|
-
const sweepHash = await wallet.sendCalls(
|
|
857
|
-
buildSweepCalls({ owner: wallet.ownerAddress, amount: proceeds })
|
|
858
|
-
);
|
|
859
|
-
return { txHash: sweepHash, amount: proceeds.toString() };
|
|
860
|
-
} catch (error) {
|
|
861
|
-
throw new SubmittedError(
|
|
862
|
-
`SurfLiquid withdrawal ${withdrawHash} landed but the sweep did not: ${error instanceof Error ? error.message : String(error)}`
|
|
863
|
-
);
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
var import_viem8, SubmittedError, VaultNotSponsorableError;
|
|
867
|
-
var init_surfliquid_sponsorship = __esm({
|
|
868
|
-
"src/agents/surfliquid/surfliquid.sponsorship.ts"() {
|
|
869
|
-
"use strict";
|
|
870
|
-
import_viem8 = require("viem");
|
|
871
|
-
init_transfer_auth();
|
|
872
|
-
init_surfliquid_constants();
|
|
873
|
-
init_surfliquid_calls();
|
|
874
|
-
SubmittedError = class extends Error {
|
|
875
|
-
constructor(message, userOpHash) {
|
|
876
|
-
super(message);
|
|
877
|
-
this.userOpHash = userOpHash;
|
|
878
|
-
this.name = "SubmittedError";
|
|
879
|
-
}
|
|
880
|
-
userOpHash;
|
|
881
|
-
};
|
|
882
|
-
VaultNotSponsorableError = class extends Error {
|
|
883
|
-
constructor(message) {
|
|
884
|
-
super(message);
|
|
885
|
-
this.name = "VaultNotSponsorableError";
|
|
886
|
-
}
|
|
887
|
-
};
|
|
888
|
-
}
|
|
889
|
-
});
|
|
890
|
-
|
|
891
|
-
// src/agents/surfliquid/surfliquid.morpho.ts
|
|
892
|
-
async function queryMorpho(query, vaultAddress, chainId) {
|
|
893
|
-
try {
|
|
894
|
-
const res = await fetch(MORPHO_API_URL, {
|
|
895
|
-
method: "POST",
|
|
896
|
-
headers: { "Content-Type": "application/json" },
|
|
897
|
-
body: JSON.stringify({
|
|
898
|
-
query,
|
|
899
|
-
variables: { address: vaultAddress, chainId }
|
|
900
|
-
})
|
|
901
|
-
});
|
|
902
|
-
if (!res.ok) return null;
|
|
903
|
-
const json = await res.json();
|
|
904
|
-
if (json.errors) return null;
|
|
905
|
-
return json.data ?? null;
|
|
906
|
-
} catch (error) {
|
|
907
|
-
console.warn("surfliquid: Morpho vault stats fetch failed", {
|
|
908
|
-
vaultAddress,
|
|
909
|
-
chainId,
|
|
910
|
-
error
|
|
911
|
-
});
|
|
912
|
-
return null;
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
function toStats(name, tvlUsd, liquidityUsd) {
|
|
916
|
-
if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
|
|
917
|
-
return null;
|
|
918
|
-
}
|
|
919
|
-
return {
|
|
920
|
-
name: typeof name === "string" ? name : null,
|
|
921
|
-
tvlUsd,
|
|
922
|
-
liquidityUsd
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
async function fetchMorphoVaultStats(vaultAddress, chainId) {
|
|
926
|
-
const v1 = await queryMorpho(VAULT_STATS_QUERY, vaultAddress, chainId);
|
|
927
|
-
const vault = v1?.vaultByAddress;
|
|
928
|
-
const v1Stats = toStats(
|
|
929
|
-
vault?.name,
|
|
930
|
-
vault?.state?.totalAssetsUsd,
|
|
931
|
-
vault?.liquidity?.usd
|
|
932
|
-
);
|
|
933
|
-
if (v1Stats) return v1Stats;
|
|
934
|
-
const v2 = await queryMorpho(VAULT_V2_STATS_QUERY, vaultAddress, chainId);
|
|
935
|
-
const vaultV2 = v2?.vaultV2ByAddress;
|
|
936
|
-
return toStats(vaultV2?.name, vaultV2?.totalAssetsUsd, vaultV2?.liquidityUsd);
|
|
937
|
-
}
|
|
938
|
-
async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
|
|
939
|
-
const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
|
|
940
|
-
const entries = await Promise.all(
|
|
941
|
-
unique.map(
|
|
942
|
-
async (address) => [address, await fetchMorphoVaultStats(address, chainId)]
|
|
943
|
-
)
|
|
944
|
-
);
|
|
945
|
-
const byVault = /* @__PURE__ */ new Map();
|
|
946
|
-
for (const [address, stats] of entries) {
|
|
947
|
-
if (stats) byVault.set(address, stats);
|
|
948
|
-
}
|
|
949
|
-
return byVault;
|
|
950
|
-
}
|
|
951
|
-
var MORPHO_API_URL, VAULT_STATS_QUERY, VAULT_V2_STATS_QUERY;
|
|
952
|
-
var init_surfliquid_morpho = __esm({
|
|
953
|
-
"src/agents/surfliquid/surfliquid.morpho.ts"() {
|
|
954
|
-
"use strict";
|
|
955
|
-
MORPHO_API_URL = "https://api.morpho.org/graphql";
|
|
956
|
-
VAULT_STATS_QUERY = `
|
|
957
|
-
query VaultStats($address: String!, $chainId: Int!) {
|
|
958
|
-
vaultByAddress(address: $address, chainId: $chainId) {
|
|
959
|
-
name
|
|
960
|
-
state { totalAssetsUsd }
|
|
961
|
-
liquidity { usd }
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
`;
|
|
965
|
-
VAULT_V2_STATS_QUERY = `
|
|
966
|
-
query VaultV2Stats($address: String!, $chainId: Int!) {
|
|
967
|
-
vaultV2ByAddress(address: $address, chainId: $chainId) {
|
|
968
|
-
name
|
|
969
|
-
totalAssetsUsd
|
|
970
|
-
liquidityUsd
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
`;
|
|
974
|
-
}
|
|
975
|
-
});
|
|
976
|
-
|
|
977
|
-
// src/agents/surfliquid/surfliquid.smart-account.ts
|
|
978
|
-
var surfliquid_smart_account_exports = {};
|
|
979
|
-
__export(surfliquid_smart_account_exports, {
|
|
980
|
-
createSponsoredChain: () => createSponsoredChain,
|
|
981
|
-
createSponsoredWallet: () => createSponsoredWallet,
|
|
982
|
-
pinAccount: () => pinAccount
|
|
983
|
-
});
|
|
984
|
-
function publicClientFor(rpcUrl) {
|
|
985
|
-
return (0, import_viem9.createPublicClient)({ chain: import_chains2.base, transport: (0, import_viem9.http)(rpcUrl) });
|
|
986
|
-
}
|
|
987
|
-
function createSponsoredChain(rpcUrl) {
|
|
988
|
-
const client = publicClientFor(rpcUrl);
|
|
989
|
-
return {
|
|
990
|
-
computeVaultAddress: (owner, salt) => client.readContract({
|
|
991
|
-
address: SURFLIQUID_FACTORY_ADDRESS,
|
|
992
|
-
abi: SURFLIQUID_FACTORY_ABI,
|
|
993
|
-
functionName: "computeVaultAddress",
|
|
994
|
-
args: [owner, salt]
|
|
995
|
-
}),
|
|
996
|
-
isDeployed: async (address) => {
|
|
997
|
-
const code = await client.getCode({ address });
|
|
998
|
-
return Boolean(code && code !== "0x");
|
|
999
|
-
},
|
|
1000
|
-
readVaultOwner: (vault) => client.readContract({ address: vault, abi: SURFLIQUID_VAULT_ABI, functionName: "owner" }),
|
|
1001
|
-
hasInitialDeposit: (vault, asset) => client.readContract({
|
|
1002
|
-
address: vault,
|
|
1003
|
-
abi: SURFLIQUID_VAULT_ABI,
|
|
1004
|
-
functionName: "assetHasInitialDeposit",
|
|
1005
|
-
args: [asset]
|
|
1006
|
-
}),
|
|
1007
|
-
usdcBalanceOf: (address) => client.readContract({
|
|
1008
|
-
address: SURFLIQUID_USDC_ADDRESS,
|
|
1009
|
-
abi: USDC_ABI,
|
|
1010
|
-
functionName: "balanceOf",
|
|
1011
|
-
args: [address]
|
|
1012
|
-
}),
|
|
1013
|
-
// Cast: viem's OP-stack tx union does not match the generic PublicClient
|
|
1014
|
-
// the helper is typed against, though every method it uses is present.
|
|
1015
|
-
readTokenMeta: () => readTokenMeta(client, SURFLIQUID_USDC_ADDRESS),
|
|
1016
|
-
readAllowance: (owner, spender) => client.readContract({
|
|
1017
|
-
address: SURFLIQUID_USDC_ADDRESS,
|
|
1018
|
-
abi: USDC_ABI,
|
|
1019
|
-
functionName: "allowance",
|
|
1020
|
-
args: [owner, spender]
|
|
1021
|
-
}),
|
|
1022
|
-
readPermitNonce: (owner) => client.readContract({
|
|
1023
|
-
address: SURFLIQUID_USDC_ADDRESS,
|
|
1024
|
-
abi: USDC_ABI,
|
|
1025
|
-
functionName: "nonces",
|
|
1026
|
-
args: [owner]
|
|
1027
|
-
})
|
|
1028
|
-
};
|
|
1029
|
-
}
|
|
1030
|
-
function pinAccount(provider, address) {
|
|
1031
|
-
return {
|
|
1032
|
-
...provider,
|
|
1033
|
-
request: (args) => args.method === "eth_accounts" || args.method === "eth_requestAccounts" ? Promise.resolve([address]) : provider.request(args)
|
|
1034
|
-
};
|
|
1035
|
-
}
|
|
1036
|
-
async function createSponsoredWallet(input) {
|
|
1037
|
-
const entryPoint = { address: import_account_abstraction.entryPoint08Address, version: "0.8" };
|
|
1038
|
-
const account = await (0, import_accounts.toSimpleSmartAccount)({
|
|
1039
|
-
client: publicClientFor(input.rpcUrl),
|
|
1040
|
-
owner: pinAccount(input.provider, input.ownerAddress),
|
|
1041
|
-
entryPoint
|
|
1042
|
-
});
|
|
1043
|
-
const bundlerTransport = (0, import_viem9.http)(sponsorProxyUrl(input.routingApiBaseUrl), {
|
|
1044
|
-
fetchOptions: { headers: { "x-owney-api-key": input.apiKey } }
|
|
1045
|
-
});
|
|
1046
|
-
const pimlico = (0, import_pimlico.createPimlicoClient)({ transport: bundlerTransport, entryPoint });
|
|
1047
|
-
const smartAccountClient = (0, import_permissionless.createSmartAccountClient)({
|
|
1048
|
-
account,
|
|
1049
|
-
chain: import_chains2.base,
|
|
1050
|
-
bundlerTransport,
|
|
1051
|
-
paymaster: pimlico,
|
|
1052
|
-
userOperation: {
|
|
1053
|
-
estimateFeesPerGas: async () => (await pimlico.getUserOperationGasPrice()).fast
|
|
1054
|
-
}
|
|
1055
|
-
});
|
|
1056
|
-
const walletClient = (0, import_viem9.createWalletClient)({
|
|
1057
|
-
account: input.ownerAddress,
|
|
1058
|
-
chain: import_chains2.base,
|
|
1059
|
-
transport: (0, import_viem9.custom)(input.provider)
|
|
1060
|
-
});
|
|
1061
|
-
return {
|
|
1062
|
-
smartAccountAddress: account.address,
|
|
1063
|
-
ownerAddress: input.ownerAddress,
|
|
1064
|
-
// The EOA signs, not the smart account: USDC verifies ECDSA from the token holder.
|
|
1065
|
-
signPermit: (typedData) => walletClient.signTypedData({
|
|
1066
|
-
account: input.ownerAddress,
|
|
1067
|
-
domain: typedData.domain,
|
|
1068
|
-
types: typedData.types,
|
|
1069
|
-
primaryType: typedData.primaryType,
|
|
1070
|
-
message: typedData.message
|
|
1071
|
-
}),
|
|
1072
|
-
sendCalls: async (calls) => {
|
|
1073
|
-
const userOpHash = await smartAccountClient.sendUserOperation({
|
|
1074
|
-
calls: calls.map((c) => ({ to: c.to, data: c.data, value: 0n }))
|
|
1075
|
-
});
|
|
1076
|
-
try {
|
|
1077
|
-
const receipt = await smartAccountClient.waitForUserOperationReceipt({ hash: userOpHash });
|
|
1078
|
-
return receipt.receipt.transactionHash;
|
|
1079
|
-
} catch (error) {
|
|
1080
|
-
throw new SubmittedError(
|
|
1081
|
-
`user operation ${userOpHash} was submitted but its receipt never arrived`,
|
|
1082
|
-
userOpHash
|
|
1083
|
-
);
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
};
|
|
1087
|
-
}
|
|
1088
|
-
var import_permissionless, import_accounts, import_pimlico, import_viem9, import_account_abstraction, import_chains2, sponsorProxyUrl;
|
|
1089
|
-
var init_surfliquid_smart_account = __esm({
|
|
1090
|
-
"src/agents/surfliquid/surfliquid.smart-account.ts"() {
|
|
1091
|
-
"use strict";
|
|
1092
|
-
import_permissionless = require("permissionless");
|
|
1093
|
-
import_accounts = require("permissionless/accounts");
|
|
1094
|
-
import_pimlico = require("permissionless/clients/pimlico");
|
|
1095
|
-
import_viem9 = require("viem");
|
|
1096
|
-
import_account_abstraction = require("viem/account-abstraction");
|
|
1097
|
-
import_chains2 = require("viem/chains");
|
|
1098
|
-
init_transfer_auth();
|
|
1099
|
-
init_surfliquid_constants();
|
|
1100
|
-
init_surfliquid_contracts();
|
|
1101
|
-
init_surfliquid_sponsorship();
|
|
1102
|
-
sponsorProxyUrl = (routingApiBaseUrl) => `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/sponsor/pimlico-rpc/${SURFLIQUID_CHAIN_ID}`;
|
|
1103
|
-
}
|
|
1104
|
-
});
|
|
1105
|
-
|
|
1106
|
-
// src/agents/surfliquid/surfliquid.agent.ts
|
|
1107
|
-
var surfliquid_agent_exports = {};
|
|
1108
|
-
__export(surfliquid_agent_exports, {
|
|
1109
|
-
SurfLiquidAgent: () => SurfLiquidAgent
|
|
1110
|
-
});
|
|
1111
|
-
function toOwneyError(error) {
|
|
1112
|
-
if (error instanceof OwneyError) return error;
|
|
1113
|
-
if (error instanceof SubmittedError) {
|
|
1114
|
-
return new OwneyError("OPERATION_PENDING", error.message, { userOpHash: error.userOpHash }, AGENT_ID2);
|
|
1115
|
-
}
|
|
1116
|
-
if (error instanceof VaultNotSponsorableError) {
|
|
1117
|
-
return new OwneyError("VAULT_NOT_SPONSORABLE", error.message, void 0, AGENT_ID2);
|
|
1118
|
-
}
|
|
1119
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1120
|
-
const code = error?.code;
|
|
1121
|
-
if (code === WALLET_REJECTED_CODE || /user rejected|user denied/i.test(message)) {
|
|
1122
|
-
return new OwneyError("USER_REJECTED", message, void 0, AGENT_ID2);
|
|
1123
|
-
}
|
|
1124
|
-
return new OwneyError("SPONSORSHIP_UNAVAILABLE", message, void 0, AGENT_ID2);
|
|
1125
|
-
}
|
|
1126
|
-
var import_viem10, import_chains3, AGENT_ID2, WALLET_REJECTED_CODE, DISCOVERY_WALLET2, HISTORY_DEFAULT_LIMIT, APY_WINDOW_KEY2, SurfLiquidAgent;
|
|
1127
|
-
var init_surfliquid_agent = __esm({
|
|
1128
|
-
"src/agents/surfliquid/surfliquid.agent.ts"() {
|
|
1129
|
-
"use strict";
|
|
1130
|
-
import_viem10 = require("viem");
|
|
1131
|
-
import_chains3 = require("viem/chains");
|
|
1132
|
-
init_errors();
|
|
1133
|
-
init_surfliquid_constants();
|
|
1134
|
-
init_surfliquid_broker();
|
|
1135
|
-
init_surfliquid_mapper();
|
|
1136
|
-
init_surfliquid_sponsorship();
|
|
1137
|
-
init_surfliquid_morpho();
|
|
1138
|
-
init_routing_api();
|
|
1139
|
-
AGENT_ID2 = "surfliquid";
|
|
1140
|
-
WALLET_REJECTED_CODE = 4001;
|
|
1141
|
-
DISCOVERY_WALLET2 = "0x";
|
|
1142
|
-
HISTORY_DEFAULT_LIMIT = 10;
|
|
1143
|
-
APY_WINDOW_KEY2 = {
|
|
1144
|
-
"7D": "apy7d",
|
|
1145
|
-
"14D": "apy14d",
|
|
1146
|
-
"30D": "apy30d"
|
|
1147
|
-
};
|
|
1148
|
-
SurfLiquidAgent = class {
|
|
1149
|
-
constructor(config) {
|
|
1150
|
-
this.config = config;
|
|
1151
|
-
}
|
|
1152
|
-
config;
|
|
1153
|
-
id = AGENT_ID2;
|
|
1154
|
-
supportedChainIds = [SURFLIQUID_CHAIN_ID];
|
|
1155
|
-
supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
|
|
1156
|
-
broker = null;
|
|
1157
|
-
brokerWallet = null;
|
|
1158
|
-
// Dedicated instance for the anonymous "0x" asset probe — never shares a slot
|
|
1159
|
-
// with the user's broker, so discovery can never evict or overwrite a session.
|
|
1160
|
-
discoveryBroker = null;
|
|
1161
|
-
// In-flight SIWE, shared by concurrent callers: SurfLiquid's nonce is single-use.
|
|
1162
|
-
connectPromise = null;
|
|
1163
|
-
get routingApiBaseUrl() {
|
|
1164
|
-
return this.config.routingApiBaseUrl ?? ROUTING_API_BASE_URL;
|
|
1165
|
-
}
|
|
1166
|
-
// Synchronous so the check-and-assign below cannot interleave with a concurrent call.
|
|
1167
|
-
brokerFor(walletAddress) {
|
|
1168
|
-
if (this.broker && this.brokerWallet === walletAddress.toLowerCase()) return this.broker;
|
|
1169
|
-
this.broker = createSurfBroker({
|
|
1170
|
-
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
1171
|
-
apiKey: this.config.apiKey,
|
|
1172
|
-
walletAddress,
|
|
1173
|
-
fetchImpl: this.config.fetchImpl
|
|
1174
|
-
});
|
|
1175
|
-
this.brokerWallet = walletAddress.toLowerCase();
|
|
1176
|
-
return this.broker;
|
|
1177
|
-
}
|
|
1178
|
-
async connect(state, shouldForce = false) {
|
|
1179
|
-
const broker = this.brokerFor(state.walletAddress);
|
|
1180
|
-
if (!shouldForce && broker.hasSession()) return broker;
|
|
1181
|
-
if (this.connectPromise) return this.connectPromise;
|
|
1182
|
-
this.connectPromise = (async () => {
|
|
1183
|
-
const message = await broker.nonce();
|
|
1184
|
-
const walletClient = (0, import_viem10.createWalletClient)({
|
|
1185
|
-
account: state.walletAddress,
|
|
1186
|
-
chain: import_chains3.base,
|
|
1187
|
-
transport: (0, import_viem10.custom)(state.provider)
|
|
1188
|
-
});
|
|
1189
|
-
const signature = await walletClient.signMessage({ account: state.walletAddress, message });
|
|
1190
|
-
await broker.login(message, signature);
|
|
1191
|
-
return broker;
|
|
1192
|
-
})();
|
|
1193
|
-
try {
|
|
1194
|
-
return await this.connectPromise;
|
|
1195
|
-
} finally {
|
|
1196
|
-
this.connectPromise = null;
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
/** A 401 can only surface before any signature (SurfLiquid is never called between sign and submit). */
|
|
1200
|
-
async withSession(state, run) {
|
|
1201
|
-
try {
|
|
1202
|
-
return await run();
|
|
1203
|
-
} catch (error) {
|
|
1204
|
-
if (!(error instanceof SurfSessionExpiredError)) throw error;
|
|
1205
|
-
await this.connect(state, true);
|
|
1206
|
-
try {
|
|
1207
|
-
return await run();
|
|
1208
|
-
} catch (retryError) {
|
|
1209
|
-
if (!(retryError instanceof SurfSessionExpiredError)) throw retryError;
|
|
1210
|
-
throw new OwneyError("SURF_UNAVAILABLE", "SurfLiquid session could not be re-established", void 0, AGENT_ID2);
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
async sponsoredWallet(state) {
|
|
1215
|
-
const { createSponsoredWallet: createSponsoredWallet2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
|
|
1216
|
-
return createSponsoredWallet2({
|
|
1217
|
-
provider: state.provider,
|
|
1218
|
-
ownerAddress: state.walletAddress,
|
|
1219
|
-
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
1220
|
-
apiKey: this.config.apiKey,
|
|
1221
|
-
rpcUrl: this.config.rpcUrl
|
|
1222
|
-
});
|
|
1223
|
-
}
|
|
1224
|
-
// --- IAgent: lifecycle ---
|
|
1225
|
-
async disconnect() {
|
|
1226
|
-
this.broker?.clearSession();
|
|
1227
|
-
this.broker = null;
|
|
1228
|
-
this.brokerWallet = null;
|
|
1229
|
-
}
|
|
1230
|
-
async activateAgent(state, _chainId) {
|
|
1231
|
-
await this.connect(state);
|
|
1232
|
-
}
|
|
1233
|
-
// --- IAgent: funds (gasless only) ---
|
|
1234
|
-
async deposit(state, _chainId, amount, _asset, _depositCallback) {
|
|
1235
|
-
const broker = await this.connect(state);
|
|
1236
|
-
const wallet = await this.sponsoredWallet(state);
|
|
1237
|
-
const { createSponsoredChain: createSponsoredChain2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
|
|
1238
|
-
try {
|
|
1239
|
-
const { txHash, vault } = await this.withSession(
|
|
1240
|
-
state,
|
|
1241
|
-
() => depositSponsored({ amount: BigInt(amount), api: broker, chain: createSponsoredChain2(this.config.rpcUrl), wallet })
|
|
1242
|
-
);
|
|
1243
|
-
broker.invalidateVault();
|
|
1244
|
-
return { txHash, smartWallet: vault, amount };
|
|
1245
|
-
} catch (error) {
|
|
1246
|
-
throw toOwneyError(error);
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
async withdraw(state, _chainId, _token, amount) {
|
|
1250
|
-
const broker = await this.connect(state);
|
|
1251
|
-
const wallet = await this.sponsoredWallet(state);
|
|
1252
|
-
const { createSponsoredChain: createSponsoredChain2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
|
|
1253
|
-
try {
|
|
1254
|
-
const result = await this.withSession(
|
|
1255
|
-
state,
|
|
1256
|
-
() => withdrawSponsored({
|
|
1257
|
-
amount: amount != null ? BigInt(amount) : void 0,
|
|
1258
|
-
api: broker,
|
|
1259
|
-
chain: createSponsoredChain2(this.config.rpcUrl),
|
|
1260
|
-
wallet
|
|
1261
|
-
})
|
|
1262
|
-
);
|
|
1263
|
-
broker.invalidateVault();
|
|
1264
|
-
return { txHash: result.txHash, type: amount != null ? "partial" : "full", amount: result.amount };
|
|
1265
|
-
} catch (error) {
|
|
1266
|
-
throw toOwneyError(error);
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
// --- IAgent: portfolio reads ---
|
|
1270
|
-
async vault(state) {
|
|
1271
|
-
const broker = await this.connect(state);
|
|
1272
|
-
return this.withSession(state, () => broker.getVault(state.walletAddress));
|
|
1273
|
-
}
|
|
1274
|
-
async getBalances(state, chainId) {
|
|
1275
|
-
const vault = await this.vault(state);
|
|
1276
|
-
const morphoVaultAddresses = (vault.assets ?? []).filter((asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId).map((asset) => asset.morphoVaultAddress).filter((address) => Boolean(address));
|
|
1277
|
-
const morphoStats = await fetchMorphoStatsByVault(morphoVaultAddresses, chainId);
|
|
1278
|
-
return mapBalances2(vault, chainId, morphoStats);
|
|
1279
|
-
}
|
|
1280
|
-
async getEarnings(state) {
|
|
1281
|
-
const vault = await this.vault(state);
|
|
1282
|
-
return mapEarnings2(vault, vault.userVaultAddress ?? state.walletAddress);
|
|
1283
|
-
}
|
|
1284
|
-
async getAccountApy(state, _chainId, days) {
|
|
1285
|
-
return mapAccountApy(await this.vault(state), days);
|
|
1286
|
-
}
|
|
1287
|
-
async getHistory(state, chainId, options) {
|
|
1288
|
-
const broker = await this.connect(state);
|
|
1289
|
-
const page = options?.cursor ? Number(options.cursor) : 1;
|
|
1290
|
-
const limit = options?.limit ?? HISTORY_DEFAULT_LIMIT;
|
|
1291
|
-
const result = await this.withSession(
|
|
1292
|
-
state,
|
|
1293
|
-
() => broker.getAgentMessages(state.walletAddress, page, limit, options?.fromDate, options?.toDate)
|
|
1294
|
-
);
|
|
1295
|
-
return mapHistory(result, chainId);
|
|
1296
|
-
}
|
|
1297
|
-
async getUserProfile(state) {
|
|
1298
|
-
return mapUserProfile2(await this.vault(state), state.walletAddress);
|
|
1299
|
-
}
|
|
1300
|
-
// --- IAgent: discovery (no wallet, no session) ---
|
|
1301
|
-
async getAgentApy(days, _options) {
|
|
1302
|
-
this.discoveryBroker ??= createSurfBroker({
|
|
1303
|
-
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
1304
|
-
apiKey: this.config.apiKey,
|
|
1305
|
-
walletAddress: DISCOVERY_WALLET2,
|
|
1306
|
-
fetchImpl: this.config.fetchImpl
|
|
1307
|
-
});
|
|
1308
|
-
const assets = await this.discoveryBroker.getSupportedAssets(SURFLIQUID_CHAIN_ID);
|
|
1309
|
-
const usdc = assets.find((asset) => asset.assetSymbol === "USDC");
|
|
1310
|
-
if (!usdc) return { averageApy: 0 };
|
|
1311
|
-
const windowed = usdc[APY_WINDOW_KEY2[days]];
|
|
1312
|
-
return { averageApy: windowed != null ? windowed : usdc.currentAPY };
|
|
1313
|
-
}
|
|
1314
|
-
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key2 of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key2) && key2 !== except)
|
|
14
|
+
__defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
|
|
1315
15
|
}
|
|
1316
|
-
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1317
19
|
|
|
1318
20
|
// src/index.ts
|
|
1319
21
|
var index_exports = {};
|
|
@@ -1325,12 +27,59 @@ __export(index_exports, {
|
|
|
1325
27
|
OwneyError: () => OwneyError,
|
|
1326
28
|
OwneySDK: () => OwneySDK,
|
|
1327
29
|
createOwneySIWX: () => createOwneySIWX,
|
|
30
|
+
recentEarningsFromPoints: () => recentEarningsFromPoints,
|
|
1328
31
|
setOwneyDebug: () => setOwneyDebug
|
|
1329
32
|
});
|
|
1330
33
|
module.exports = __toCommonJS(index_exports);
|
|
1331
34
|
|
|
1332
|
-
// src/
|
|
1333
|
-
|
|
35
|
+
// src/errors.ts
|
|
36
|
+
var OwneyError = class extends Error {
|
|
37
|
+
code;
|
|
38
|
+
details;
|
|
39
|
+
agentId;
|
|
40
|
+
constructor(code, message, details, agentId) {
|
|
41
|
+
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
42
|
+
super(`${prefix} ${message}`);
|
|
43
|
+
this.name = "OwneyError";
|
|
44
|
+
this.code = code;
|
|
45
|
+
this.details = details;
|
|
46
|
+
this.agentId = agentId;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var AgentNotFoundError = class extends OwneyError {
|
|
50
|
+
constructor(agentId, available) {
|
|
51
|
+
super(
|
|
52
|
+
"AGENT_NOT_FOUND",
|
|
53
|
+
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
54
|
+
{ agentId, available },
|
|
55
|
+
agentId
|
|
56
|
+
);
|
|
57
|
+
this.name = "AgentNotFoundError";
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var NotConnectedError = class extends OwneyError {
|
|
61
|
+
constructor() {
|
|
62
|
+
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
63
|
+
this.name = "NotConnectedError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var AgentChainIncompatibleError = class extends OwneyError {
|
|
67
|
+
incompatibleAgents;
|
|
68
|
+
connectedChainId;
|
|
69
|
+
constructor(incompatibleAgents, connectedChainId) {
|
|
70
|
+
const details = incompatibleAgents.map(
|
|
71
|
+
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
72
|
+
).join("; ");
|
|
73
|
+
super(
|
|
74
|
+
"AGENT_CHAIN_INCOMPATIBLE",
|
|
75
|
+
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
76
|
+
{ incompatibleAgents, connectedChainId }
|
|
77
|
+
);
|
|
78
|
+
this.name = "AgentChainIncompatibleError";
|
|
79
|
+
this.incompatibleAgents = incompatibleAgents;
|
|
80
|
+
this.connectedChainId = connectedChainId;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
1334
83
|
|
|
1335
84
|
// src/lib/rate-limit.ts
|
|
1336
85
|
function rateLimitDelay(error, now = Date.now()) {
|
|
@@ -1497,11 +246,24 @@ var SupportedAssets = [
|
|
|
1497
246
|
}
|
|
1498
247
|
];
|
|
1499
248
|
|
|
1500
|
-
// src/
|
|
1501
|
-
|
|
249
|
+
// src/lib/debug.ts
|
|
250
|
+
var configuredDebug = false;
|
|
251
|
+
function setOwneyDebug(enabled) {
|
|
252
|
+
configuredDebug = enabled;
|
|
253
|
+
}
|
|
254
|
+
function isOwneyDebug() {
|
|
255
|
+
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
256
|
+
}
|
|
257
|
+
function debugLog(scope, message, data) {
|
|
258
|
+
if (!isOwneyDebug()) return;
|
|
259
|
+
if (data === void 0) {
|
|
260
|
+
console.log(`[${scope}] ${message}`);
|
|
261
|
+
} else {
|
|
262
|
+
console.log(`[${scope}] ${message}`, data);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
1502
265
|
|
|
1503
266
|
// src/lib/utils.ts
|
|
1504
|
-
init_errors();
|
|
1505
267
|
var isValidChainId = (chainId) => {
|
|
1506
268
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
1507
269
|
throw new OwneyError(
|
|
@@ -1512,12 +274,6 @@ var isValidChainId = (chainId) => {
|
|
|
1512
274
|
}
|
|
1513
275
|
return chainId;
|
|
1514
276
|
};
|
|
1515
|
-
function isSameAsset(tokenSymbol, asset) {
|
|
1516
|
-
const token = tokenSymbol.toLowerCase();
|
|
1517
|
-
const target = asset.toLowerCase();
|
|
1518
|
-
if (token === target) return true;
|
|
1519
|
-
return target === "weth" && token === "eth" || target === "eth" && token === "weth";
|
|
1520
|
-
}
|
|
1521
277
|
function hexToDecimal(hex, decimals = 6) {
|
|
1522
278
|
const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
|
|
1523
279
|
const parsed = BigInt(normalized);
|
|
@@ -1942,6 +698,63 @@ function computeAllocationApy(positions) {
|
|
|
1942
698
|
const totalApy = totalValue > 0 ? String(weightedSum / totalValue) : "0";
|
|
1943
699
|
return { totalApy, apyByChainAndAsset };
|
|
1944
700
|
}
|
|
701
|
+
var ZYFAI_NET_OF_FEE_MULTIPLIER = 0.9;
|
|
702
|
+
function sumEarningsBucket(bucket, chainId, tokenSymbol) {
|
|
703
|
+
const tokens = bucket?.[String(chainId)];
|
|
704
|
+
if (!tokens) return null;
|
|
705
|
+
const wanted = tokenSymbol?.toUpperCase();
|
|
706
|
+
let total = 0;
|
|
707
|
+
let matched = false;
|
|
708
|
+
for (const [symbol, value] of Object.entries(tokens)) {
|
|
709
|
+
if (wanted && symbol.toUpperCase() !== wanted) continue;
|
|
710
|
+
matched = true;
|
|
711
|
+
const amount = Number(value);
|
|
712
|
+
if (!Number.isFinite(amount)) continue;
|
|
713
|
+
total += amount;
|
|
714
|
+
}
|
|
715
|
+
return matched ? total : null;
|
|
716
|
+
}
|
|
717
|
+
function netEarningsForSnapshot(entry, chainId, tokenSymbol) {
|
|
718
|
+
const lifetime = sumEarningsBucket(entry.lifetime_earnings_by_token, chainId, tokenSymbol);
|
|
719
|
+
const unrealized = sumEarningsBucket(entry.unrealized_earnings_by_token, chainId, tokenSymbol);
|
|
720
|
+
const current = sumEarningsBucket(entry.current_earnings_by_token, chainId, tokenSymbol);
|
|
721
|
+
if (lifetime === null && unrealized === null && current === null) {
|
|
722
|
+
const gross = sumEarningsBucket(entry.total_earnings_by_token, chainId, tokenSymbol);
|
|
723
|
+
if (gross === null) return null;
|
|
724
|
+
if (!warnedGrossApyFallbacks.has("daily_earnings_net_components")) {
|
|
725
|
+
warnedGrossApyFallbacks.add("daily_earnings_net_components");
|
|
726
|
+
console.warn(
|
|
727
|
+
`[owney] @zyfai/sdk omitted the daily net-earnings components; falling back to gross totals, which do not deduct Zyfai's performance fee and so read high.`
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
debugLog("zyfai:earnings", "gross fallback for daily earnings", { gross });
|
|
731
|
+
return gross;
|
|
732
|
+
}
|
|
733
|
+
return (lifetime ?? 0) + (unrealized ?? 0) + (current ?? 0) * ZYFAI_NET_OF_FEE_MULTIPLIER;
|
|
734
|
+
}
|
|
735
|
+
function mapDailyEarnings(raw, chainId, tokenSymbol) {
|
|
736
|
+
const points = (raw.data ?? []).map((entry) => ({
|
|
737
|
+
date: entry.snapshot_date,
|
|
738
|
+
net: netEarningsForSnapshot(entry, chainId, tokenSymbol)
|
|
739
|
+
})).filter((p) => p.net !== null).sort((a, b) => a.date.localeCompare(b.date));
|
|
740
|
+
return { walletAddress: raw.walletAddress, points };
|
|
741
|
+
}
|
|
742
|
+
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
743
|
+
function recentEarningsFromPoints(points, requestedDays) {
|
|
744
|
+
if (points.length === 0) return null;
|
|
745
|
+
const first = points[0];
|
|
746
|
+
const last = points[points.length - 1];
|
|
747
|
+
const spanDays = Math.round(
|
|
748
|
+
(Date.parse(last.date) - Date.parse(first.date)) / MS_PER_DAY
|
|
749
|
+
);
|
|
750
|
+
const amount = Math.max(0, last.net - first.net);
|
|
751
|
+
return {
|
|
752
|
+
amount,
|
|
753
|
+
spanDays: Number.isFinite(spanDays) ? spanDays : 0,
|
|
754
|
+
// A single snapshot spans no window at all, so it is always truncated.
|
|
755
|
+
isTruncated: requestedDays === void 0 ? points.length < 2 : spanDays < requestedDays
|
|
756
|
+
};
|
|
757
|
+
}
|
|
1945
758
|
|
|
1946
759
|
// src/agents/zyfai/zyfai.withdraw-amount.ts
|
|
1947
760
|
var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
@@ -1991,9 +804,6 @@ function decodeHistoryCursor(token) {
|
|
|
1991
804
|
return parsed;
|
|
1992
805
|
}
|
|
1993
806
|
|
|
1994
|
-
// src/agents/zyfai/zyfai.agent.ts
|
|
1995
|
-
init_errors();
|
|
1996
|
-
|
|
1997
807
|
// src/agents/zyfai/zyfai.auth-cache.ts
|
|
1998
808
|
var KEY_PREFIX = "owney.zyfai.session";
|
|
1999
809
|
var storage = () => {
|
|
@@ -2256,7 +1066,6 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
|
|
|
2256
1066
|
}
|
|
2257
1067
|
|
|
2258
1068
|
// src/agents/zyfai/zyfai.agent.ts
|
|
2259
|
-
init_debug();
|
|
2260
1069
|
var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem.parseAbi)([
|
|
2261
1070
|
"function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
|
|
2262
1071
|
]);
|
|
@@ -2775,37 +1584,6 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2775
1584
|
);
|
|
2776
1585
|
}
|
|
2777
1586
|
}
|
|
2778
|
-
/**
|
|
2779
|
-
* Records the deposit with Zyfai, retrying transient failures.
|
|
2780
|
-
*
|
|
2781
|
-
* This runs AFTER the transfer has already landed on-chain, so it must never
|
|
2782
|
-
* fail the deposit — the funds moved. But it is also the ONLY source of the
|
|
2783
|
-
* "Top up wallet" entry the history is built from: Zyfai auto-deploys the
|
|
2784
|
-
* balance it detects either way, so when this call is lost the user's deposit
|
|
2785
|
-
* never appears in Activity (an earlier withdrawal stays the newest row) and
|
|
2786
|
-
* nothing ever backfills it. Retry, then log loudly enough to be recoverable.
|
|
2787
|
-
*/
|
|
2788
|
-
async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
|
|
2789
|
-
const ATTEMPTS = 3;
|
|
2790
|
-
const RETRY_DELAY_MS = 1e3;
|
|
2791
|
-
for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
|
|
2792
|
-
try {
|
|
2793
|
-
await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
|
|
2794
|
-
return;
|
|
2795
|
-
} catch (logError) {
|
|
2796
|
-
if (attempt === ATTEMPTS) {
|
|
2797
|
-
console.error(
|
|
2798
|
-
"[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
|
|
2799
|
-
{ txHash, chainId, amount, tokenAddress, error: logError }
|
|
2800
|
-
);
|
|
2801
|
-
return;
|
|
2802
|
-
}
|
|
2803
|
-
await new Promise(
|
|
2804
|
-
(resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
|
|
2805
|
-
);
|
|
2806
|
-
}
|
|
2807
|
-
}
|
|
2808
|
-
}
|
|
2809
1587
|
/**
|
|
2810
1588
|
* True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
|
|
2811
1589
|
* to this EOA — the "new wallet" kind that is predeployed on the chains it
|
|
@@ -3115,12 +1893,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
3115
1893
|
);
|
|
3116
1894
|
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
3117
1895
|
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
3118
|
-
|
|
3119
|
-
validChainId,
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
1896
|
+
try {
|
|
1897
|
+
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
1898
|
+
} catch (logError) {
|
|
1899
|
+
console.warn(
|
|
1900
|
+
"[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
|
|
1901
|
+
logError
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
3124
1904
|
return { txHash, smartWallet, amount };
|
|
3125
1905
|
}
|
|
3126
1906
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
@@ -3203,9 +1983,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
3203
1983
|
const recent = this.earningsSnapshot;
|
|
3204
1984
|
const current = recent?.key === key2 && Date.now() - recent.at < 5e3 ? recent.raw : await this.readEarnings(key2, smartWallet);
|
|
3205
1985
|
const lastCheck = current.data.lastCheckTimestamp ? Date.parse(current.data.lastCheckTimestamp) : Number.NaN;
|
|
3206
|
-
const
|
|
3207
|
-
const earnings =
|
|
3208
|
-
if (!
|
|
1986
|
+
const isFresh = Number.isFinite(lastCheck) && Date.now() - lastCheck < EARNINGS_REFRESH_COOLDOWN_MS;
|
|
1987
|
+
const earnings = isFresh ? current : await this.sdk.calculateOnchainEarnings(smartWallet);
|
|
1988
|
+
if (!isFresh && generation === this.earningsGeneration) {
|
|
3209
1989
|
this.earningsSnapshot = { key: key2, raw: earnings, at: Date.now() };
|
|
3210
1990
|
}
|
|
3211
1991
|
return mapEarnings(earnings, smartWallet);
|
|
@@ -3221,6 +2001,15 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
3221
2001
|
const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
|
|
3222
2002
|
return mapApyHistory(raw, chainId, tokenSymbol);
|
|
3223
2003
|
}
|
|
2004
|
+
async getDailyEarnings(state, chainId, days, tokenSymbol) {
|
|
2005
|
+
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
2006
|
+
const start = new Date(Date.now() - (DayFilterMapping[days] + 1) * 864e5);
|
|
2007
|
+
const raw = await this.sdk.getDailyEarnings(
|
|
2008
|
+
smartWallet,
|
|
2009
|
+
start.toISOString().slice(0, 10)
|
|
2010
|
+
);
|
|
2011
|
+
return mapDailyEarnings(raw, chainId, tokenSymbol);
|
|
2012
|
+
}
|
|
3224
2013
|
/**
|
|
3225
2014
|
* Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
|
|
3226
2015
|
* takes lowercase `assetType` and denominates WETH as "eth" (the same
|
|
@@ -3334,13 +2123,71 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
3334
2123
|
}
|
|
3335
2124
|
};
|
|
3336
2125
|
|
|
3337
|
-
// src/
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
2126
|
+
// src/lib/routing-api.ts
|
|
2127
|
+
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2128
|
+
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2129
|
+
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
2130
|
+
try {
|
|
2131
|
+
const res = await fetch(url, {
|
|
2132
|
+
method: "GET",
|
|
2133
|
+
headers: {
|
|
2134
|
+
"Content-Type": "application/json",
|
|
2135
|
+
"x-owney-api-key": `${apiKey}`
|
|
2136
|
+
}
|
|
2137
|
+
});
|
|
2138
|
+
if (!res.ok) {
|
|
2139
|
+
if (res.status !== 404) {
|
|
2140
|
+
console.warn(
|
|
2141
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
2142
|
+
);
|
|
2143
|
+
}
|
|
2144
|
+
return null;
|
|
2145
|
+
}
|
|
2146
|
+
const json = await res.json();
|
|
2147
|
+
const policy = json.success ? json.data ?? null : null;
|
|
2148
|
+
debugLog(
|
|
2149
|
+
"owney-sdk",
|
|
2150
|
+
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
2151
|
+
policy ?? void 0
|
|
2152
|
+
);
|
|
2153
|
+
return policy;
|
|
2154
|
+
} catch (error) {
|
|
2155
|
+
console.warn(
|
|
2156
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
2157
|
+
error instanceof Error ? error.message : String(error)
|
|
2158
|
+
);
|
|
2159
|
+
return null;
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2163
|
+
const url = `${baseUrl}/api/v1/agent/keys`;
|
|
2164
|
+
const res = await fetch(url, {
|
|
2165
|
+
method: "GET",
|
|
2166
|
+
headers: {
|
|
2167
|
+
"Content-Type": "application/json",
|
|
2168
|
+
"x-owney-api-key": `${apiKey}`
|
|
2169
|
+
}
|
|
2170
|
+
});
|
|
2171
|
+
if (!res.ok) {
|
|
2172
|
+
const text = await res.text().catch(() => "");
|
|
2173
|
+
throw new OwneyError(
|
|
2174
|
+
"API_ROUTING_ERROR",
|
|
2175
|
+
`Routing API error ${res.status}: ${text}`,
|
|
2176
|
+
{ statusCode: res.status, responseBody: text }
|
|
2177
|
+
);
|
|
2178
|
+
}
|
|
2179
|
+
const json = await res.json();
|
|
2180
|
+
if (!json.success) {
|
|
2181
|
+
throw new OwneyError(
|
|
2182
|
+
"API_ROUTING_FAILED",
|
|
2183
|
+
`Routing API request failed: ${json.message}`,
|
|
2184
|
+
{ message: json.message }
|
|
2185
|
+
);
|
|
2186
|
+
}
|
|
2187
|
+
return json.data;
|
|
2188
|
+
}
|
|
3341
2189
|
|
|
3342
2190
|
// src/lib/health-report.ts
|
|
3343
|
-
init_errors();
|
|
3344
2191
|
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
3345
2192
|
async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
|
|
3346
2193
|
try {
|
|
@@ -3376,10 +2223,11 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
3376
2223
|
// src/lib/helpers/withdraw-helper.ts
|
|
3377
2224
|
var import_viem2 = require("viem");
|
|
3378
2225
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
2226
|
+
const target = asset.toUpperCase();
|
|
3379
2227
|
return agents.map((agent) => {
|
|
3380
2228
|
const agentBalance = aggregated[agent.id];
|
|
3381
2229
|
const tokenBalance = agentBalance?.tokens.find(
|
|
3382
|
-
(t) => t.chainId === chainId &&
|
|
2230
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
3383
2231
|
);
|
|
3384
2232
|
if (!tokenBalance) return { agent, balance: 0n };
|
|
3385
2233
|
return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
|
|
@@ -3529,21 +2377,52 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
3529
2377
|
}
|
|
3530
2378
|
|
|
3531
2379
|
// src/client.ts
|
|
3532
|
-
var
|
|
3533
|
-
var
|
|
2380
|
+
var import_viem6 = require("viem");
|
|
2381
|
+
var import_chains2 = require("viem/chains");
|
|
3534
2382
|
|
|
3535
|
-
// src/lib/
|
|
3536
|
-
|
|
3537
|
-
|
|
2383
|
+
// src/lib/transfer-auth.ts
|
|
2384
|
+
var import_viem3 = require("viem");
|
|
2385
|
+
var ERC20_META_ABI = [
|
|
2386
|
+
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
2387
|
+
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
2388
|
+
];
|
|
2389
|
+
function buildTransferWithAuthorizationTypedData(input) {
|
|
2390
|
+
return {
|
|
2391
|
+
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
2392
|
+
types: {
|
|
2393
|
+
TransferWithAuthorization: [
|
|
2394
|
+
{ name: "from", type: "address" },
|
|
2395
|
+
{ name: "to", type: "address" },
|
|
2396
|
+
{ name: "value", type: "uint256" },
|
|
2397
|
+
{ name: "validAfter", type: "uint256" },
|
|
2398
|
+
{ name: "validBefore", type: "uint256" },
|
|
2399
|
+
{ name: "nonce", type: "bytes32" }
|
|
2400
|
+
]
|
|
2401
|
+
},
|
|
2402
|
+
primaryType: "TransferWithAuthorization",
|
|
2403
|
+
message: input.message
|
|
2404
|
+
};
|
|
2405
|
+
}
|
|
2406
|
+
async function readTokenMeta(publicClient, token) {
|
|
2407
|
+
const [tokenName, tokenVersion] = await Promise.all([
|
|
2408
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
2409
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
2410
|
+
]);
|
|
2411
|
+
return { tokenName, tokenVersion };
|
|
2412
|
+
}
|
|
2413
|
+
function randomAuthNonce() {
|
|
2414
|
+
const bytes = new Uint8Array(32);
|
|
2415
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
2416
|
+
return (0, import_viem3.bytesToHex)(bytes);
|
|
2417
|
+
}
|
|
3538
2418
|
|
|
3539
2419
|
// src/lib/sponsor-client.ts
|
|
3540
|
-
init_errors();
|
|
3541
2420
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
3542
2421
|
async function postSponsorTransferAuth(input) {
|
|
3543
|
-
const
|
|
2422
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
3544
2423
|
let res;
|
|
3545
2424
|
try {
|
|
3546
|
-
res = await fetch(`${
|
|
2425
|
+
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
3547
2426
|
method: "POST",
|
|
3548
2427
|
headers: {
|
|
3549
2428
|
"content-type": "application/json",
|
|
@@ -3580,10 +2459,10 @@ async function postSponsorTransferAuth(input) {
|
|
|
3580
2459
|
return parsed.data;
|
|
3581
2460
|
}
|
|
3582
2461
|
async function postSponsorPermit2Transfer(input) {
|
|
3583
|
-
const
|
|
2462
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
3584
2463
|
let res;
|
|
3585
2464
|
try {
|
|
3586
|
-
res = await fetch(`${
|
|
2465
|
+
res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
|
|
3587
2466
|
method: "POST",
|
|
3588
2467
|
headers: {
|
|
3589
2468
|
"content-type": "application/json",
|
|
@@ -3618,11 +2497,11 @@ async function postSponsorPermit2Transfer(input) {
|
|
|
3618
2497
|
return parsed.data;
|
|
3619
2498
|
}
|
|
3620
2499
|
async function getSponsorRelayerAddress(input) {
|
|
3621
|
-
const
|
|
2500
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
3622
2501
|
let res;
|
|
3623
2502
|
try {
|
|
3624
2503
|
res = await fetch(
|
|
3625
|
-
`${
|
|
2504
|
+
`${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
3626
2505
|
{
|
|
3627
2506
|
headers: { "x-owney-api-key": input.apiKey }
|
|
3628
2507
|
}
|
|
@@ -3733,7 +2612,6 @@ async function readErc20Balance(publicClient, token, owner) {
|
|
|
3733
2612
|
}
|
|
3734
2613
|
|
|
3735
2614
|
// src/lib/chain-guard.ts
|
|
3736
|
-
init_errors();
|
|
3737
2615
|
var CHAIN_NAMES = {
|
|
3738
2616
|
1: "Ethereum",
|
|
3739
2617
|
8453: "Base",
|
|
@@ -3847,7 +2725,6 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
3847
2725
|
}
|
|
3848
2726
|
|
|
3849
2727
|
// src/lib/sponsored-weth-deposit.ts
|
|
3850
|
-
init_errors();
|
|
3851
2728
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
3852
2729
|
function makeSponsoredWethCallback(deps) {
|
|
3853
2730
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
@@ -3932,7 +2809,6 @@ function makeSponsoredWethCallback(deps) {
|
|
|
3932
2809
|
|
|
3933
2810
|
// src/lib/sponsored-calls-deposit.ts
|
|
3934
2811
|
var import_viem5 = require("viem");
|
|
3935
|
-
init_errors();
|
|
3936
2812
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
3937
2813
|
var DEFAULT_MAX_POLLS = 30;
|
|
3938
2814
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -4049,9 +2925,9 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
4049
2925
|
1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
4050
2926
|
};
|
|
4051
2927
|
var VIEM_CHAIN2 = {
|
|
4052
|
-
8453:
|
|
4053
|
-
42161:
|
|
4054
|
-
1:
|
|
2928
|
+
8453: import_chains2.base,
|
|
2929
|
+
42161: import_chains2.arbitrum,
|
|
2930
|
+
1: import_chains2.mainnet
|
|
4055
2931
|
};
|
|
4056
2932
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
4057
2933
|
8453: "0x4200000000000000000000000000000000000006",
|
|
@@ -4061,7 +2937,6 @@ var SPONSORED_WETH_BY_CHAIN = {
|
|
|
4061
2937
|
function shouldFallbackToUserPaid(error, asset, appCallback) {
|
|
4062
2938
|
return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
|
|
4063
2939
|
}
|
|
4064
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai"];
|
|
4065
2940
|
var OwneySDK = class {
|
|
4066
2941
|
agents = /* @__PURE__ */ new Map();
|
|
4067
2942
|
activeAgents = /* @__PURE__ */ new Set();
|
|
@@ -4208,14 +3083,14 @@ var OwneySDK = class {
|
|
|
4208
3083
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4209
3084
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4210
3085
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4211
|
-
getPublicClient: (cid) => (0,
|
|
3086
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
4212
3087
|
chain: VIEM_CHAIN2[cid],
|
|
4213
|
-
transport: (0,
|
|
3088
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4214
3089
|
}),
|
|
4215
|
-
getWalletClient: (cid) => (0,
|
|
3090
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
4216
3091
|
account: owner,
|
|
4217
3092
|
chain: VIEM_CHAIN2[cid],
|
|
4218
|
-
transport: (0,
|
|
3093
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4219
3094
|
})
|
|
4220
3095
|
});
|
|
4221
3096
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -4261,14 +3136,14 @@ var OwneySDK = class {
|
|
|
4261
3136
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4262
3137
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4263
3138
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4264
|
-
getPublicClient: (cid) => (0,
|
|
3139
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
4265
3140
|
chain: VIEM_CHAIN2[cid],
|
|
4266
|
-
transport: (0,
|
|
3141
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4267
3142
|
}),
|
|
4268
|
-
getWalletClient: (cid) => (0,
|
|
3143
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
4269
3144
|
account: owner,
|
|
4270
3145
|
chain: VIEM_CHAIN2[cid],
|
|
4271
|
-
transport: (0,
|
|
3146
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4272
3147
|
})
|
|
4273
3148
|
});
|
|
4274
3149
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -4345,7 +3220,7 @@ var OwneySDK = class {
|
|
|
4345
3220
|
);
|
|
4346
3221
|
this.disabledAgents.clear();
|
|
4347
3222
|
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
4348
|
-
const agent =
|
|
3223
|
+
const agent = this.createAgent(agent_type, key2);
|
|
4349
3224
|
if (!agent) continue;
|
|
4350
3225
|
this.agents.set(agent_type, agent);
|
|
4351
3226
|
if (is_enabled === false) {
|
|
@@ -4366,18 +3241,10 @@ var OwneySDK = class {
|
|
|
4366
3241
|
this.initializingAgentsPromise = null;
|
|
4367
3242
|
}
|
|
4368
3243
|
}
|
|
4369
|
-
|
|
3244
|
+
createAgent(agentId, key2) {
|
|
4370
3245
|
if (agentId === "zyfai") {
|
|
4371
3246
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
4372
3247
|
}
|
|
4373
|
-
if (agentId === "surfliquid") {
|
|
4374
|
-
if (!key2) return null;
|
|
4375
|
-
const { SurfLiquidAgent: SurfLiquidAgent2 } = await Promise.resolve().then(() => (init_surfliquid_agent(), surfliquid_agent_exports));
|
|
4376
|
-
return new SurfLiquidAgent2({
|
|
4377
|
-
apiKey: this.apiKey,
|
|
4378
|
-
routingApiBaseUrl: this.routingApiBaseUrl
|
|
4379
|
-
});
|
|
4380
|
-
}
|
|
4381
3248
|
return null;
|
|
4382
3249
|
}
|
|
4383
3250
|
/**
|
|
@@ -4775,14 +3642,15 @@ var OwneySDK = class {
|
|
|
4775
3642
|
async hasExistingBalance(agent, state, chainId, asset, requireReliableRead = false) {
|
|
4776
3643
|
try {
|
|
4777
3644
|
const balance = await agent.getBalances(state, chainId);
|
|
3645
|
+
const target = asset.toLowerCase();
|
|
4778
3646
|
const token = balance.tokens.find(
|
|
4779
|
-
(t) => t.chainId === chainId &&
|
|
3647
|
+
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
4780
3648
|
);
|
|
4781
3649
|
const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
|
|
4782
3650
|
const position = (balance.positions ?? []).find((p) => {
|
|
4783
3651
|
const positionChain = p.chain.trim().toUpperCase();
|
|
4784
3652
|
const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
|
|
4785
|
-
return matchesChain &&
|
|
3653
|
+
return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
|
|
4786
3654
|
});
|
|
4787
3655
|
return !!token && Number(token.amount) > 0 || !!position;
|
|
4788
3656
|
} catch (error) {
|
|
@@ -4829,34 +3697,6 @@ var OwneySDK = class {
|
|
|
4829
3697
|
}
|
|
4830
3698
|
return eligible;
|
|
4831
3699
|
}
|
|
4832
|
-
/**
|
|
4833
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
4834
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
4835
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
4836
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
4837
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
4838
|
-
*
|
|
4839
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
4840
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
4841
|
-
*/
|
|
4842
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
4843
|
-
try {
|
|
4844
|
-
await this.ensureAgentsInitialized();
|
|
4845
|
-
} catch (error) {
|
|
4846
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
4847
|
-
return [];
|
|
4848
|
-
}
|
|
4849
|
-
throw error;
|
|
4850
|
-
}
|
|
4851
|
-
return [...this.agents.values()].filter((agent) => {
|
|
4852
|
-
const chainAssets = agent.supportedAssets.find(
|
|
4853
|
-
(sa) => sa.chainId === chainId
|
|
4854
|
-
);
|
|
4855
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
4856
|
-
}).map((agent) => agent.id).sort(
|
|
4857
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
4858
|
-
);
|
|
4859
|
-
}
|
|
4860
3700
|
// --- Fund operations ---
|
|
4861
3701
|
/**
|
|
4862
3702
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -4893,19 +3733,9 @@ var OwneySDK = class {
|
|
|
4893
3733
|
}
|
|
4894
3734
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
4895
3735
|
if (!amount) {
|
|
4896
|
-
const aggregated2 = await this.getBalances();
|
|
4897
|
-
const funded = projectAgentBalancesForAsset(
|
|
4898
|
-
eligibleAgents,
|
|
4899
|
-
aggregated2.agentBalances,
|
|
4900
|
-
chainId,
|
|
4901
|
-
asset,
|
|
4902
|
-
assetInfo.decimals
|
|
4903
|
-
).filter(
|
|
4904
|
-
({ agent, balance }) => balance > 0n || aggregated2.agentErrors?.[agent.id] !== void 0
|
|
4905
|
-
).map(({ agent }) => agent);
|
|
4906
3736
|
const results2 = {};
|
|
4907
3737
|
const agentErrors2 = {};
|
|
4908
|
-
for (const agent of
|
|
3738
|
+
for (const agent of eligibleAgents) {
|
|
4909
3739
|
try {
|
|
4910
3740
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
4911
3741
|
} catch (err) {
|
|
@@ -5148,6 +3978,60 @@ var OwneySDK = class {
|
|
|
5148
3978
|
* @param options.days - Lookback period: "7D", "14D", or "30D"
|
|
5149
3979
|
* @returns {AccountAgentApy} for a single agent, or {OwneyAccountApy} with totalApy and per-agent breakdown
|
|
5150
3980
|
*/
|
|
3981
|
+
/**
|
|
3982
|
+
* Daily cumulative NET earnings for the selected chain/asset, backing the
|
|
3983
|
+
* "recent earnings" subline. Net is computed as Zyfai's own
|
|
3984
|
+
* `lifetime + unrealized + current x 0.9`, so the figure reconciles with the
|
|
3985
|
+
* balance headline rather than reading ~11% high. (ROUT-452)
|
|
3986
|
+
*
|
|
3987
|
+
* Unlike getAccountApy this does NOT blend across agents: earnings are
|
|
3988
|
+
* summed, not weighted, and an agent that fails to report must not silently
|
|
3989
|
+
* subtract from the total. Without an agentId the series is the sum of the
|
|
3990
|
+
* agents that answered.
|
|
3991
|
+
*/
|
|
3992
|
+
async getDailyEarnings({
|
|
3993
|
+
agentId,
|
|
3994
|
+
days,
|
|
3995
|
+
tokenSymbol
|
|
3996
|
+
}) {
|
|
3997
|
+
const state = this.requireState();
|
|
3998
|
+
const chainId = this.requireChainId();
|
|
3999
|
+
if (agentId) {
|
|
4000
|
+
const agent = this.getAgent(agentId);
|
|
4001
|
+
if (!agent.getDailyEarnings) {
|
|
4002
|
+
return { walletAddress: state.walletAddress ?? "", points: [] };
|
|
4003
|
+
}
|
|
4004
|
+
return this.readAgent(
|
|
4005
|
+
agent,
|
|
4006
|
+
"dailyEarnings",
|
|
4007
|
+
() => agent.getDailyEarnings(state, chainId, days, tokenSymbol),
|
|
4008
|
+
{ days, tokenSymbol }
|
|
4009
|
+
);
|
|
4010
|
+
}
|
|
4011
|
+
const entries = [...this.getActiveAgents().entries()].filter(
|
|
4012
|
+
([, agent]) => agent.getDailyEarnings
|
|
4013
|
+
);
|
|
4014
|
+
const series = await Promise.all(
|
|
4015
|
+
entries.map(
|
|
4016
|
+
([, agent]) => this.readAgent(
|
|
4017
|
+
agent,
|
|
4018
|
+
"dailyEarnings",
|
|
4019
|
+
() => agent.getDailyEarnings(state, chainId, days, tokenSymbol),
|
|
4020
|
+
{ days, tokenSymbol }
|
|
4021
|
+
)
|
|
4022
|
+
)
|
|
4023
|
+
);
|
|
4024
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
4025
|
+
for (const s of series) {
|
|
4026
|
+
for (const point of s.points) {
|
|
4027
|
+
byDate.set(point.date, (byDate.get(point.date) ?? 0) + point.net);
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
return {
|
|
4031
|
+
walletAddress: series[0]?.walletAddress ?? state.walletAddress ?? "",
|
|
4032
|
+
points: [...byDate.entries()].map(([date, net]) => ({ date, net })).sort((a, b) => a.date.localeCompare(b.date))
|
|
4033
|
+
};
|
|
4034
|
+
}
|
|
5151
4035
|
async getAccountApy({
|
|
5152
4036
|
agentId,
|
|
5153
4037
|
days,
|
|
@@ -5362,10 +4246,10 @@ var OwneySDK = class {
|
|
|
5362
4246
|
);
|
|
5363
4247
|
}
|
|
5364
4248
|
const provider = this.requireConnectedProvider();
|
|
5365
|
-
const wallet = (0,
|
|
4249
|
+
const wallet = (0, import_viem6.createWalletClient)({
|
|
5366
4250
|
account: state.walletAddress,
|
|
5367
4251
|
chain: VIEM_CHAIN2[chainId],
|
|
5368
|
-
transport: (0,
|
|
4252
|
+
transport: (0, import_viem6.custom)(provider)
|
|
5369
4253
|
});
|
|
5370
4254
|
const hash = await wallet.writeContract({
|
|
5371
4255
|
address: token,
|
|
@@ -5375,9 +4259,9 @@ var OwneySDK = class {
|
|
|
5375
4259
|
account: state.walletAddress,
|
|
5376
4260
|
chain: VIEM_CHAIN2[chainId]
|
|
5377
4261
|
});
|
|
5378
|
-
const publicClient = (0,
|
|
4262
|
+
const publicClient = (0, import_viem6.createPublicClient)({
|
|
5379
4263
|
chain: VIEM_CHAIN2[chainId],
|
|
5380
|
-
transport: (0,
|
|
4264
|
+
transport: (0, import_viem6.custom)(provider)
|
|
5381
4265
|
});
|
|
5382
4266
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
5383
4267
|
hash,
|
|
@@ -5488,18 +4372,14 @@ var OwneySDK = class {
|
|
|
5488
4372
|
}
|
|
5489
4373
|
};
|
|
5490
4374
|
|
|
5491
|
-
// src/index.ts
|
|
5492
|
-
init_errors();
|
|
5493
|
-
init_debug();
|
|
5494
|
-
|
|
5495
4375
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
5496
|
-
var
|
|
4376
|
+
var import_viem7 = require("viem");
|
|
5497
4377
|
var import_siwe = require("siwe");
|
|
5498
4378
|
var import_sdk2 = require("@zyfai/sdk");
|
|
5499
4379
|
|
|
5500
4380
|
// src/agents/zyfai/zyfai.siwx-cache.ts
|
|
5501
|
-
var
|
|
5502
|
-
var
|
|
4381
|
+
var KEY_PREFIX2 = "owney.siwx.session";
|
|
4382
|
+
var storage2 = () => {
|
|
5503
4383
|
if (typeof window === "undefined") return null;
|
|
5504
4384
|
try {
|
|
5505
4385
|
return window.localStorage;
|
|
@@ -5507,8 +4387,8 @@ var storage3 = () => {
|
|
|
5507
4387
|
return null;
|
|
5508
4388
|
}
|
|
5509
4389
|
};
|
|
5510
|
-
var
|
|
5511
|
-
var legacyKeyPrefix2 = (address) => `${
|
|
4390
|
+
var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
|
|
4391
|
+
var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
|
|
5512
4392
|
var memorySiwxSessions = /* @__PURE__ */ new Map();
|
|
5513
4393
|
var readLegacySiwxSession = (store, address) => {
|
|
5514
4394
|
if (!store) return null;
|
|
@@ -5539,8 +4419,8 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
5539
4419
|
};
|
|
5540
4420
|
var readSiwxSession = (address, chainId) => {
|
|
5541
4421
|
if (typeof window === "undefined") return null;
|
|
5542
|
-
const key2 =
|
|
5543
|
-
const store =
|
|
4422
|
+
const key2 = buildKey2(address);
|
|
4423
|
+
const store = storage2();
|
|
5544
4424
|
let raw = null;
|
|
5545
4425
|
try {
|
|
5546
4426
|
raw = store?.getItem(key2) ?? null;
|
|
@@ -5568,18 +4448,18 @@ var readSiwxSession = (address, chainId) => {
|
|
|
5568
4448
|
};
|
|
5569
4449
|
var writeSiwxSession = (address, _chainId, session) => {
|
|
5570
4450
|
if (typeof window === "undefined") return;
|
|
5571
|
-
const key2 =
|
|
4451
|
+
const key2 = buildKey2(address);
|
|
5572
4452
|
memorySiwxSessions.set(key2, session);
|
|
5573
|
-
const store =
|
|
4453
|
+
const store = storage2();
|
|
5574
4454
|
try {
|
|
5575
4455
|
store?.setItem(key2, JSON.stringify(session));
|
|
5576
4456
|
} catch {
|
|
5577
4457
|
}
|
|
5578
4458
|
};
|
|
5579
4459
|
var clearSiwxSession = (address, _chainId) => {
|
|
5580
|
-
const key2 =
|
|
4460
|
+
const key2 = buildKey2(address);
|
|
5581
4461
|
memorySiwxSessions.delete(key2);
|
|
5582
|
-
const store =
|
|
4462
|
+
const store = storage2();
|
|
5583
4463
|
try {
|
|
5584
4464
|
store?.removeItem(key2);
|
|
5585
4465
|
} catch {
|
|
@@ -5620,7 +4500,7 @@ function buildSIWXConfig(deps) {
|
|
|
5620
4500
|
issuedAt,
|
|
5621
4501
|
toString() {
|
|
5622
4502
|
return new import_siwe.SiweMessage({
|
|
5623
|
-
address: (0,
|
|
4503
|
+
address: (0, import_viem7.getAddress)(accountAddress),
|
|
5624
4504
|
chainId: numericChainId(chainId),
|
|
5625
4505
|
domain,
|
|
5626
4506
|
uri,
|
|
@@ -5698,9 +4578,9 @@ function buildSIWXConfig(deps) {
|
|
|
5698
4578
|
}
|
|
5699
4579
|
function createOwneySIWX(config) {
|
|
5700
4580
|
const zyfai = new import_sdk2.ZyfaiSDK({ apiKey: config.apiKey });
|
|
5701
|
-
const
|
|
4581
|
+
const http2 = zyfai.httpClient;
|
|
5702
4582
|
return buildSIWXConfig({
|
|
5703
|
-
post: (url, data) =>
|
|
4583
|
+
post: (url, data) => http2.post(url, data),
|
|
5704
4584
|
referralSource: config.referralSource
|
|
5705
4585
|
});
|
|
5706
4586
|
}
|
|
@@ -5713,5 +4593,6 @@ function createOwneySIWX(config) {
|
|
|
5713
4593
|
OwneyError,
|
|
5714
4594
|
OwneySDK,
|
|
5715
4595
|
createOwneySIWX,
|
|
4596
|
+
recentEarningsFromPoints,
|
|
5716
4597
|
setOwneyDebug
|
|
5717
4598
|
});
|