@owney/sdk 0.7.16-beta.7 → 0.7.17-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +644 -1463
- package/dist/index.d.cts +26 -33
- package/dist/index.d.ts +26 -33
- package/dist/index.js +630 -211
- package/package.json +1 -4
- package/dist/chunk-5LU2SHO7.js +0 -50
- package/dist/chunk-DBRXNDSB.js +0 -87
- package/dist/chunk-GMNQBWUB.js +0 -55
- package/dist/chunk-QA7JUSDB.js +0 -92
- package/dist/chunk-V2LNMTE6.js +0 -222
- package/dist/chunk-VHQ4VXY7.js +0 -39
- package/dist/routing-api-KAILDWMD.js +0 -11
- package/dist/surfliquid.agent-5GY7A6HY.js +0 -532
- package/dist/surfliquid.smart-account-ZTZV7HUD.js +0 -125
- package/dist/surfliquid.sponsorship-BFAL2O3B.js +0 -14
package/dist/index.cjs
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __esm = (fn, res, err) => function __init() {
|
|
9
|
-
if (err) throw err[0];
|
|
10
|
-
try {
|
|
11
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
|
-
} catch (e) {
|
|
13
|
-
throw err = [e], e;
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
6
|
var __export = (target, all) => {
|
|
17
7
|
for (var name in all)
|
|
18
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -25,1245 +15,183 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
25
15
|
}
|
|
26
16
|
return to;
|
|
27
17
|
};
|
|
28
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
-
mod
|
|
35
|
-
));
|
|
36
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
19
|
|
|
38
|
-
// src/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
} else {
|
|
50
|
-
console.log(`[${scope}] ${message}`, data);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
var configuredDebug;
|
|
54
|
-
var init_debug = __esm({
|
|
55
|
-
"src/lib/debug.ts"() {
|
|
56
|
-
"use strict";
|
|
57
|
-
configuredDebug = false;
|
|
58
|
-
}
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AgentChainIncompatibleError: () => AgentChainIncompatibleError,
|
|
24
|
+
AgentNotFoundError: () => AgentNotFoundError,
|
|
25
|
+
InvalidHistoryCursorError: () => InvalidHistoryCursorError,
|
|
26
|
+
NotConnectedError: () => NotConnectedError,
|
|
27
|
+
OwneyError: () => OwneyError,
|
|
28
|
+
OwneySDK: () => OwneySDK,
|
|
29
|
+
createOwneySIWX: () => createOwneySIWX,
|
|
30
|
+
setOwneyDebug: () => setOwneyDebug
|
|
59
31
|
});
|
|
32
|
+
module.exports = __toCommonJS(index_exports);
|
|
60
33
|
|
|
61
34
|
// src/errors.ts
|
|
62
|
-
var OwneyError
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
this.name = "OwneyError";
|
|
74
|
-
this.code = code;
|
|
75
|
-
this.details = details;
|
|
76
|
-
this.agentId = agentId;
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
AgentNotFoundError = class extends OwneyError {
|
|
80
|
-
constructor(agentId, available) {
|
|
81
|
-
super(
|
|
82
|
-
"AGENT_NOT_FOUND",
|
|
83
|
-
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
84
|
-
{ agentId, available },
|
|
85
|
-
agentId
|
|
86
|
-
);
|
|
87
|
-
this.name = "AgentNotFoundError";
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
NotConnectedError = class extends OwneyError {
|
|
91
|
-
constructor() {
|
|
92
|
-
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
93
|
-
this.name = "NotConnectedError";
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
AgentChainIncompatibleError = class extends OwneyError {
|
|
97
|
-
incompatibleAgents;
|
|
98
|
-
connectedChainId;
|
|
99
|
-
constructor(incompatibleAgents, connectedChainId) {
|
|
100
|
-
const details = incompatibleAgents.map(
|
|
101
|
-
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
102
|
-
).join("; ");
|
|
103
|
-
super(
|
|
104
|
-
"AGENT_CHAIN_INCOMPATIBLE",
|
|
105
|
-
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
106
|
-
{ incompatibleAgents, connectedChainId }
|
|
107
|
-
);
|
|
108
|
-
this.name = "AgentChainIncompatibleError";
|
|
109
|
-
this.incompatibleAgents = incompatibleAgents;
|
|
110
|
-
this.connectedChainId = connectedChainId;
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
// src/lib/routing-api.ts
|
|
117
|
-
var routing_api_exports = {};
|
|
118
|
-
__export(routing_api_exports, {
|
|
119
|
-
ROUTING_API_BASE_URL: () => ROUTING_API_BASE_URL,
|
|
120
|
-
fetchAgentKeys: () => fetchAgentKeys,
|
|
121
|
-
fetchOrgAgentConfig: () => fetchOrgAgentConfig
|
|
122
|
-
});
|
|
123
|
-
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
124
|
-
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
125
|
-
try {
|
|
126
|
-
const res = await fetch(url, {
|
|
127
|
-
method: "GET",
|
|
128
|
-
headers: {
|
|
129
|
-
"Content-Type": "application/json",
|
|
130
|
-
"x-owney-api-key": `${apiKey}`
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
if (!res.ok) {
|
|
134
|
-
if (res.status !== 404) {
|
|
135
|
-
console.warn(
|
|
136
|
-
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
const json = await res.json();
|
|
142
|
-
const policy = json.success ? json.data ?? null : null;
|
|
143
|
-
debugLog(
|
|
144
|
-
"owney-sdk",
|
|
145
|
-
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
146
|
-
policy ?? void 0
|
|
147
|
-
);
|
|
148
|
-
return policy;
|
|
149
|
-
} catch (error) {
|
|
150
|
-
console.warn(
|
|
151
|
-
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
152
|
-
error instanceof Error ? error.message : String(error)
|
|
153
|
-
);
|
|
154
|
-
return null;
|
|
35
|
+
var OwneyError = class extends Error {
|
|
36
|
+
code;
|
|
37
|
+
details;
|
|
38
|
+
agentId;
|
|
39
|
+
constructor(code, message, details, agentId) {
|
|
40
|
+
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
41
|
+
super(`${prefix} ${message}`);
|
|
42
|
+
this.name = "OwneyError";
|
|
43
|
+
this.code = code;
|
|
44
|
+
this.details = details;
|
|
45
|
+
this.agentId = agentId;
|
|
155
46
|
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
if (!res.ok) {
|
|
167
|
-
const text = await res.text().catch(() => "");
|
|
168
|
-
throw new OwneyError(
|
|
169
|
-
"API_ROUTING_ERROR",
|
|
170
|
-
`Routing API error ${res.status}: ${text}`,
|
|
171
|
-
{ statusCode: res.status, responseBody: text }
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
const json = await res.json();
|
|
175
|
-
if (!json.success) {
|
|
176
|
-
throw new OwneyError(
|
|
177
|
-
"API_ROUTING_FAILED",
|
|
178
|
-
`Routing API request failed: ${json.message}`,
|
|
179
|
-
{ message: json.message }
|
|
47
|
+
};
|
|
48
|
+
var AgentNotFoundError = class extends OwneyError {
|
|
49
|
+
constructor(agentId, available) {
|
|
50
|
+
super(
|
|
51
|
+
"AGENT_NOT_FOUND",
|
|
52
|
+
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
53
|
+
{ agentId, available },
|
|
54
|
+
agentId
|
|
180
55
|
);
|
|
56
|
+
this.name = "AgentNotFoundError";
|
|
181
57
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
"use strict";
|
|
188
|
-
init_errors();
|
|
189
|
-
init_debug();
|
|
190
|
-
ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
// src/lib/transfer-auth.ts
|
|
195
|
-
function buildTransferWithAuthorizationTypedData(input) {
|
|
196
|
-
return {
|
|
197
|
-
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
198
|
-
types: {
|
|
199
|
-
TransferWithAuthorization: [
|
|
200
|
-
{ name: "from", type: "address" },
|
|
201
|
-
{ name: "to", type: "address" },
|
|
202
|
-
{ name: "value", type: "uint256" },
|
|
203
|
-
{ name: "validAfter", type: "uint256" },
|
|
204
|
-
{ name: "validBefore", type: "uint256" },
|
|
205
|
-
{ name: "nonce", type: "bytes32" }
|
|
206
|
-
]
|
|
207
|
-
},
|
|
208
|
-
primaryType: "TransferWithAuthorization",
|
|
209
|
-
message: input.message
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
function buildReceiveWithAuthorizationTypedData(input) {
|
|
213
|
-
const transfer = buildTransferWithAuthorizationTypedData(input);
|
|
214
|
-
return {
|
|
215
|
-
...transfer,
|
|
216
|
-
types: { ReceiveWithAuthorization: transfer.types.TransferWithAuthorization },
|
|
217
|
-
primaryType: "ReceiveWithAuthorization"
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
async function readTokenMeta(publicClient, token) {
|
|
221
|
-
const [tokenName, tokenVersion] = await Promise.all([
|
|
222
|
-
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
223
|
-
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
224
|
-
]);
|
|
225
|
-
return { tokenName, tokenVersion };
|
|
226
|
-
}
|
|
227
|
-
function randomAuthNonce() {
|
|
228
|
-
const bytes = new Uint8Array(32);
|
|
229
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
230
|
-
return (0, import_viem3.bytesToHex)(bytes);
|
|
231
|
-
}
|
|
232
|
-
var import_viem3, ERC20_META_ABI;
|
|
233
|
-
var init_transfer_auth = __esm({
|
|
234
|
-
"src/lib/transfer-auth.ts"() {
|
|
235
|
-
"use strict";
|
|
236
|
-
import_viem3 = require("viem");
|
|
237
|
-
ERC20_META_ABI = [
|
|
238
|
-
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
239
|
-
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
240
|
-
];
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
// src/lib/permit2.ts
|
|
245
|
-
function buildPermitTransferFromTypedData(input) {
|
|
246
|
-
return {
|
|
247
|
-
domain: {
|
|
248
|
-
name: "Permit2",
|
|
249
|
-
chainId: input.chainId,
|
|
250
|
-
verifyingContract: PERMIT2_ADDRESS
|
|
251
|
-
},
|
|
252
|
-
types: {
|
|
253
|
-
PermitTransferFrom: [
|
|
254
|
-
{ name: "permitted", type: "TokenPermissions" },
|
|
255
|
-
{ name: "spender", type: "address" },
|
|
256
|
-
{ name: "nonce", type: "uint256" },
|
|
257
|
-
{ name: "deadline", type: "uint256" }
|
|
258
|
-
],
|
|
259
|
-
TokenPermissions: [
|
|
260
|
-
{ name: "token", type: "address" },
|
|
261
|
-
{ name: "amount", type: "uint256" }
|
|
262
|
-
]
|
|
263
|
-
},
|
|
264
|
-
primaryType: "PermitTransferFrom",
|
|
265
|
-
message: input.message
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
function randomPermit2Nonce() {
|
|
269
|
-
const bytes = new Uint8Array(32);
|
|
270
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
271
|
-
return BigInt((0, import_viem4.bytesToHex)(bytes));
|
|
272
|
-
}
|
|
273
|
-
async function readPermit2Allowance(publicClient, token, owner) {
|
|
274
|
-
return publicClient.readContract({
|
|
275
|
-
address: token,
|
|
276
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
277
|
-
functionName: "allowance",
|
|
278
|
-
args: [owner, PERMIT2_ADDRESS]
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
async function readErc20Balance(publicClient, token, owner) {
|
|
282
|
-
return publicClient.readContract({
|
|
283
|
-
address: token,
|
|
284
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
285
|
-
functionName: "balanceOf",
|
|
286
|
-
args: [owner]
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
var import_viem4, PERMIT2_ADDRESS, MAX_UINT256, ERC20_ALLOWANCE_ABI;
|
|
290
|
-
var init_permit2 = __esm({
|
|
291
|
-
"src/lib/permit2.ts"() {
|
|
292
|
-
"use strict";
|
|
293
|
-
import_viem4 = require("viem");
|
|
294
|
-
PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
295
|
-
MAX_UINT256 = 2n ** 256n - 1n;
|
|
296
|
-
ERC20_ALLOWANCE_ABI = [
|
|
297
|
-
{
|
|
298
|
-
type: "function",
|
|
299
|
-
name: "allowance",
|
|
300
|
-
stateMutability: "view",
|
|
301
|
-
inputs: [
|
|
302
|
-
{ name: "owner", type: "address" },
|
|
303
|
-
{ name: "spender", type: "address" }
|
|
304
|
-
],
|
|
305
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
type: "function",
|
|
309
|
-
name: "approve",
|
|
310
|
-
stateMutability: "nonpayable",
|
|
311
|
-
inputs: [
|
|
312
|
-
{ name: "spender", type: "address" },
|
|
313
|
-
{ name: "amount", type: "uint256" }
|
|
314
|
-
],
|
|
315
|
-
outputs: [{ name: "", type: "bool" }]
|
|
316
|
-
},
|
|
317
|
-
{
|
|
318
|
-
type: "function",
|
|
319
|
-
name: "balanceOf",
|
|
320
|
-
stateMutability: "view",
|
|
321
|
-
inputs: [{ name: "account", type: "address" }],
|
|
322
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
323
|
-
}
|
|
324
|
-
];
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
// src/agents/surfliquid/surfliquid.constants.ts
|
|
329
|
-
var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_USDC_DECIMALS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_APPROVAL_TARGET, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
|
|
330
|
-
var init_surfliquid_constants = __esm({
|
|
331
|
-
"src/agents/surfliquid/surfliquid.constants.ts"() {
|
|
332
|
-
"use strict";
|
|
333
|
-
SURFLIQUID_CHAIN_ID = 8453;
|
|
334
|
-
SURFLIQUID_CHAIN_NAME = "BASE";
|
|
335
|
-
SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
336
|
-
SURFLIQUID_USDC_DECIMALS = 6;
|
|
337
|
-
SURFLIQUID_MIN_DEPOSIT = "0";
|
|
338
|
-
SURFLIQUID_APPROVAL_TARGET = 100000000000n;
|
|
339
|
-
SURFLIQUID_SUPPORTED_ASSETS = [
|
|
340
|
-
{
|
|
341
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
342
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
343
|
-
assets: [{ symbol: "USDC", minDepositAmount: SURFLIQUID_MIN_DEPOSIT }]
|
|
344
|
-
}
|
|
345
|
-
];
|
|
346
|
-
SURFLIQUID_ACTION_MAP = {
|
|
347
|
-
// INITIAL_DEPOSIT is the user's real first deposit, so surface it like any
|
|
348
|
-
// other funding ("Top up"). The mini-app intentionally hides the "Deposit"
|
|
349
|
-
// action (it marks Zyfai's smart-account-creation event), which would
|
|
350
|
-
// otherwise drop a SurfLiquid user's only history row.
|
|
351
|
-
INITIAL_DEPOSIT: "Top up",
|
|
352
|
-
DEPOSIT: "Top up",
|
|
353
|
-
USER_DEPOSIT: "Top up",
|
|
354
|
-
WITHDRAWAL: "Withdraw",
|
|
355
|
-
USER_WITHDRAWAL: "Withdraw",
|
|
356
|
-
REBALANCE: "Rebalance",
|
|
357
|
-
REBALANCE_COMPLETED: "Rebalance",
|
|
358
|
-
CROSS_CHAIN_REBALANCE: "Rebalance",
|
|
359
|
-
MERKL_CLAIM: "Earned"
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
// src/agents/surfliquid/surfliquid.mapper.ts
|
|
365
|
-
function mapMessage(message) {
|
|
366
|
-
const action = SURFLIQUID_ACTION_MAP[message.transactionType];
|
|
367
|
-
if (!action) return null;
|
|
368
|
-
return {
|
|
369
|
-
agent: "surfliquid",
|
|
370
|
-
action,
|
|
371
|
-
date: message.timestamp,
|
|
372
|
-
oldApy: message.apyBefore != null ? String(message.apyBefore) : null,
|
|
373
|
-
newApy: message.apyAfter != null ? String(message.apyAfter) : null,
|
|
374
|
-
transactions: [
|
|
375
|
-
{
|
|
376
|
-
txHashes: [message.txHash],
|
|
377
|
-
chainId: message.chainId,
|
|
378
|
-
tokenSymbol: message.token ?? void 0,
|
|
379
|
-
amount: message.amount != null ? String(message.amount) : void 0
|
|
380
|
-
}
|
|
381
|
-
],
|
|
382
|
-
rebalanceLog: []
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
function mapHistory(result, _chainId) {
|
|
386
|
-
const data = result.messages.map(mapMessage).filter((entry) => entry !== null);
|
|
387
|
-
const hasMore = result.page < result.pages;
|
|
388
|
-
return {
|
|
389
|
-
data,
|
|
390
|
-
hasMore,
|
|
391
|
-
nextCursor: hasMore ? String(result.page + 1) : void 0
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
function mapBalances2(vault, chainId, morphoStats) {
|
|
395
|
-
const assets = (vault.assets ?? []).filter(
|
|
396
|
-
(asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId
|
|
397
|
-
);
|
|
398
|
-
const tokens = assets.map((asset) => ({
|
|
399
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
400
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
401
|
-
asset: "USDC",
|
|
402
|
-
amount: String(asset.currentValueUSD)
|
|
403
|
-
}));
|
|
404
|
-
const positions = assets.map((asset) => {
|
|
405
|
-
const stats = morphoStats?.get(asset.morphoVaultAddress?.toLowerCase() ?? "");
|
|
406
|
-
return {
|
|
407
|
-
chain: SURFLIQUID_CHAIN_NAME,
|
|
408
|
-
protocol: "Morpho",
|
|
409
|
-
// The specific MetaMorpho vault (e.g. "Gauntlet USDC Frontier"), read from
|
|
410
|
-
// Morpho — renders as "Morpho <vault>" alongside zyfai's vault detail.
|
|
411
|
-
pool: stats?.name ?? void 0,
|
|
412
|
-
asset: "USDC",
|
|
413
|
-
amount: String(asset.currentValueUSD),
|
|
414
|
-
apy: asset.currentAPY,
|
|
415
|
-
// TVL + liquidity come straight from Morpho (SurfLiquid's API omits them).
|
|
416
|
-
tvl: stats?.tvlUsd,
|
|
417
|
-
liquidity: stats?.liquidityUsd
|
|
418
|
-
};
|
|
419
|
-
});
|
|
420
|
-
const total = assets.reduce(
|
|
421
|
-
(sum, asset) => sum + asset.currentValueUSD,
|
|
422
|
-
0
|
|
423
|
-
);
|
|
424
|
-
return {
|
|
425
|
-
smartWallet: vault.userVaultAddress ?? void 0,
|
|
426
|
-
totalBalance: String(total),
|
|
427
|
-
totalBalanceAsset: "usdc",
|
|
428
|
-
tokens,
|
|
429
|
-
positions
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
function mapAccountApy(vault, days) {
|
|
433
|
-
const breakdown = vault.apyBreakdown;
|
|
434
|
-
const windowed = breakdown ? breakdown[APY_WINDOW_KEY[days]] : void 0;
|
|
435
|
-
const apy = windowed != null ? windowed : breakdown?.currentAPY ?? 0;
|
|
436
|
-
return {
|
|
437
|
-
walletAddress: vault.walletAddress ?? "",
|
|
438
|
-
weightedApyAfterFee: apy,
|
|
439
|
-
apyByChainAndAsset: { [SURFLIQUID_CHAIN_ID]: { USDC: apy } },
|
|
440
|
-
// Parity with Sail: SurfLiquid's core-sdk exposes no daily net-APY series.
|
|
441
|
-
history: []
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
function mapEarnings2(vault, vaultAddress) {
|
|
445
|
-
return {
|
|
446
|
-
smartWallet: vaultAddress,
|
|
447
|
-
lifetimeEarnings: vault.earned?.totalEarningsUSD ?? 0,
|
|
448
|
-
tokens: []
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
function mapUserProfile2(vault, address) {
|
|
452
|
-
return {
|
|
453
|
-
address,
|
|
454
|
-
smartWallet: vault.userVaultAddress ?? "",
|
|
455
|
-
chains: [SURFLIQUID_CHAIN_ID],
|
|
456
|
-
// SurfLiquid uses cookie-based session auth — no session-key concept.
|
|
457
|
-
hasActiveSessionKey: false,
|
|
458
|
-
protocols: ["SurfLiquid"]
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
var APY_WINDOW_KEY;
|
|
462
|
-
var init_surfliquid_mapper = __esm({
|
|
463
|
-
"src/agents/surfliquid/surfliquid.mapper.ts"() {
|
|
464
|
-
"use strict";
|
|
465
|
-
init_surfliquid_constants();
|
|
466
|
-
APY_WINDOW_KEY = {
|
|
467
|
-
"7D": "apy7d",
|
|
468
|
-
"14D": "apy14d",
|
|
469
|
-
"30D": "apy30d"
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
// src/agents/surfliquid/surfliquid.wallet-adapter.ts
|
|
475
|
-
var import_core_sdk, OwneyWalletAdapter;
|
|
476
|
-
var init_surfliquid_wallet_adapter = __esm({
|
|
477
|
-
"src/agents/surfliquid/surfliquid.wallet-adapter.ts"() {
|
|
478
|
-
"use strict";
|
|
479
|
-
import_core_sdk = require("@surf_liquid/core-sdk");
|
|
480
|
-
OwneyWalletAdapter = class extends import_core_sdk.BaseWalletAdapter {
|
|
481
|
-
constructor(eip1193Provider) {
|
|
482
|
-
super();
|
|
483
|
-
this.eip1193Provider = eip1193Provider;
|
|
484
|
-
}
|
|
485
|
-
eip1193Provider;
|
|
486
|
-
name = "owney";
|
|
487
|
-
get installed() {
|
|
488
|
-
return true;
|
|
489
|
-
}
|
|
490
|
-
resolveProvider() {
|
|
491
|
-
return this.eip1193Provider;
|
|
492
|
-
}
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
// src/agents/surfliquid/surfliquid.morpho.ts
|
|
498
|
-
async function queryMorpho(query, vaultAddress, chainId) {
|
|
499
|
-
try {
|
|
500
|
-
const res = await fetch(MORPHO_API_URL, {
|
|
501
|
-
method: "POST",
|
|
502
|
-
headers: { "Content-Type": "application/json" },
|
|
503
|
-
body: JSON.stringify({
|
|
504
|
-
query,
|
|
505
|
-
variables: { address: vaultAddress, chainId }
|
|
506
|
-
})
|
|
507
|
-
});
|
|
508
|
-
if (!res.ok) return null;
|
|
509
|
-
const json = await res.json();
|
|
510
|
-
if (json.errors) return null;
|
|
511
|
-
return json.data ?? null;
|
|
512
|
-
} catch (error) {
|
|
513
|
-
console.warn("surfliquid: Morpho vault stats fetch failed", {
|
|
514
|
-
vaultAddress,
|
|
515
|
-
chainId,
|
|
516
|
-
error
|
|
517
|
-
});
|
|
518
|
-
return null;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
function toStats(name, tvlUsd, liquidityUsd) {
|
|
522
|
-
if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
|
|
523
|
-
return null;
|
|
524
|
-
}
|
|
525
|
-
return {
|
|
526
|
-
name: typeof name === "string" ? name : null,
|
|
527
|
-
tvlUsd,
|
|
528
|
-
liquidityUsd
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
async function fetchMorphoVaultStats(vaultAddress, chainId) {
|
|
532
|
-
const v1 = await queryMorpho(VAULT_STATS_QUERY, vaultAddress, chainId);
|
|
533
|
-
const vault = v1?.vaultByAddress;
|
|
534
|
-
const v1Stats = toStats(
|
|
535
|
-
vault?.name,
|
|
536
|
-
vault?.state?.totalAssetsUsd,
|
|
537
|
-
vault?.liquidity?.usd
|
|
538
|
-
);
|
|
539
|
-
if (v1Stats) return v1Stats;
|
|
540
|
-
const v2 = await queryMorpho(VAULT_V2_STATS_QUERY, vaultAddress, chainId);
|
|
541
|
-
const vaultV2 = v2?.vaultV2ByAddress;
|
|
542
|
-
return toStats(vaultV2?.name, vaultV2?.totalAssetsUsd, vaultV2?.liquidityUsd);
|
|
543
|
-
}
|
|
544
|
-
async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
|
|
545
|
-
const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
|
|
546
|
-
const entries = await Promise.all(
|
|
547
|
-
unique.map(
|
|
548
|
-
async (address) => [address, await fetchMorphoVaultStats(address, chainId)]
|
|
549
|
-
)
|
|
550
|
-
);
|
|
551
|
-
const byVault = /* @__PURE__ */ new Map();
|
|
552
|
-
for (const [address, stats] of entries) {
|
|
553
|
-
if (stats) byVault.set(address, stats);
|
|
554
|
-
}
|
|
555
|
-
return byVault;
|
|
556
|
-
}
|
|
557
|
-
var MORPHO_API_URL, VAULT_STATS_QUERY, VAULT_V2_STATS_QUERY;
|
|
558
|
-
var init_surfliquid_morpho = __esm({
|
|
559
|
-
"src/agents/surfliquid/surfliquid.morpho.ts"() {
|
|
560
|
-
"use strict";
|
|
561
|
-
MORPHO_API_URL = "https://api.morpho.org/graphql";
|
|
562
|
-
VAULT_STATS_QUERY = `
|
|
563
|
-
query VaultStats($address: String!, $chainId: Int!) {
|
|
564
|
-
vaultByAddress(address: $address, chainId: $chainId) {
|
|
565
|
-
name
|
|
566
|
-
state { totalAssetsUsd }
|
|
567
|
-
liquidity { usd }
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
`;
|
|
571
|
-
VAULT_V2_STATS_QUERY = `
|
|
572
|
-
query VaultV2Stats($address: String!, $chainId: Int!) {
|
|
573
|
-
vaultV2ByAddress(address: $address, chainId: $chainId) {
|
|
574
|
-
name
|
|
575
|
-
totalAssetsUsd
|
|
576
|
-
liquidityUsd
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
`;
|
|
580
|
-
}
|
|
581
|
-
});
|
|
582
|
-
|
|
583
|
-
// src/agents/surfliquid/surfliquid.contracts.ts
|
|
584
|
-
var import_viem6, SURFLIQUID_FACTORY_ADDRESS, SURFLIQUID_FACTORY_ABI, SURFLIQUID_VAULT_ABI, USDC_ABI;
|
|
585
|
-
var init_surfliquid_contracts = __esm({
|
|
586
|
-
"src/agents/surfliquid/surfliquid.contracts.ts"() {
|
|
587
|
-
"use strict";
|
|
588
|
-
import_viem6 = require("viem");
|
|
589
|
-
SURFLIQUID_FACTORY_ADDRESS = "0x8fa50DeA8DB10987D7d22ac092001c3613C18779";
|
|
590
|
-
SURFLIQUID_FACTORY_ABI = (0, import_viem6.parseAbi)([
|
|
591
|
-
"function deployVault(address vaultOwner, bytes32 salt) returns (address)",
|
|
592
|
-
"function computeVaultAddress(address vaultOwner, bytes32 salt) view returns (address)"
|
|
593
|
-
]);
|
|
594
|
-
SURFLIQUID_VAULT_ABI = (0, import_viem6.parseAbi)([
|
|
595
|
-
"function initialDeposit(address asset, address vault, uint256 amount)",
|
|
596
|
-
"function userDeposit(address asset, uint256 amount)",
|
|
597
|
-
// amount 0 withdraws everything; proceeds go to the vault's owner.
|
|
598
|
-
"function withdraw(address asset, uint256 amount)",
|
|
599
|
-
"function assetHasInitialDeposit(address asset) view returns (bool)",
|
|
600
|
-
"function owner() view returns (address)"
|
|
601
|
-
]);
|
|
602
|
-
USDC_ABI = (0, import_viem6.parseAbi)([
|
|
603
|
-
"function approve(address spender, uint256 amount)",
|
|
604
|
-
"function transfer(address to, uint256 amount)",
|
|
605
|
-
"function balanceOf(address account) view returns (uint256)",
|
|
606
|
-
"function receiveWithAuthorization(address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, bytes signature)"
|
|
607
|
-
]);
|
|
58
|
+
};
|
|
59
|
+
var NotConnectedError = class extends OwneyError {
|
|
60
|
+
constructor() {
|
|
61
|
+
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
62
|
+
this.name = "NotConnectedError";
|
|
608
63
|
}
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
throw new Error("A first deposit needs a target morpho vault");
|
|
622
|
-
}
|
|
623
|
-
const calls = [];
|
|
624
|
-
if (deploySalt) {
|
|
625
|
-
calls.push(
|
|
626
|
-
call(SURFLIQUID_FACTORY_ADDRESS, SURFLIQUID_FACTORY_ABI, "deployVault", [
|
|
627
|
-
smartAccount,
|
|
628
|
-
deploySalt
|
|
629
|
-
])
|
|
64
|
+
};
|
|
65
|
+
var AgentChainIncompatibleError = class extends OwneyError {
|
|
66
|
+
incompatibleAgents;
|
|
67
|
+
connectedChainId;
|
|
68
|
+
constructor(incompatibleAgents, connectedChainId) {
|
|
69
|
+
const details = incompatibleAgents.map(
|
|
70
|
+
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
71
|
+
).join("; ");
|
|
72
|
+
super(
|
|
73
|
+
"AGENT_CHAIN_INCOMPATIBLE",
|
|
74
|
+
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
75
|
+
{ incompatibleAgents, connectedChainId }
|
|
630
76
|
);
|
|
77
|
+
this.name = "AgentChainIncompatibleError";
|
|
78
|
+
this.incompatibleAgents = incompatibleAgents;
|
|
79
|
+
this.connectedChainId = connectedChainId;
|
|
631
80
|
}
|
|
632
|
-
|
|
633
|
-
call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "receiveWithAuthorization", [
|
|
634
|
-
authorization.from,
|
|
635
|
-
authorization.to,
|
|
636
|
-
authorization.value,
|
|
637
|
-
authorization.validAfter,
|
|
638
|
-
authorization.validBefore,
|
|
639
|
-
authorization.nonce,
|
|
640
|
-
authorization.signature
|
|
641
|
-
]),
|
|
642
|
-
call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "approve", [vault, amount]),
|
|
643
|
-
input.hasInitialDeposit ? call(vault, SURFLIQUID_VAULT_ABI, "userDeposit", [SURFLIQUID_USDC_ADDRESS, amount]) : call(vault, SURFLIQUID_VAULT_ABI, "initialDeposit", [
|
|
644
|
-
SURFLIQUID_USDC_ADDRESS,
|
|
645
|
-
input.morphoVault,
|
|
646
|
-
amount
|
|
647
|
-
])
|
|
648
|
-
);
|
|
649
|
-
return calls;
|
|
650
|
-
}
|
|
651
|
-
function buildWithdrawCalls(input) {
|
|
652
|
-
return [
|
|
653
|
-
call(input.vault, SURFLIQUID_VAULT_ABI, "withdraw", [
|
|
654
|
-
SURFLIQUID_USDC_ADDRESS,
|
|
655
|
-
input.amount ?? 0n
|
|
656
|
-
])
|
|
657
|
-
];
|
|
658
|
-
}
|
|
659
|
-
function buildSweepCalls(input) {
|
|
660
|
-
return [call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "transfer", [input.owner, input.amount])];
|
|
661
|
-
}
|
|
662
|
-
var import_viem7, call;
|
|
663
|
-
var init_surfliquid_calls = __esm({
|
|
664
|
-
"src/agents/surfliquid/surfliquid.calls.ts"() {
|
|
665
|
-
"use strict";
|
|
666
|
-
import_viem7 = require("viem");
|
|
667
|
-
init_surfliquid_constants();
|
|
668
|
-
init_surfliquid_contracts();
|
|
669
|
-
call = (to, abi, functionName, args) => ({
|
|
670
|
-
to,
|
|
671
|
-
data: (0, import_viem7.encodeFunctionData)({ abi, functionName, args })
|
|
672
|
-
});
|
|
673
|
-
}
|
|
674
|
-
});
|
|
81
|
+
};
|
|
675
82
|
|
|
676
|
-
// src/
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
if (!registered.userVaultAddress) {
|
|
688
|
-
const salt2 = registered.deploymentSalt ?? (await ctx.api.prepare(SURFLIQUID_CHAIN_ID)).salt;
|
|
689
|
-
return {
|
|
690
|
-
vault: await ctx.chain.computeVaultAddress(smartAccount, salt2),
|
|
691
|
-
deploySalt: salt2,
|
|
692
|
-
registerAfterDeposit: true
|
|
693
|
-
};
|
|
694
|
-
}
|
|
695
|
-
const vault = registered.userVaultAddress;
|
|
696
|
-
if (await ctx.chain.isDeployed(vault)) {
|
|
697
|
-
const owner = await ctx.chain.readVaultOwner(vault);
|
|
698
|
-
if (owner.toLowerCase() !== smartAccount.toLowerCase()) {
|
|
699
|
-
throw new Error(`SurfLiquid vault ${vault} is not owned by the smart account`);
|
|
83
|
+
// src/lib/rate-limit.ts
|
|
84
|
+
function rateLimitDelay(error, now = Date.now()) {
|
|
85
|
+
const seen = /* @__PURE__ */ new Set();
|
|
86
|
+
let limited = false;
|
|
87
|
+
let delay = 0;
|
|
88
|
+
function visit(value, depth = 0) {
|
|
89
|
+
if (depth > 6 || value == null) return;
|
|
90
|
+
if (typeof value === "string") {
|
|
91
|
+
if (/rate[ _-]?limit|too many requests|HTTP_429|\b429\b/i.test(value))
|
|
92
|
+
limited = true;
|
|
93
|
+
return;
|
|
700
94
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
);
|
|
741
|
-
const txHash = await wallet.sendCalls(
|
|
742
|
-
buildDepositCalls({
|
|
743
|
-
smartAccount: wallet.smartAccountAddress,
|
|
744
|
-
vault,
|
|
745
|
-
amount,
|
|
746
|
-
authorization: { ...message, signature },
|
|
747
|
-
hasInitialDeposit,
|
|
748
|
-
morphoVault,
|
|
749
|
-
deploySalt
|
|
750
|
-
})
|
|
751
|
-
);
|
|
752
|
-
if (registerAfterDeposit && deploySalt) {
|
|
753
|
-
try {
|
|
754
|
-
await api.confirm({
|
|
755
|
-
userVaultAddress: vault,
|
|
756
|
-
homeChainId: SURFLIQUID_CHAIN_ID,
|
|
757
|
-
deploymentSalt: deploySalt,
|
|
758
|
-
initialAssets: []
|
|
759
|
-
});
|
|
760
|
-
} catch (error) {
|
|
761
|
-
console.warn(
|
|
762
|
-
"[owney-sdk] SurfLiquid vault registration failed after a successful deposit:",
|
|
763
|
-
error instanceof Error ? error.message : String(error)
|
|
764
|
-
);
|
|
95
|
+
if (typeof value !== "object" || seen.has(value)) return;
|
|
96
|
+
seen.add(value);
|
|
97
|
+
const record = value;
|
|
98
|
+
if ([record.status, record.statusCode, record.code].some(
|
|
99
|
+
(code) => String(code) === "429"
|
|
100
|
+
)) {
|
|
101
|
+
limited = true;
|
|
102
|
+
}
|
|
103
|
+
for (const key2 of ["retryAfterSeconds", "retryAfter"]) {
|
|
104
|
+
const seconds = Number(record[key2]);
|
|
105
|
+
if (Number.isFinite(seconds) && seconds > 0)
|
|
106
|
+
delay = Math.max(delay, seconds * 1e3);
|
|
107
|
+
}
|
|
108
|
+
const retryAt = Number(record.retryAt);
|
|
109
|
+
if (Number.isFinite(retryAt) && retryAt > now)
|
|
110
|
+
delay = Math.max(delay, retryAt - now);
|
|
111
|
+
const headers = record.headers;
|
|
112
|
+
const header = typeof headers?.get === "function" ? headers.get("Retry-After") : headers?.["retry-after"] ?? headers?.["Retry-After"];
|
|
113
|
+
if (typeof header === "string" || typeof header === "number") {
|
|
114
|
+
const seconds = Number(header);
|
|
115
|
+
const ms = Number.isFinite(seconds) ? seconds * 1e3 : Date.parse(String(header)) - now;
|
|
116
|
+
if (Number.isFinite(ms) && ms > 0) delay = Math.max(delay, ms);
|
|
117
|
+
}
|
|
118
|
+
for (const key2 of [
|
|
119
|
+
"message",
|
|
120
|
+
"code",
|
|
121
|
+
"cause",
|
|
122
|
+
"details",
|
|
123
|
+
"response",
|
|
124
|
+
"data",
|
|
125
|
+
"fields"
|
|
126
|
+
]) {
|
|
127
|
+
visit(record[key2], depth + 1);
|
|
128
|
+
}
|
|
129
|
+
for (const key2 of ["agentErrors", "failures"]) {
|
|
130
|
+
const entries = record[key2];
|
|
131
|
+
if (entries && typeof entries === "object") {
|
|
132
|
+
for (const entry of Object.values(entries)) visit(entry, depth + 1);
|
|
133
|
+
}
|
|
765
134
|
}
|
|
766
135
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
async function withdrawSponsored(input) {
|
|
770
|
-
const { api, chain, wallet, amount } = input;
|
|
771
|
-
const registered = await api.getVault(wallet.ownerAddress);
|
|
772
|
-
if (!registered.userVaultAddress) {
|
|
773
|
-
throw new Error("SurfLiquid has no vault registered for this wallet");
|
|
774
|
-
}
|
|
775
|
-
const vault = registered.userVaultAddress;
|
|
776
|
-
const owner = await chain.readVaultOwner(vault);
|
|
777
|
-
if (owner.toLowerCase() !== wallet.smartAccountAddress.toLowerCase()) {
|
|
778
|
-
throw new Error(`SurfLiquid vault ${vault} is not owned by the smart account`);
|
|
779
|
-
}
|
|
780
|
-
const withdrawHash = await wallet.sendCalls(buildWithdrawCalls({ vault, amount }));
|
|
781
|
-
try {
|
|
782
|
-
const proceeds = await chain.usdcBalanceOf(wallet.smartAccountAddress);
|
|
783
|
-
if (proceeds === 0n) return { txHash: withdrawHash, amount: "0" };
|
|
784
|
-
const sweepHash = await wallet.sendCalls(
|
|
785
|
-
buildSweepCalls({ owner: wallet.ownerAddress, amount: proceeds })
|
|
786
|
-
);
|
|
787
|
-
return { txHash: sweepHash, amount: proceeds.toString() };
|
|
788
|
-
} catch (error) {
|
|
789
|
-
throw new SubmittedError(
|
|
790
|
-
`SurfLiquid withdrawal ${withdrawHash} landed but the sweep did not: ${error instanceof Error ? error.message : String(error)}`
|
|
791
|
-
);
|
|
792
|
-
}
|
|
136
|
+
visit(error);
|
|
137
|
+
return limited ? delay : void 0;
|
|
793
138
|
}
|
|
794
|
-
var AUTHORIZATION_TTL_SECONDS, SubmittedError, isSafeToRetry;
|
|
795
|
-
var init_surfliquid_sponsorship = __esm({
|
|
796
|
-
"src/agents/surfliquid/surfliquid.sponsorship.ts"() {
|
|
797
|
-
"use strict";
|
|
798
|
-
init_transfer_auth();
|
|
799
|
-
init_surfliquid_constants();
|
|
800
|
-
init_surfliquid_calls();
|
|
801
|
-
AUTHORIZATION_TTL_SECONDS = 3600n;
|
|
802
|
-
SubmittedError = class extends Error {
|
|
803
|
-
constructor(message, userOpHash) {
|
|
804
|
-
super(message);
|
|
805
|
-
this.userOpHash = userOpHash;
|
|
806
|
-
this.name = "SubmittedError";
|
|
807
|
-
}
|
|
808
|
-
userOpHash;
|
|
809
|
-
};
|
|
810
|
-
isSafeToRetry = (error) => !(error instanceof SubmittedError);
|
|
811
|
-
}
|
|
812
|
-
});
|
|
813
139
|
|
|
814
|
-
// src/
|
|
815
|
-
var
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
isDeployed: async (address) => {
|
|
834
|
-
const code = await client.getCode({ address });
|
|
835
|
-
return Boolean(code && code !== "0x");
|
|
836
|
-
},
|
|
837
|
-
readVaultOwner: (vault) => client.readContract({ address: vault, abi: SURFLIQUID_VAULT_ABI, functionName: "owner" }),
|
|
838
|
-
hasInitialDeposit: (vault, asset) => client.readContract({
|
|
839
|
-
address: vault,
|
|
840
|
-
abi: SURFLIQUID_VAULT_ABI,
|
|
841
|
-
functionName: "assetHasInitialDeposit",
|
|
842
|
-
args: [asset]
|
|
843
|
-
}),
|
|
844
|
-
usdcBalanceOf: (address) => client.readContract({
|
|
845
|
-
address: SURFLIQUID_USDC_ADDRESS,
|
|
846
|
-
abi: USDC_ABI,
|
|
847
|
-
functionName: "balanceOf",
|
|
848
|
-
args: [address]
|
|
849
|
-
}),
|
|
850
|
-
// Cast: viem's OP-stack tx union does not match the generic PublicClient
|
|
851
|
-
// the helper is typed against, though every method it uses is present.
|
|
852
|
-
readTokenMeta: () => readTokenMeta(client, SURFLIQUID_USDC_ADDRESS)
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
function pinAccount(provider, address) {
|
|
856
|
-
return {
|
|
857
|
-
...provider,
|
|
858
|
-
request: (args) => args.method === "eth_accounts" || args.method === "eth_requestAccounts" ? Promise.resolve([address]) : provider.request(args)
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
|
-
async function createSponsoredWallet(input) {
|
|
862
|
-
const entryPoint = { address: import_account_abstraction.entryPoint08Address, version: "0.8" };
|
|
863
|
-
const account = await (0, import_accounts.toSimpleSmartAccount)({
|
|
864
|
-
client: publicClientFor(input.rpcUrl),
|
|
865
|
-
owner: pinAccount(input.provider, input.ownerAddress),
|
|
866
|
-
entryPoint
|
|
867
|
-
});
|
|
868
|
-
const bundlerTransport = (0, import_viem8.http)(sponsorProxyUrl(input.routingApiBaseUrl), {
|
|
869
|
-
fetchOptions: { headers: { "x-owney-api-key": input.apiKey } }
|
|
870
|
-
});
|
|
871
|
-
const pimlico = (0, import_pimlico.createPimlicoClient)({ transport: bundlerTransport, entryPoint });
|
|
872
|
-
const smartAccountClient = (0, import_permissionless.createSmartAccountClient)({
|
|
873
|
-
account,
|
|
874
|
-
chain: import_chains2.base,
|
|
875
|
-
bundlerTransport,
|
|
876
|
-
paymaster: pimlico,
|
|
877
|
-
userOperation: {
|
|
878
|
-
estimateFeesPerGas: async () => (await pimlico.getUserOperationGasPrice()).fast
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
const walletClient = (0, import_viem8.createWalletClient)({
|
|
882
|
-
account: input.ownerAddress,
|
|
883
|
-
chain: import_chains2.base,
|
|
884
|
-
transport: (0, import_viem8.custom)(input.provider)
|
|
885
|
-
});
|
|
886
|
-
return {
|
|
887
|
-
smartAccountAddress: account.address,
|
|
888
|
-
ownerAddress: input.ownerAddress,
|
|
889
|
-
// The EOA signs, not the smart account: USDC verifies ECDSA from the token holder.
|
|
890
|
-
signTransferAuthorization: (typedData) => walletClient.signTypedData({
|
|
891
|
-
account: input.ownerAddress,
|
|
892
|
-
domain: typedData.domain,
|
|
893
|
-
types: typedData.types,
|
|
894
|
-
primaryType: typedData.primaryType,
|
|
895
|
-
message: typedData.message
|
|
896
|
-
}),
|
|
897
|
-
sendCalls: async (calls) => {
|
|
898
|
-
const userOpHash = await smartAccountClient.sendUserOperation({
|
|
899
|
-
calls: calls.map((c) => ({ to: c.to, data: c.data, value: 0n }))
|
|
900
|
-
});
|
|
901
|
-
try {
|
|
902
|
-
const receipt = await smartAccountClient.waitForUserOperationReceipt({ hash: userOpHash });
|
|
903
|
-
return receipt.receipt.transactionHash;
|
|
904
|
-
} catch (error) {
|
|
905
|
-
throw new SubmittedError(
|
|
906
|
-
`user operation ${userOpHash} was submitted but its receipt never arrived`,
|
|
907
|
-
userOpHash
|
|
908
|
-
);
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
};
|
|
912
|
-
}
|
|
913
|
-
var import_permissionless, import_accounts, import_pimlico, import_viem8, import_account_abstraction, import_chains2, sponsorProxyUrl;
|
|
914
|
-
var init_surfliquid_smart_account = __esm({
|
|
915
|
-
"src/agents/surfliquid/surfliquid.smart-account.ts"() {
|
|
916
|
-
"use strict";
|
|
917
|
-
import_permissionless = require("permissionless");
|
|
918
|
-
import_accounts = require("permissionless/accounts");
|
|
919
|
-
import_pimlico = require("permissionless/clients/pimlico");
|
|
920
|
-
import_viem8 = require("viem");
|
|
921
|
-
import_account_abstraction = require("viem/account-abstraction");
|
|
922
|
-
import_chains2 = require("viem/chains");
|
|
923
|
-
init_transfer_auth();
|
|
924
|
-
init_surfliquid_constants();
|
|
925
|
-
init_surfliquid_contracts();
|
|
926
|
-
init_surfliquid_sponsorship();
|
|
927
|
-
sponsorProxyUrl = (routingApiBaseUrl) => `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/sponsor/pimlico-rpc/${SURFLIQUID_CHAIN_ID}`;
|
|
140
|
+
// src/lib/agent-reads.ts
|
|
141
|
+
var AgentReads = class {
|
|
142
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
143
|
+
cooldowns = /* @__PURE__ */ new Map();
|
|
144
|
+
// A reconnect must not reuse work started by the previous connection.
|
|
145
|
+
clearInFlight() {
|
|
146
|
+
this.inFlight.clear();
|
|
147
|
+
}
|
|
148
|
+
limited(agentId, until) {
|
|
149
|
+
return new OwneyError(
|
|
150
|
+
"AGENT_RATE_LIMITED",
|
|
151
|
+
"Too many requests. Please wait before trying again.",
|
|
152
|
+
{
|
|
153
|
+
statusCode: 429,
|
|
154
|
+
retryAt: until,
|
|
155
|
+
retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3))
|
|
156
|
+
},
|
|
157
|
+
agentId
|
|
158
|
+
);
|
|
928
159
|
}
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
"14D": "apy14d",
|
|
952
|
-
"30D": "apy30d"
|
|
953
|
-
};
|
|
954
|
-
SurfLiquidAgent = class {
|
|
955
|
-
constructor(config) {
|
|
956
|
-
this.config = config;
|
|
957
|
-
}
|
|
958
|
-
config;
|
|
959
|
-
id = "surfliquid";
|
|
960
|
-
supportedChainIds = [SURFLIQUID_CHAIN_ID];
|
|
961
|
-
supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
|
|
962
|
-
surf = null;
|
|
963
|
-
connectedAddress = null;
|
|
964
|
-
// In-flight connect+auth, shared by concurrent callers to dedupe SIWE.
|
|
965
|
-
connectPromise = null;
|
|
966
|
-
ensureSurf() {
|
|
967
|
-
if (this.surf) return this.surf;
|
|
968
|
-
this.surf = import_core_sdk2.SurfClient.create({
|
|
969
|
-
projectName: this.config.projectName,
|
|
970
|
-
appId: this.config.appId,
|
|
971
|
-
environment: "mainnet",
|
|
972
|
-
chainId: SURFLIQUID_CHAIN_ID,
|
|
973
|
-
apiBaseUrl: this.config.apiBaseUrl,
|
|
974
|
-
rpcUrl: this.config.rpcUrl,
|
|
975
|
-
// Let the SDK auto-approve USDC to the vault before depositing.
|
|
976
|
-
autoApprove: true
|
|
977
|
-
});
|
|
978
|
-
return this.surf;
|
|
979
|
-
}
|
|
980
|
-
/**
|
|
981
|
-
* Connects + authenticates the SurfClient against owney's provider. Skips the
|
|
982
|
-
* SIWE prompt when already authenticated for this wallet (cookie session).
|
|
983
|
-
*/
|
|
984
|
-
async connect(state) {
|
|
985
|
-
const surf = this.ensureSurf();
|
|
986
|
-
const sameWallet = this.connectedAddress?.toLowerCase() === state.walletAddress.toLowerCase();
|
|
987
|
-
if (sameWallet && surf.getAuthState().authenticated) {
|
|
988
|
-
return surf;
|
|
989
|
-
}
|
|
990
|
-
if (this.connectPromise) return this.connectPromise;
|
|
991
|
-
this.connectPromise = (async () => {
|
|
992
|
-
surf.registerWalletAdapter(
|
|
993
|
-
"owney",
|
|
994
|
-
new OwneyWalletAdapter(state.provider)
|
|
995
|
-
);
|
|
996
|
-
await surf.connectWallet("owney");
|
|
997
|
-
await surf.authenticate();
|
|
998
|
-
this.connectedAddress = state.walletAddress;
|
|
999
|
-
return surf;
|
|
1000
|
-
})();
|
|
1001
|
-
try {
|
|
1002
|
-
return await this.connectPromise;
|
|
1003
|
-
} finally {
|
|
1004
|
-
this.connectPromise = null;
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
/**
|
|
1008
|
-
* Returns the user's vault address, deploying one on first use. SurfLiquid's
|
|
1009
|
-
* deposit requires the vault to exist, so this must run before depositing.
|
|
1010
|
-
* Existing vault → returned as-is; otherwise `deployVault()` is sent
|
|
1011
|
-
* (user-pays) and the freshly deployed address is returned.
|
|
1012
|
-
*/
|
|
1013
|
-
async resolveVaultAddress(surf, owner) {
|
|
1014
|
-
const vault = await surf.getVault(owner).catch(() => null);
|
|
1015
|
-
if (vault?.exists && vault.userVaultAddress) {
|
|
1016
|
-
return vault.userVaultAddress;
|
|
1017
|
-
}
|
|
1018
|
-
const { vaultAddress } = await surf.deployVault();
|
|
1019
|
-
return vaultAddress;
|
|
1020
|
-
}
|
|
1021
|
-
/**
|
|
1022
|
-
* Grants the user's vault a standing USDC allowance so SurfLiquid's
|
|
1023
|
-
* `autoApprove` has nothing to do — see {@link SURFLIQUID_APPROVAL_TARGET}
|
|
1024
|
-
* for why one prompt per deposit is worth removing.
|
|
1025
|
-
*
|
|
1026
|
-
* Fails OPEN on a read error: if the allowance can't be checked we simply
|
|
1027
|
-
* return and let SurfLiquid's own per-deposit approve run, because a flaky
|
|
1028
|
-
* RPC must never block a deposit. A failed or rejected APPROVE does
|
|
1029
|
-
* propagate — the user declined a transaction, and letting SurfLiquid
|
|
1030
|
-
* immediately ask again for a smaller one is exactly the double prompt this
|
|
1031
|
-
* removes.
|
|
1032
|
-
*/
|
|
1033
|
-
async ensureVaultAllowance(state, vaultAddress, amount) {
|
|
1034
|
-
const spender = vaultAddress;
|
|
1035
|
-
const transport = (0, import_viem9.custom)(state.provider);
|
|
1036
|
-
const publicClient = (0, import_viem9.createPublicClient)({ chain: import_chains3.base, transport });
|
|
1037
|
-
let allowance;
|
|
1038
|
-
try {
|
|
1039
|
-
allowance = await publicClient.readContract({
|
|
1040
|
-
address: SURFLIQUID_USDC_ADDRESS,
|
|
1041
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
1042
|
-
functionName: "allowance",
|
|
1043
|
-
args: [state.walletAddress, spender]
|
|
1044
|
-
});
|
|
1045
|
-
} catch (error) {
|
|
1046
|
-
console.warn(
|
|
1047
|
-
"[owney-sdk] SurfLiquid allowance pre-check failed; deferring to its per-deposit approve:",
|
|
1048
|
-
error instanceof Error ? error.message : String(error)
|
|
1049
|
-
);
|
|
1050
|
-
return;
|
|
1051
|
-
}
|
|
1052
|
-
if (allowance >= amount) return;
|
|
1053
|
-
const target = amount > SURFLIQUID_APPROVAL_TARGET ? amount : SURFLIQUID_APPROVAL_TARGET;
|
|
1054
|
-
const wallet = (0, import_viem9.createWalletClient)({
|
|
1055
|
-
account: state.walletAddress,
|
|
1056
|
-
chain: import_chains3.base,
|
|
1057
|
-
transport
|
|
1058
|
-
});
|
|
1059
|
-
const hash = await wallet.writeContract({
|
|
1060
|
-
address: SURFLIQUID_USDC_ADDRESS,
|
|
1061
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
1062
|
-
functionName: "approve",
|
|
1063
|
-
args: [spender, target],
|
|
1064
|
-
account: state.walletAddress,
|
|
1065
|
-
chain: import_chains3.base
|
|
1066
|
-
});
|
|
1067
|
-
const receipt = await publicClient.waitForTransactionReceipt({
|
|
1068
|
-
hash,
|
|
1069
|
-
confirmations: 1
|
|
1070
|
-
});
|
|
1071
|
-
if (receipt.status !== "success") {
|
|
1072
|
-
throw new Error(`SurfLiquid USDC approval reverted (tx ${hash})`);
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
// --- IAgent: lifecycle ---
|
|
1076
|
-
async disconnect() {
|
|
1077
|
-
if (this.surf) {
|
|
1078
|
-
await this.surf.disconnectWallet();
|
|
1079
|
-
}
|
|
1080
|
-
this.connectedAddress = null;
|
|
1081
|
-
}
|
|
1082
|
-
async activateAgent(state) {
|
|
1083
|
-
await this.connect(state);
|
|
1084
|
-
}
|
|
1085
|
-
/** Their exported client, so `prepare`/`confirm` ride the SIWE cookie this session already holds. */
|
|
1086
|
-
async vaultApi() {
|
|
1087
|
-
const { HttpClient, VaultApiService } = await import("@surf_liquid/core-sdk");
|
|
1088
|
-
return new VaultApiService(
|
|
1089
|
-
new HttpClient({
|
|
1090
|
-
baseUrl: this.config.apiBaseUrl ?? "https://api.surfliquid.com",
|
|
1091
|
-
projectName: this.config.projectName,
|
|
1092
|
-
projectId: this.config.projectName,
|
|
1093
|
-
appId: this.config.appId ?? ""
|
|
1094
|
-
})
|
|
1095
|
-
);
|
|
1096
|
-
}
|
|
1097
|
-
async sponsoredWallet(state) {
|
|
1098
|
-
if (!this.config.apiKey) return null;
|
|
1099
|
-
const { createSponsoredWallet: createSponsoredWallet2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
|
|
1100
|
-
const { ROUTING_API_BASE_URL: ROUTING_API_BASE_URL4 } = await Promise.resolve().then(() => (init_routing_api(), routing_api_exports));
|
|
1101
|
-
return createSponsoredWallet2({
|
|
1102
|
-
provider: state.provider,
|
|
1103
|
-
ownerAddress: state.walletAddress,
|
|
1104
|
-
// Apps rarely set this; without the default, sponsorship silently never runs in production.
|
|
1105
|
-
routingApiBaseUrl: this.config.routingApiBaseUrl ?? ROUTING_API_BASE_URL4,
|
|
1106
|
-
apiKey: this.config.apiKey,
|
|
1107
|
-
rpcUrl: this.config.rpcUrl
|
|
1108
|
-
});
|
|
1109
|
-
}
|
|
1110
|
-
/** Null means nothing happened on-chain, so the caller is free to retry as user-pays. */
|
|
1111
|
-
async trySponsoredDeposit(state, amount) {
|
|
1112
|
-
const wallet = await this.sponsoredWallet(state).catch(() => null);
|
|
1113
|
-
if (!wallet) return null;
|
|
1114
|
-
const { depositSponsored: depositSponsored2, isSafeToRetry: isSafeToRetry2 } = await Promise.resolve().then(() => (init_surfliquid_sponsorship(), surfliquid_sponsorship_exports));
|
|
1115
|
-
const { createSponsoredChain: createSponsoredChain2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
|
|
1116
|
-
try {
|
|
1117
|
-
const { txHash, vault } = await depositSponsored2({
|
|
1118
|
-
amount,
|
|
1119
|
-
api: await this.vaultApi(),
|
|
1120
|
-
chain: createSponsoredChain2(this.config.rpcUrl),
|
|
1121
|
-
wallet
|
|
1122
|
-
});
|
|
1123
|
-
return { txHash, smartWallet: vault };
|
|
1124
|
-
} catch (error) {
|
|
1125
|
-
if (!isSafeToRetry2(error)) throw error;
|
|
1126
|
-
console.warn(
|
|
1127
|
-
"[owney-sdk] SurfLiquid sponsored deposit unavailable; falling back to user-pays:",
|
|
1128
|
-
error instanceof Error ? error.message : String(error)
|
|
1129
|
-
);
|
|
1130
|
-
return null;
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
async trySponsoredWithdraw(state, amount) {
|
|
1134
|
-
const wallet = await this.sponsoredWallet(state).catch(() => null);
|
|
1135
|
-
if (!wallet) return null;
|
|
1136
|
-
const { withdrawSponsored: withdrawSponsored2, isSafeToRetry: isSafeToRetry2 } = await Promise.resolve().then(() => (init_surfliquid_sponsorship(), surfliquid_sponsorship_exports));
|
|
1137
|
-
const { createSponsoredChain: createSponsoredChain2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
|
|
1138
|
-
try {
|
|
1139
|
-
const result = await withdrawSponsored2({
|
|
1140
|
-
amount: amount != null ? BigInt(amount) : void 0,
|
|
1141
|
-
api: await this.vaultApi(),
|
|
1142
|
-
chain: createSponsoredChain2(this.config.rpcUrl),
|
|
1143
|
-
wallet
|
|
1144
|
-
});
|
|
1145
|
-
return {
|
|
1146
|
-
txHash: result.txHash,
|
|
1147
|
-
type: amount != null ? "partial" : "full",
|
|
1148
|
-
amount: result.amount
|
|
1149
|
-
};
|
|
1150
|
-
} catch (error) {
|
|
1151
|
-
if (!isSafeToRetry2(error)) throw error;
|
|
1152
|
-
console.warn(
|
|
1153
|
-
"[owney-sdk] SurfLiquid sponsored withdraw unavailable; falling back to user-pays:",
|
|
1154
|
-
error instanceof Error ? error.message : String(error)
|
|
1155
|
-
);
|
|
1156
|
-
return null;
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
// --- IAgent: funds (gasless when sponsorship is reachable, else user-pays) ---
|
|
1160
|
-
async deposit(state, _chainId, amount, _asset, _depositCallback) {
|
|
1161
|
-
const surf = await this.connect(state);
|
|
1162
|
-
const sponsored = await this.trySponsoredDeposit(state, BigInt(amount));
|
|
1163
|
-
if (sponsored) return { ...sponsored, amount };
|
|
1164
|
-
const human = (0, import_viem9.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS);
|
|
1165
|
-
const smartWallet = await this.resolveVaultAddress(
|
|
1166
|
-
surf,
|
|
1167
|
-
state.walletAddress
|
|
1168
|
-
);
|
|
1169
|
-
await this.ensureVaultAllowance(state, smartWallet, BigInt(amount));
|
|
1170
|
-
const tx = await surf.deposit({
|
|
1171
|
-
asset: SURFLIQUID_USDC_ADDRESS,
|
|
1172
|
-
amount: human
|
|
1173
|
-
});
|
|
1174
|
-
await tx.wait();
|
|
1175
|
-
return { txHash: tx.hash, smartWallet, amount };
|
|
1176
|
-
}
|
|
1177
|
-
async withdraw(state, _chainId, _token, amount) {
|
|
1178
|
-
const surf = await this.connect(state);
|
|
1179
|
-
const sponsored = await this.trySponsoredWithdraw(state, amount);
|
|
1180
|
-
if (sponsored) return sponsored;
|
|
1181
|
-
const human = amount != null ? (0, import_viem9.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS) : void 0;
|
|
1182
|
-
try {
|
|
1183
|
-
const tx = await surf.withdraw({
|
|
1184
|
-
asset: SURFLIQUID_USDC_ADDRESS,
|
|
1185
|
-
amount: human
|
|
1186
|
-
});
|
|
1187
|
-
await tx.wait();
|
|
1188
|
-
return {
|
|
1189
|
-
txHash: tx.hash,
|
|
1190
|
-
type: amount != null ? "partial" : "full",
|
|
1191
|
-
amount: amount ?? "0"
|
|
1192
|
-
};
|
|
1193
|
-
} catch (error) {
|
|
1194
|
-
throw new OwneyError(
|
|
1195
|
-
"WITHDRAW_FAILED",
|
|
1196
|
-
error instanceof Error ? error.message : "SurfLiquid withdraw failed.",
|
|
1197
|
-
{ chainId: SURFLIQUID_CHAIN_ID, amount },
|
|
1198
|
-
this.id
|
|
1199
|
-
);
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
// --- IAgent: portfolio reads ---
|
|
1203
|
-
async getBalances(state, chainId) {
|
|
1204
|
-
const surf = await this.connect(state);
|
|
1205
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
1206
|
-
const morphoVaultAddresses = (vault.assets ?? []).filter((asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId).map((asset) => asset.morphoVaultAddress).filter((address) => Boolean(address));
|
|
1207
|
-
const morphoStats = await fetchMorphoStatsByVault(
|
|
1208
|
-
morphoVaultAddresses,
|
|
1209
|
-
chainId
|
|
1210
|
-
);
|
|
1211
|
-
return mapBalances2(vault, chainId, morphoStats);
|
|
1212
|
-
}
|
|
1213
|
-
async getEarnings(state) {
|
|
1214
|
-
const surf = await this.connect(state);
|
|
1215
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
1216
|
-
return mapEarnings2(vault, vault.userVaultAddress ?? state.walletAddress);
|
|
1217
|
-
}
|
|
1218
|
-
async getAccountApy(state, _chainId, days, _tokenSymbol) {
|
|
1219
|
-
const surf = await this.connect(state);
|
|
1220
|
-
const vault = await surf.getVault(state.walletAddress);
|
|
1221
|
-
return mapAccountApy(vault, days);
|
|
1222
|
-
}
|
|
1223
|
-
async getHistory(state, chainId, options) {
|
|
1224
|
-
const surf = await this.connect(state);
|
|
1225
|
-
const page = options?.cursor ? Number(options.cursor) : 1;
|
|
1226
|
-
const limit = options?.limit ?? 10;
|
|
1227
|
-
const result = await surf.getAgentMessages(
|
|
1228
|
-
state.walletAddress,
|
|
1229
|
-
page,
|
|
1230
|
-
limit,
|
|
1231
|
-
options?.fromDate,
|
|
1232
|
-
options?.toDate
|
|
160
|
+
run(agentId, key2, fetch2) {
|
|
161
|
+
const cooldown = this.cooldowns.get(agentId);
|
|
162
|
+
if (cooldown && cooldown.until > Date.now()) {
|
|
163
|
+
return Promise.reject(this.limited(agentId, cooldown.until));
|
|
164
|
+
}
|
|
165
|
+
const requestKey = JSON.stringify([agentId, key2]);
|
|
166
|
+
const existing = this.inFlight.get(requestKey);
|
|
167
|
+
if (existing) return existing;
|
|
168
|
+
const promise = Promise.resolve().then(fetch2).then(
|
|
169
|
+
(value) => {
|
|
170
|
+
if (this.cooldowns.get(agentId) === cooldown)
|
|
171
|
+
this.cooldowns.delete(agentId);
|
|
172
|
+
return value;
|
|
173
|
+
},
|
|
174
|
+
(error) => {
|
|
175
|
+
const requestedDelay = rateLimitDelay(error);
|
|
176
|
+
if (requestedDelay === void 0) throw error;
|
|
177
|
+
const previous = this.cooldowns.get(agentId);
|
|
178
|
+
const failures = previous && previous.until > Date.now() ? previous.failures : Math.min((previous?.failures ?? 0) + 1, 5);
|
|
179
|
+
const delay = Math.max(
|
|
180
|
+
requestedDelay,
|
|
181
|
+
Math.min(3e4 * 2 ** (failures - 1), 3e5)
|
|
1233
182
|
);
|
|
1234
|
-
|
|
183
|
+
const until = Math.max(previous?.until ?? 0, Date.now() + delay);
|
|
184
|
+
this.cooldowns.set(agentId, { until, failures });
|
|
185
|
+
throw this.limited(agentId, until);
|
|
1235
186
|
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
async getAgentApy(days, _options) {
|
|
1243
|
-
const surf = this.ensureSurf();
|
|
1244
|
-
const assets = await surf.getSupportedAssets(SURFLIQUID_CHAIN_ID);
|
|
1245
|
-
const usdc = assets.find((asset) => asset.assetSymbol === "USDC");
|
|
1246
|
-
if (!usdc) return { averageApy: 0 };
|
|
1247
|
-
const windowed = usdc[APY_WINDOW_KEY2[days]];
|
|
1248
|
-
return { averageApy: windowed != null ? windowed : usdc.currentAPY };
|
|
1249
|
-
}
|
|
1250
|
-
};
|
|
187
|
+
).finally(() => {
|
|
188
|
+
if (this.inFlight.get(requestKey) === promise)
|
|
189
|
+
this.inFlight.delete(requestKey);
|
|
190
|
+
});
|
|
191
|
+
this.inFlight.set(requestKey, promise);
|
|
192
|
+
return promise;
|
|
1251
193
|
}
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
// src/index.ts
|
|
1255
|
-
var index_exports = {};
|
|
1256
|
-
__export(index_exports, {
|
|
1257
|
-
AgentChainIncompatibleError: () => AgentChainIncompatibleError,
|
|
1258
|
-
AgentNotFoundError: () => AgentNotFoundError,
|
|
1259
|
-
InvalidHistoryCursorError: () => InvalidHistoryCursorError,
|
|
1260
|
-
NotConnectedError: () => NotConnectedError,
|
|
1261
|
-
OwneyError: () => OwneyError,
|
|
1262
|
-
OwneySDK: () => OwneySDK,
|
|
1263
|
-
createOwneySIWX: () => createOwneySIWX,
|
|
1264
|
-
setOwneyDebug: () => setOwneyDebug
|
|
1265
|
-
});
|
|
1266
|
-
module.exports = __toCommonJS(index_exports);
|
|
194
|
+
};
|
|
1267
195
|
|
|
1268
196
|
// src/agents/zyfai/zyfai.agent.ts
|
|
1269
197
|
var import_sdk = require("@zyfai/sdk");
|
|
@@ -1317,11 +245,24 @@ var SupportedAssets = [
|
|
|
1317
245
|
}
|
|
1318
246
|
];
|
|
1319
247
|
|
|
1320
|
-
// src/
|
|
1321
|
-
|
|
248
|
+
// src/lib/debug.ts
|
|
249
|
+
var configuredDebug = false;
|
|
250
|
+
function setOwneyDebug(enabled) {
|
|
251
|
+
configuredDebug = enabled;
|
|
252
|
+
}
|
|
253
|
+
function isOwneyDebug() {
|
|
254
|
+
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
255
|
+
}
|
|
256
|
+
function debugLog(scope, message, data) {
|
|
257
|
+
if (!isOwneyDebug()) return;
|
|
258
|
+
if (data === void 0) {
|
|
259
|
+
console.log(`[${scope}] ${message}`);
|
|
260
|
+
} else {
|
|
261
|
+
console.log(`[${scope}] ${message}`, data);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
1322
264
|
|
|
1323
265
|
// src/lib/utils.ts
|
|
1324
|
-
init_errors();
|
|
1325
266
|
var isValidChainId = (chainId) => {
|
|
1326
267
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
1327
268
|
throw new OwneyError(
|
|
@@ -1332,12 +273,6 @@ var isValidChainId = (chainId) => {
|
|
|
1332
273
|
}
|
|
1333
274
|
return chainId;
|
|
1334
275
|
};
|
|
1335
|
-
function isSameAsset(tokenSymbol, asset) {
|
|
1336
|
-
const token = tokenSymbol.toLowerCase();
|
|
1337
|
-
const target = asset.toLowerCase();
|
|
1338
|
-
if (token === target) return true;
|
|
1339
|
-
return target === "weth" && token === "eth" || target === "eth" && token === "weth";
|
|
1340
|
-
}
|
|
1341
276
|
function hexToDecimal(hex, decimals = 6) {
|
|
1342
277
|
const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
|
|
1343
278
|
const parsed = BigInt(normalized);
|
|
@@ -1800,9 +735,6 @@ function decodeHistoryCursor(token) {
|
|
|
1800
735
|
return parsed;
|
|
1801
736
|
}
|
|
1802
737
|
|
|
1803
|
-
// src/agents/zyfai/zyfai.agent.ts
|
|
1804
|
-
init_errors();
|
|
1805
|
-
|
|
1806
738
|
// src/agents/zyfai/zyfai.auth-cache.ts
|
|
1807
739
|
var KEY_PREFIX = "owney.zyfai.session";
|
|
1808
740
|
var storage = () => {
|
|
@@ -2065,7 +997,6 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
|
|
|
2065
997
|
}
|
|
2066
998
|
|
|
2067
999
|
// src/agents/zyfai/zyfai.agent.ts
|
|
2068
|
-
init_debug();
|
|
2069
1000
|
var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem.parseAbi)([
|
|
2070
1001
|
"function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
|
|
2071
1002
|
]);
|
|
@@ -2134,7 +1065,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2134
1065
|
// successful decode is cached forever; failures are NOT cached so a transient
|
|
2135
1066
|
// RPC error retries on the next fetch.
|
|
2136
1067
|
withdrawAmountCache = /* @__PURE__ */ new Map();
|
|
2137
|
-
|
|
1068
|
+
earningsReads = /* @__PURE__ */ new Map();
|
|
1069
|
+
earningsRefreshes = /* @__PURE__ */ new Map();
|
|
1070
|
+
earningsSnapshot = null;
|
|
1071
|
+
earningsGeneration = 0;
|
|
2138
1072
|
constructor(apiKey, rpcUrls, referralSource) {
|
|
2139
1073
|
this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
|
|
2140
1074
|
this.sdk = new import_sdk.ZyfaiSDK({
|
|
@@ -2379,6 +1313,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2379
1313
|
}
|
|
2380
1314
|
// --- IAgent: Connection lifecycle ---
|
|
2381
1315
|
async disconnect() {
|
|
1316
|
+
this.earningsGeneration++;
|
|
1317
|
+
this.earningsReads.clear();
|
|
1318
|
+
this.earningsRefreshes.clear();
|
|
1319
|
+
this.earningsSnapshot = null;
|
|
2382
1320
|
if (this.connectedAddress && this.connectedChainId !== null) {
|
|
2383
1321
|
clearSession(this.connectedAddress, this.connectedChainId);
|
|
2384
1322
|
}
|
|
@@ -2571,39 +1509,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2571
1509
|
} catch (error) {
|
|
2572
1510
|
console.warn(
|
|
2573
1511
|
"[zyfai] applyPoolPolicy failed (non-fatal):",
|
|
2574
|
-
error instanceof Error ? error.message : String(error)
|
|
2575
|
-
);
|
|
2576
|
-
}
|
|
2577
|
-
}
|
|
2578
|
-
/**
|
|
2579
|
-
* Records the deposit with Zyfai, retrying transient failures.
|
|
2580
|
-
*
|
|
2581
|
-
* This runs AFTER the transfer has already landed on-chain, so it must never
|
|
2582
|
-
* fail the deposit — the funds moved. But it is also the ONLY source of the
|
|
2583
|
-
* "Top up wallet" entry the history is built from: Zyfai auto-deploys the
|
|
2584
|
-
* balance it detects either way, so when this call is lost the user's deposit
|
|
2585
|
-
* never appears in Activity (an earlier withdrawal stays the newest row) and
|
|
2586
|
-
* nothing ever backfills it. Retry, then log loudly enough to be recoverable.
|
|
2587
|
-
*/
|
|
2588
|
-
async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
|
|
2589
|
-
const ATTEMPTS = 3;
|
|
2590
|
-
const RETRY_DELAY_MS = 1e3;
|
|
2591
|
-
for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
|
|
2592
|
-
try {
|
|
2593
|
-
await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
|
|
2594
|
-
return;
|
|
2595
|
-
} catch (logError) {
|
|
2596
|
-
if (attempt === ATTEMPTS) {
|
|
2597
|
-
console.error(
|
|
2598
|
-
"[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
|
|
2599
|
-
{ txHash, chainId, amount, tokenAddress, error: logError }
|
|
2600
|
-
);
|
|
2601
|
-
return;
|
|
2602
|
-
}
|
|
2603
|
-
await new Promise(
|
|
2604
|
-
(resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
|
|
2605
|
-
);
|
|
2606
|
-
}
|
|
1512
|
+
error instanceof Error ? error.message : String(error)
|
|
1513
|
+
);
|
|
2607
1514
|
}
|
|
2608
1515
|
}
|
|
2609
1516
|
/**
|
|
@@ -2909,12 +1816,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2909
1816
|
);
|
|
2910
1817
|
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
2911
1818
|
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
2912
|
-
|
|
2913
|
-
validChainId,
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
1819
|
+
try {
|
|
1820
|
+
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
1821
|
+
} catch (logError) {
|
|
1822
|
+
console.warn(
|
|
1823
|
+
"[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
|
|
1824
|
+
logError
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
2918
1827
|
return { txHash, smartWallet, amount };
|
|
2919
1828
|
}
|
|
2920
1829
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
@@ -2956,26 +1865,59 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2956
1865
|
const raw = await this.sdk.getPortfolio(this.getAddress());
|
|
2957
1866
|
return mapBalances(raw, validChainId, smartWallet);
|
|
2958
1867
|
}
|
|
1868
|
+
earningsKey(state, chainId, smartWallet) {
|
|
1869
|
+
return JSON.stringify([
|
|
1870
|
+
state.walletAddress?.toLowerCase(),
|
|
1871
|
+
chainId,
|
|
1872
|
+
smartWallet.toLowerCase()
|
|
1873
|
+
]);
|
|
1874
|
+
}
|
|
1875
|
+
readEarnings(key2, smartWallet) {
|
|
1876
|
+
const existing = this.earningsReads.get(key2);
|
|
1877
|
+
if (existing) return existing;
|
|
1878
|
+
const generation = this.earningsGeneration;
|
|
1879
|
+
const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw) => {
|
|
1880
|
+
if (generation === this.earningsGeneration) {
|
|
1881
|
+
this.earningsSnapshot = { key: key2, raw, at: Date.now() };
|
|
1882
|
+
}
|
|
1883
|
+
return raw;
|
|
1884
|
+
}).finally(() => {
|
|
1885
|
+
if (this.earningsReads.get(key2) === pending)
|
|
1886
|
+
this.earningsReads.delete(key2);
|
|
1887
|
+
});
|
|
1888
|
+
this.earningsReads.set(key2, pending);
|
|
1889
|
+
return pending;
|
|
1890
|
+
}
|
|
2959
1891
|
async getEarnings(state, chainId) {
|
|
2960
1892
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
2961
|
-
const raw = await this.
|
|
1893
|
+
const raw = await this.readEarnings(
|
|
1894
|
+
this.earningsKey(state, chainId, smartWallet),
|
|
1895
|
+
smartWallet
|
|
1896
|
+
);
|
|
2962
1897
|
return mapEarnings(raw, smartWallet);
|
|
2963
1898
|
}
|
|
2964
1899
|
async refreshEarnings(state, chainId) {
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
1900
|
+
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1901
|
+
const key2 = this.earningsKey(state, chainId, smartWallet);
|
|
1902
|
+
const existing = this.earningsRefreshes.get(key2);
|
|
1903
|
+
if (existing) return existing;
|
|
1904
|
+
const generation = this.earningsGeneration;
|
|
1905
|
+
const pending = (async () => {
|
|
1906
|
+
const recent = this.earningsSnapshot;
|
|
1907
|
+
const current = recent?.key === key2 && Date.now() - recent.at < 5e3 ? recent.raw : await this.readEarnings(key2, smartWallet);
|
|
2969
1908
|
const lastCheck = current.data.lastCheckTimestamp ? Date.parse(current.data.lastCheckTimestamp) : Number.NaN;
|
|
2970
1909
|
const isFresh = Number.isFinite(lastCheck) && Date.now() - lastCheck < EARNINGS_REFRESH_COOLDOWN_MS;
|
|
2971
1910
|
const earnings = isFresh ? current : await this.sdk.calculateOnchainEarnings(smartWallet);
|
|
1911
|
+
if (!isFresh && generation === this.earningsGeneration) {
|
|
1912
|
+
this.earningsSnapshot = { key: key2, raw: earnings, at: Date.now() };
|
|
1913
|
+
}
|
|
2972
1914
|
return mapEarnings(earnings, smartWallet);
|
|
2973
|
-
})()
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
}
|
|
2977
|
-
|
|
2978
|
-
|
|
1915
|
+
})().finally(() => {
|
|
1916
|
+
if (this.earningsRefreshes.get(key2) === pending)
|
|
1917
|
+
this.earningsRefreshes.delete(key2);
|
|
1918
|
+
});
|
|
1919
|
+
this.earningsRefreshes.set(key2, pending);
|
|
1920
|
+
return pending;
|
|
2979
1921
|
}
|
|
2980
1922
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
2981
1923
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
@@ -3095,13 +2037,71 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
3095
2037
|
}
|
|
3096
2038
|
};
|
|
3097
2039
|
|
|
3098
|
-
// src/
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
2040
|
+
// src/lib/routing-api.ts
|
|
2041
|
+
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2042
|
+
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2043
|
+
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
2044
|
+
try {
|
|
2045
|
+
const res = await fetch(url, {
|
|
2046
|
+
method: "GET",
|
|
2047
|
+
headers: {
|
|
2048
|
+
"Content-Type": "application/json",
|
|
2049
|
+
"x-owney-api-key": `${apiKey}`
|
|
2050
|
+
}
|
|
2051
|
+
});
|
|
2052
|
+
if (!res.ok) {
|
|
2053
|
+
if (res.status !== 404) {
|
|
2054
|
+
console.warn(
|
|
2055
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
2056
|
+
);
|
|
2057
|
+
}
|
|
2058
|
+
return null;
|
|
2059
|
+
}
|
|
2060
|
+
const json = await res.json();
|
|
2061
|
+
const policy = json.success ? json.data ?? null : null;
|
|
2062
|
+
debugLog(
|
|
2063
|
+
"owney-sdk",
|
|
2064
|
+
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
2065
|
+
policy ?? void 0
|
|
2066
|
+
);
|
|
2067
|
+
return policy;
|
|
2068
|
+
} catch (error) {
|
|
2069
|
+
console.warn(
|
|
2070
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
2071
|
+
error instanceof Error ? error.message : String(error)
|
|
2072
|
+
);
|
|
2073
|
+
return null;
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2077
|
+
const url = `${baseUrl}/api/v1/agent/keys`;
|
|
2078
|
+
const res = await fetch(url, {
|
|
2079
|
+
method: "GET",
|
|
2080
|
+
headers: {
|
|
2081
|
+
"Content-Type": "application/json",
|
|
2082
|
+
"x-owney-api-key": `${apiKey}`
|
|
2083
|
+
}
|
|
2084
|
+
});
|
|
2085
|
+
if (!res.ok) {
|
|
2086
|
+
const text = await res.text().catch(() => "");
|
|
2087
|
+
throw new OwneyError(
|
|
2088
|
+
"API_ROUTING_ERROR",
|
|
2089
|
+
`Routing API error ${res.status}: ${text}`,
|
|
2090
|
+
{ statusCode: res.status, responseBody: text }
|
|
2091
|
+
);
|
|
2092
|
+
}
|
|
2093
|
+
const json = await res.json();
|
|
2094
|
+
if (!json.success) {
|
|
2095
|
+
throw new OwneyError(
|
|
2096
|
+
"API_ROUTING_FAILED",
|
|
2097
|
+
`Routing API request failed: ${json.message}`,
|
|
2098
|
+
{ message: json.message }
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
return json.data;
|
|
2102
|
+
}
|
|
3102
2103
|
|
|
3103
2104
|
// src/lib/health-report.ts
|
|
3104
|
-
init_errors();
|
|
3105
2105
|
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
3106
2106
|
async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
|
|
3107
2107
|
try {
|
|
@@ -3137,10 +2137,11 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
3137
2137
|
// src/lib/helpers/withdraw-helper.ts
|
|
3138
2138
|
var import_viem2 = require("viem");
|
|
3139
2139
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
2140
|
+
const target = asset.toUpperCase();
|
|
3140
2141
|
return agents.map((agent) => {
|
|
3141
2142
|
const agentBalance = aggregated[agent.id];
|
|
3142
2143
|
const tokenBalance = agentBalance?.tokens.find(
|
|
3143
|
-
(t) => t.chainId === chainId &&
|
|
2144
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
3144
2145
|
);
|
|
3145
2146
|
if (!tokenBalance) return { agent, balance: 0n };
|
|
3146
2147
|
return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
|
|
@@ -3250,21 +2251,52 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
3250
2251
|
}
|
|
3251
2252
|
|
|
3252
2253
|
// src/client.ts
|
|
3253
|
-
var
|
|
3254
|
-
var
|
|
2254
|
+
var import_viem6 = require("viem");
|
|
2255
|
+
var import_chains2 = require("viem/chains");
|
|
3255
2256
|
|
|
3256
|
-
// src/lib/
|
|
3257
|
-
|
|
3258
|
-
|
|
2257
|
+
// src/lib/transfer-auth.ts
|
|
2258
|
+
var import_viem3 = require("viem");
|
|
2259
|
+
var ERC20_META_ABI = [
|
|
2260
|
+
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
2261
|
+
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
2262
|
+
];
|
|
2263
|
+
function buildTransferWithAuthorizationTypedData(input) {
|
|
2264
|
+
return {
|
|
2265
|
+
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
2266
|
+
types: {
|
|
2267
|
+
TransferWithAuthorization: [
|
|
2268
|
+
{ name: "from", type: "address" },
|
|
2269
|
+
{ name: "to", type: "address" },
|
|
2270
|
+
{ name: "value", type: "uint256" },
|
|
2271
|
+
{ name: "validAfter", type: "uint256" },
|
|
2272
|
+
{ name: "validBefore", type: "uint256" },
|
|
2273
|
+
{ name: "nonce", type: "bytes32" }
|
|
2274
|
+
]
|
|
2275
|
+
},
|
|
2276
|
+
primaryType: "TransferWithAuthorization",
|
|
2277
|
+
message: input.message
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
async function readTokenMeta(publicClient, token) {
|
|
2281
|
+
const [tokenName, tokenVersion] = await Promise.all([
|
|
2282
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
2283
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
2284
|
+
]);
|
|
2285
|
+
return { tokenName, tokenVersion };
|
|
2286
|
+
}
|
|
2287
|
+
function randomAuthNonce() {
|
|
2288
|
+
const bytes = new Uint8Array(32);
|
|
2289
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
2290
|
+
return (0, import_viem3.bytesToHex)(bytes);
|
|
2291
|
+
}
|
|
3259
2292
|
|
|
3260
2293
|
// src/lib/sponsor-client.ts
|
|
3261
|
-
init_errors();
|
|
3262
2294
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
3263
2295
|
async function postSponsorTransferAuth(input) {
|
|
3264
|
-
const
|
|
2296
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
3265
2297
|
let res;
|
|
3266
2298
|
try {
|
|
3267
|
-
res = await fetch(`${
|
|
2299
|
+
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
3268
2300
|
method: "POST",
|
|
3269
2301
|
headers: {
|
|
3270
2302
|
"content-type": "application/json",
|
|
@@ -3301,10 +2333,10 @@ async function postSponsorTransferAuth(input) {
|
|
|
3301
2333
|
return parsed.data;
|
|
3302
2334
|
}
|
|
3303
2335
|
async function postSponsorPermit2Transfer(input) {
|
|
3304
|
-
const
|
|
2336
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
3305
2337
|
let res;
|
|
3306
2338
|
try {
|
|
3307
|
-
res = await fetch(`${
|
|
2339
|
+
res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
|
|
3308
2340
|
method: "POST",
|
|
3309
2341
|
headers: {
|
|
3310
2342
|
"content-type": "application/json",
|
|
@@ -3339,11 +2371,11 @@ async function postSponsorPermit2Transfer(input) {
|
|
|
3339
2371
|
return parsed.data;
|
|
3340
2372
|
}
|
|
3341
2373
|
async function getSponsorRelayerAddress(input) {
|
|
3342
|
-
const
|
|
2374
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
3343
2375
|
let res;
|
|
3344
2376
|
try {
|
|
3345
2377
|
res = await fetch(
|
|
3346
|
-
`${
|
|
2378
|
+
`${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
3347
2379
|
{
|
|
3348
2380
|
headers: { "x-owney-api-key": input.apiKey }
|
|
3349
2381
|
}
|
|
@@ -3375,11 +2407,85 @@ async function getSponsorRelayerAddress(input) {
|
|
|
3375
2407
|
return parsed.data.relayer;
|
|
3376
2408
|
}
|
|
3377
2409
|
|
|
3378
|
-
// src/lib/
|
|
3379
|
-
|
|
2410
|
+
// src/lib/permit2.ts
|
|
2411
|
+
var import_viem4 = require("viem");
|
|
2412
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2413
|
+
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
2414
|
+
var ERC20_ALLOWANCE_ABI = [
|
|
2415
|
+
{
|
|
2416
|
+
type: "function",
|
|
2417
|
+
name: "allowance",
|
|
2418
|
+
stateMutability: "view",
|
|
2419
|
+
inputs: [
|
|
2420
|
+
{ name: "owner", type: "address" },
|
|
2421
|
+
{ name: "spender", type: "address" }
|
|
2422
|
+
],
|
|
2423
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
2424
|
+
},
|
|
2425
|
+
{
|
|
2426
|
+
type: "function",
|
|
2427
|
+
name: "approve",
|
|
2428
|
+
stateMutability: "nonpayable",
|
|
2429
|
+
inputs: [
|
|
2430
|
+
{ name: "spender", type: "address" },
|
|
2431
|
+
{ name: "amount", type: "uint256" }
|
|
2432
|
+
],
|
|
2433
|
+
outputs: [{ name: "", type: "bool" }]
|
|
2434
|
+
},
|
|
2435
|
+
{
|
|
2436
|
+
type: "function",
|
|
2437
|
+
name: "balanceOf",
|
|
2438
|
+
stateMutability: "view",
|
|
2439
|
+
inputs: [{ name: "account", type: "address" }],
|
|
2440
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
2441
|
+
}
|
|
2442
|
+
];
|
|
2443
|
+
function buildPermitTransferFromTypedData(input) {
|
|
2444
|
+
return {
|
|
2445
|
+
domain: {
|
|
2446
|
+
name: "Permit2",
|
|
2447
|
+
chainId: input.chainId,
|
|
2448
|
+
verifyingContract: PERMIT2_ADDRESS
|
|
2449
|
+
},
|
|
2450
|
+
types: {
|
|
2451
|
+
PermitTransferFrom: [
|
|
2452
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
2453
|
+
{ name: "spender", type: "address" },
|
|
2454
|
+
{ name: "nonce", type: "uint256" },
|
|
2455
|
+
{ name: "deadline", type: "uint256" }
|
|
2456
|
+
],
|
|
2457
|
+
TokenPermissions: [
|
|
2458
|
+
{ name: "token", type: "address" },
|
|
2459
|
+
{ name: "amount", type: "uint256" }
|
|
2460
|
+
]
|
|
2461
|
+
},
|
|
2462
|
+
primaryType: "PermitTransferFrom",
|
|
2463
|
+
message: input.message
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2466
|
+
function randomPermit2Nonce() {
|
|
2467
|
+
const bytes = new Uint8Array(32);
|
|
2468
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
2469
|
+
return BigInt((0, import_viem4.bytesToHex)(bytes));
|
|
2470
|
+
}
|
|
2471
|
+
async function readPermit2Allowance(publicClient, token, owner) {
|
|
2472
|
+
return publicClient.readContract({
|
|
2473
|
+
address: token,
|
|
2474
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
2475
|
+
functionName: "allowance",
|
|
2476
|
+
args: [owner, PERMIT2_ADDRESS]
|
|
2477
|
+
});
|
|
2478
|
+
}
|
|
2479
|
+
async function readErc20Balance(publicClient, token, owner) {
|
|
2480
|
+
return publicClient.readContract({
|
|
2481
|
+
address: token,
|
|
2482
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
2483
|
+
functionName: "balanceOf",
|
|
2484
|
+
args: [owner]
|
|
2485
|
+
});
|
|
2486
|
+
}
|
|
3380
2487
|
|
|
3381
2488
|
// src/lib/chain-guard.ts
|
|
3382
|
-
init_errors();
|
|
3383
2489
|
var CHAIN_NAMES = {
|
|
3384
2490
|
1: "Ethereum",
|
|
3385
2491
|
8453: "Base",
|
|
@@ -3493,8 +2599,6 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
3493
2599
|
}
|
|
3494
2600
|
|
|
3495
2601
|
// src/lib/sponsored-weth-deposit.ts
|
|
3496
|
-
init_errors();
|
|
3497
|
-
init_permit2();
|
|
3498
2602
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
3499
2603
|
function makeSponsoredWethCallback(deps) {
|
|
3500
2604
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
@@ -3579,7 +2683,6 @@ function makeSponsoredWethCallback(deps) {
|
|
|
3579
2683
|
|
|
3580
2684
|
// src/lib/sponsored-calls-deposit.ts
|
|
3581
2685
|
var import_viem5 = require("viem");
|
|
3582
|
-
init_errors();
|
|
3583
2686
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
3584
2687
|
var DEFAULT_MAX_POLLS = 30;
|
|
3585
2688
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -3670,7 +2773,6 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
3670
2773
|
}
|
|
3671
2774
|
|
|
3672
2775
|
// src/client.ts
|
|
3673
|
-
init_permit2();
|
|
3674
2776
|
function encodeMultiAgentCursor(map) {
|
|
3675
2777
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
3676
2778
|
}
|
|
@@ -3697,11 +2799,10 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
3697
2799
|
1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
3698
2800
|
};
|
|
3699
2801
|
var VIEM_CHAIN2 = {
|
|
3700
|
-
8453:
|
|
3701
|
-
42161:
|
|
3702
|
-
1:
|
|
2802
|
+
8453: import_chains2.base,
|
|
2803
|
+
42161: import_chains2.arbitrum,
|
|
2804
|
+
1: import_chains2.mainnet
|
|
3703
2805
|
};
|
|
3704
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai"];
|
|
3705
2806
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
3706
2807
|
8453: "0x4200000000000000000000000000000000000006",
|
|
3707
2808
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -3730,11 +2831,21 @@ var OwneySDK = class {
|
|
|
3730
2831
|
zyfaiRpcUrls;
|
|
3731
2832
|
routingApiBaseUrl;
|
|
3732
2833
|
referralSource;
|
|
3733
|
-
surfliquidApiBaseUrl;
|
|
3734
2834
|
cachedSponsoredCallback = null;
|
|
3735
2835
|
cachedWethSponsoredCallback = null;
|
|
3736
2836
|
paymasterServiceUrl;
|
|
3737
2837
|
cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
|
|
2838
|
+
agentReads = new AgentReads();
|
|
2839
|
+
activationChecks = /* @__PURE__ */ new Map();
|
|
2840
|
+
readAgent(agent, method, fetch2, params = null) {
|
|
2841
|
+
const key2 = JSON.stringify([
|
|
2842
|
+
this.state?.walletAddress.toLowerCase() ?? null,
|
|
2843
|
+
this.state?.chainId ?? null,
|
|
2844
|
+
method,
|
|
2845
|
+
params
|
|
2846
|
+
]);
|
|
2847
|
+
return this.agentReads.run(agent.id, key2, fetch2);
|
|
2848
|
+
}
|
|
3738
2849
|
initializingAgentsPromise = null;
|
|
3739
2850
|
constructor(config) {
|
|
3740
2851
|
this.apiKey = config.apiKey;
|
|
@@ -3743,7 +2854,6 @@ var OwneySDK = class {
|
|
|
3743
2854
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
3744
2855
|
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
3745
2856
|
this.referralSource = config.referralSource;
|
|
3746
|
-
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
3747
2857
|
}
|
|
3748
2858
|
/**
|
|
3749
2859
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -3762,6 +2872,8 @@ var OwneySDK = class {
|
|
|
3762
2872
|
"No accounts found. Ensure the wallet is unlocked and connected."
|
|
3763
2873
|
);
|
|
3764
2874
|
}
|
|
2875
|
+
this.agentReads.clearInFlight();
|
|
2876
|
+
this.activationChecks.clear();
|
|
3765
2877
|
this.state = { provider, walletAddress, chainId: null };
|
|
3766
2878
|
this.cachedSponsoredCallback = null;
|
|
3767
2879
|
this.cachedWethSponsoredCallback = null;
|
|
@@ -3777,6 +2889,8 @@ var OwneySDK = class {
|
|
|
3777
2889
|
}
|
|
3778
2890
|
this.activeAgents.clear();
|
|
3779
2891
|
this.disabledAgents.clear();
|
|
2892
|
+
this.agentReads.clearInFlight();
|
|
2893
|
+
this.activationChecks.clear();
|
|
3780
2894
|
this.state = null;
|
|
3781
2895
|
this.cachedSponsoredCallback = null;
|
|
3782
2896
|
this.cachedWethSponsoredCallback = null;
|
|
@@ -3843,14 +2957,14 @@ var OwneySDK = class {
|
|
|
3843
2957
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
3844
2958
|
// PublicClient/WalletClient param types — structurally identical at
|
|
3845
2959
|
// runtime, but the two share a name TS treats as unrelated.
|
|
3846
|
-
getPublicClient: (cid) => (0,
|
|
2960
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
3847
2961
|
chain: VIEM_CHAIN2[cid],
|
|
3848
|
-
transport: (0,
|
|
2962
|
+
transport: (0, import_viem6.custom)(provider)
|
|
3849
2963
|
}),
|
|
3850
|
-
getWalletClient: (cid) => (0,
|
|
2964
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
3851
2965
|
account: owner,
|
|
3852
2966
|
chain: VIEM_CHAIN2[cid],
|
|
3853
|
-
transport: (0,
|
|
2967
|
+
transport: (0, import_viem6.custom)(provider)
|
|
3854
2968
|
})
|
|
3855
2969
|
});
|
|
3856
2970
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -3896,14 +3010,14 @@ var OwneySDK = class {
|
|
|
3896
3010
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
3897
3011
|
// PublicClient/WalletClient param types — structurally identical at
|
|
3898
3012
|
// runtime, but the two share a name TS treats as unrelated.
|
|
3899
|
-
getPublicClient: (cid) => (0,
|
|
3013
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
3900
3014
|
chain: VIEM_CHAIN2[cid],
|
|
3901
|
-
transport: (0,
|
|
3015
|
+
transport: (0, import_viem6.custom)(provider)
|
|
3902
3016
|
}),
|
|
3903
|
-
getWalletClient: (cid) => (0,
|
|
3017
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
3904
3018
|
account: owner,
|
|
3905
3019
|
chain: VIEM_CHAIN2[cid],
|
|
3906
|
-
transport: (0,
|
|
3020
|
+
transport: (0, import_viem6.custom)(provider)
|
|
3907
3021
|
})
|
|
3908
3022
|
});
|
|
3909
3023
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -3979,8 +3093,8 @@ var OwneySDK = class {
|
|
|
3979
3093
|
this.routingApiBaseUrl
|
|
3980
3094
|
);
|
|
3981
3095
|
this.disabledAgents.clear();
|
|
3982
|
-
for (const { key: key2, agent_type,
|
|
3983
|
-
const agent =
|
|
3096
|
+
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
3097
|
+
const agent = this.createAgent(agent_type, key2);
|
|
3984
3098
|
if (!agent) continue;
|
|
3985
3099
|
this.agents.set(agent_type, agent);
|
|
3986
3100
|
if (is_enabled === false) {
|
|
@@ -4001,25 +3115,42 @@ var OwneySDK = class {
|
|
|
4001
3115
|
this.initializingAgentsPromise = null;
|
|
4002
3116
|
}
|
|
4003
3117
|
}
|
|
4004
|
-
|
|
3118
|
+
createAgent(agentId, key2) {
|
|
4005
3119
|
if (agentId === "zyfai") {
|
|
4006
3120
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
4007
3121
|
}
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
3122
|
+
return null;
|
|
3123
|
+
}
|
|
3124
|
+
/**
|
|
3125
|
+
* Discover the agents actually returned by routing for this organization.
|
|
3126
|
+
* Consumers should use this instead of hardcoding a global agent roster.
|
|
3127
|
+
*/
|
|
3128
|
+
async getAvailableAgents(options = {}) {
|
|
3129
|
+
await this.ensureAgentsInitialized();
|
|
3130
|
+
const { chainId, asset, includeDisabled = false } = options;
|
|
3131
|
+
const available = [];
|
|
3132
|
+
for (const [id, agent] of this.agents) {
|
|
3133
|
+
const isEnabled = !this.isAgentDisabled(id);
|
|
3134
|
+
if (!includeDisabled && !isEnabled) continue;
|
|
3135
|
+
if (chainId !== void 0 && !agent.supportedChainIds.includes(chainId)) {
|
|
3136
|
+
continue;
|
|
3137
|
+
}
|
|
3138
|
+
if (asset !== void 0) {
|
|
3139
|
+
const supportsAsset = agent.supportedAssets.some(
|
|
3140
|
+
(entry) => (chainId === void 0 || entry.chainId === chainId) && entry.assets.some((candidate) => candidate.symbol === asset)
|
|
3141
|
+
);
|
|
3142
|
+
if (!supportsAsset) {
|
|
3143
|
+
continue;
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
available.push({
|
|
3147
|
+
id,
|
|
3148
|
+
isEnabled,
|
|
3149
|
+
supportedChainIds: agent.supportedChainIds,
|
|
3150
|
+
supportedAssets: agent.supportedAssets
|
|
4020
3151
|
});
|
|
4021
3152
|
}
|
|
4022
|
-
return
|
|
3153
|
+
return available;
|
|
4023
3154
|
}
|
|
4024
3155
|
// --- Account lifecycle ---
|
|
4025
3156
|
/**
|
|
@@ -4068,9 +3199,7 @@ var OwneySDK = class {
|
|
|
4068
3199
|
this.activeAgents.add(id);
|
|
4069
3200
|
}
|
|
4070
3201
|
state.chainId = chainId;
|
|
4071
|
-
this.activateAgentsInTurn(agents, state, chainId)
|
|
4072
|
-
console.error("activateAgent background init failed:", error);
|
|
4073
|
-
});
|
|
3202
|
+
await this.activateAgentsInTurn(agents, state, chainId);
|
|
4074
3203
|
return;
|
|
4075
3204
|
}
|
|
4076
3205
|
const compatible = [...this.agents.values()].filter(
|
|
@@ -4091,11 +3220,7 @@ var OwneySDK = class {
|
|
|
4091
3220
|
const enabledCompatible = compatible.filter(
|
|
4092
3221
|
(agent) => !this.isAgentDisabled(agent.id)
|
|
4093
3222
|
);
|
|
4094
|
-
this.activateAgentsInTurn(enabledCompatible, state, chainId)
|
|
4095
|
-
(error) => {
|
|
4096
|
-
console.error("activateAgent background init failed:", error);
|
|
4097
|
-
}
|
|
4098
|
-
);
|
|
3223
|
+
await this.activateAgentsInTurn(enabledCompatible, state, chainId);
|
|
4099
3224
|
}
|
|
4100
3225
|
/**
|
|
4101
3226
|
* Activate agents ONE AT A TIME, each followed by its org policy.
|
|
@@ -4132,7 +3257,7 @@ var OwneySDK = class {
|
|
|
4132
3257
|
if (firstError !== null) throw firstError;
|
|
4133
3258
|
}
|
|
4134
3259
|
/**
|
|
4135
|
-
* Deposit
|
|
3260
|
+
* Deposit into a specific agent, or distribute across all eligible agents.
|
|
4136
3261
|
* Validates that the asset is supported and amount meets minimums for the target agent(s).
|
|
4137
3262
|
* @param options - Deposit parameters
|
|
4138
3263
|
* @param options.amount - Amount to deposit in smallest unit (e.g. "100000000" for 100 USDC)
|
|
@@ -4140,7 +3265,8 @@ var OwneySDK = class {
|
|
|
4140
3265
|
* @param options.depositCallback - Callback that performs the token transfer and returns a tx hash.
|
|
4141
3266
|
* When agentId is omitted, this callback is invoked once per eligible agent with that agent's
|
|
4142
3267
|
* split amount and smart wallet address — expect multiple wallet prompts.
|
|
4143
|
-
* @param options.agentId - Optional
|
|
3268
|
+
* @param options.agentId - Optional explicit target. Otherwise split equally,
|
|
3269
|
+
* or fund remaining agents when a recovery deposit cannot meet every minimum.
|
|
4144
3270
|
* @returns {OwneyDepositResult} for a single agent, or {OwneyMultiDepositResult} with per-agent results
|
|
4145
3271
|
*/
|
|
4146
3272
|
async deposit(options) {
|
|
@@ -4178,7 +3304,7 @@ var OwneySDK = class {
|
|
|
4178
3304
|
});
|
|
4179
3305
|
const exemptFlags = await Promise.all(
|
|
4180
3306
|
eligibleAgents.map(
|
|
4181
|
-
(a) => this.hasExistingBalance(a, state, chainId, asset)
|
|
3307
|
+
(a) => this.hasExistingBalance(a, state, chainId, asset, true)
|
|
4182
3308
|
)
|
|
4183
3309
|
);
|
|
4184
3310
|
const exempt = new Set(
|
|
@@ -4192,15 +3318,42 @@ var OwneySDK = class {
|
|
|
4192
3318
|
exempt
|
|
4193
3319
|
);
|
|
4194
3320
|
if (agentAmounts.length === 0) {
|
|
3321
|
+
const agentsRequiringActivation = eligibleAgents.filter(
|
|
3322
|
+
(agent) => !exempt.has(agent.id)
|
|
3323
|
+
);
|
|
3324
|
+
const perAgentMinimum = agentsRequiringActivation.reduce(
|
|
3325
|
+
(highest, agent) => {
|
|
3326
|
+
const minimum = this.getMinDepositAmount(agent, chainId, asset);
|
|
3327
|
+
return minimum > highest ? minimum : highest;
|
|
3328
|
+
},
|
|
3329
|
+
0n
|
|
3330
|
+
);
|
|
3331
|
+
const minimumRequired = agentsRequiringActivation.length > 0 ? (perAgentMinimum > 0n ? perAgentMinimum : 1n) * BigInt(agentsRequiringActivation.length) : BigInt(eligibleAgents.length);
|
|
4195
3332
|
throw new OwneyError(
|
|
4196
3333
|
"DEPOSIT_AMOUNT_BELOW_MINIMUM",
|
|
4197
|
-
`Amount "${amount}" cannot
|
|
4198
|
-
{
|
|
3334
|
+
`Amount "${amount}" cannot activate every eligible agent. The combined minimum is "${minimumRequired.toString()}" for ${asset}.`,
|
|
3335
|
+
{
|
|
3336
|
+
amount,
|
|
3337
|
+
asset,
|
|
3338
|
+
chainId,
|
|
3339
|
+
minDepositAmount: minimumRequired.toString(),
|
|
3340
|
+
perAgentDepositAmount: perAgentMinimum.toString(),
|
|
3341
|
+
agentMinimums: agentsRequiringActivation.map((agent) => ({
|
|
3342
|
+
agentId: agent.id,
|
|
3343
|
+
minDepositAmount: this.getMinDepositAmount(
|
|
3344
|
+
agent,
|
|
3345
|
+
chainId,
|
|
3346
|
+
asset
|
|
3347
|
+
).toString()
|
|
3348
|
+
}))
|
|
3349
|
+
}
|
|
4199
3350
|
);
|
|
4200
3351
|
}
|
|
4201
3352
|
const agentResults = {};
|
|
4202
|
-
const
|
|
4203
|
-
|
|
3353
|
+
for (const [
|
|
3354
|
+
index,
|
|
3355
|
+
{ agent, amount: agentAmount }
|
|
3356
|
+
] of agentAmounts.entries()) {
|
|
4204
3357
|
try {
|
|
4205
3358
|
agentResults[agent.id] = await this.depositWithFallback(
|
|
4206
3359
|
agent,
|
|
@@ -4212,17 +3365,22 @@ var OwneySDK = class {
|
|
|
4212
3365
|
depositCallback
|
|
4213
3366
|
);
|
|
4214
3367
|
} catch (error) {
|
|
4215
|
-
|
|
3368
|
+
if (Object.keys(agentResults).length === 0) throw error;
|
|
3369
|
+
throw new OwneyError(
|
|
3370
|
+
"DEPOSIT_PARTIAL_FAILURE",
|
|
3371
|
+
"Some deposits completed before another agent failed. Check activity and balances before depositing again; the failed transfer may still settle.",
|
|
3372
|
+
{
|
|
3373
|
+
agentResults,
|
|
3374
|
+
failedAgentId: agent.id,
|
|
3375
|
+
failedAmount: agentAmount,
|
|
3376
|
+
unattemptedAgentIds: agentAmounts.slice(index + 1).map(({ agent: agent2 }) => agent2.id),
|
|
3377
|
+
cause: error
|
|
3378
|
+
},
|
|
3379
|
+
agent.id
|
|
3380
|
+
);
|
|
4216
3381
|
}
|
|
4217
3382
|
}
|
|
4218
|
-
|
|
4219
|
-
throw new OwneyError(
|
|
4220
|
-
"DEPOSIT_ALL_FAILED",
|
|
4221
|
-
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
4222
|
-
{ agentErrors }
|
|
4223
|
-
);
|
|
4224
|
-
}
|
|
4225
|
-
return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
|
|
3383
|
+
return { agentResults };
|
|
4226
3384
|
}
|
|
4227
3385
|
/**
|
|
4228
3386
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -4293,6 +3451,17 @@ var OwneySDK = class {
|
|
|
4293
3451
|
}
|
|
4294
3452
|
splitDepositAmount(totalAmount, agents, chainId, asset, exempt = /* @__PURE__ */ new Set()) {
|
|
4295
3453
|
if (agents.length === 0) return [];
|
|
3454
|
+
const agentsRequiringActivation = agents.filter(
|
|
3455
|
+
(agent) => !exempt.has(agent.id)
|
|
3456
|
+
);
|
|
3457
|
+
if (agentsRequiringActivation.length === agents.length) {
|
|
3458
|
+
const highestMinimum2 = agents.reduce((highest, agent) => {
|
|
3459
|
+
const minimum = this.getMinDepositAmount(agent, chainId, asset);
|
|
3460
|
+
return minimum > highest ? minimum : highest;
|
|
3461
|
+
}, 0n);
|
|
3462
|
+
const minimumRequired2 = (highestMinimum2 > 0n ? highestMinimum2 : 1n) * BigInt(agents.length);
|
|
3463
|
+
if (totalAmount < minimumRequired2) return [];
|
|
3464
|
+
}
|
|
4296
3465
|
const perAgent = totalAmount / BigInt(agents.length);
|
|
4297
3466
|
const remainder = totalAmount % BigInt(agents.length);
|
|
4298
3467
|
const splits = agents.map((agent, i) => ({
|
|
@@ -4300,18 +3469,26 @@ var OwneySDK = class {
|
|
|
4300
3469
|
amount: i === agents.length - 1 ? perAgent + remainder : perAgent
|
|
4301
3470
|
}));
|
|
4302
3471
|
const valid = splits.filter(
|
|
4303
|
-
(s) => exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset)
|
|
3472
|
+
(s) => s.amount > 0n && (exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset))
|
|
4304
3473
|
);
|
|
4305
3474
|
if (valid.length === agents.length) {
|
|
4306
3475
|
return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
|
|
4307
3476
|
}
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
);
|
|
3477
|
+
const targets = agentsRequiringActivation.length > 0 ? agentsRequiringActivation : agents;
|
|
3478
|
+
const highestMinimum = targets.reduce((highest, agent) => {
|
|
3479
|
+
const minimum = this.getMinDepositAmount(agent, chainId, asset);
|
|
3480
|
+
return minimum > highest ? minimum : highest;
|
|
3481
|
+
}, 0n);
|
|
3482
|
+
const minimumRequired = (highestMinimum > 0n ? highestMinimum : 1n) * BigInt(targets.length);
|
|
3483
|
+
if (totalAmount < minimumRequired) return [];
|
|
3484
|
+
const targetShare = totalAmount / BigInt(targets.length);
|
|
3485
|
+
const targetRemainder = totalAmount % BigInt(targets.length);
|
|
3486
|
+
return targets.map((agent, index) => ({
|
|
3487
|
+
agent,
|
|
3488
|
+
amount: String(
|
|
3489
|
+
targetShare + (index === targets.length - 1 ? targetRemainder : 0n)
|
|
3490
|
+
)
|
|
3491
|
+
}));
|
|
4315
3492
|
}
|
|
4316
3493
|
async validateMinDepositAmount(agent, state, chainId, asset, amount) {
|
|
4317
3494
|
const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
|
|
@@ -4336,14 +3513,29 @@ var OwneySDK = class {
|
|
|
4336
3513
|
* per-agent minimum. Fails closed: any error reading balances returns
|
|
4337
3514
|
* false, so the minimum is enforced as today.
|
|
4338
3515
|
*/
|
|
4339
|
-
async hasExistingBalance(agent, state, chainId, asset) {
|
|
3516
|
+
async hasExistingBalance(agent, state, chainId, asset, requireReliableRead = false) {
|
|
4340
3517
|
try {
|
|
4341
3518
|
const balance = await agent.getBalances(state, chainId);
|
|
3519
|
+
const target = asset.toLowerCase();
|
|
4342
3520
|
const token = balance.tokens.find(
|
|
4343
|
-
(t) => t.chainId === chainId &&
|
|
3521
|
+
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
4344
3522
|
);
|
|
4345
|
-
|
|
4346
|
-
|
|
3523
|
+
const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
|
|
3524
|
+
const position = (balance.positions ?? []).find((p) => {
|
|
3525
|
+
const positionChain = p.chain.trim().toUpperCase();
|
|
3526
|
+
const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
|
|
3527
|
+
return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
|
|
3528
|
+
});
|
|
3529
|
+
return !!token && Number(token.amount) > 0 || !!position;
|
|
3530
|
+
} catch (error) {
|
|
3531
|
+
if (requireReliableRead) {
|
|
3532
|
+
throw new OwneyError(
|
|
3533
|
+
"DEPOSIT_BALANCE_UNAVAILABLE",
|
|
3534
|
+
"Could not verify every agent balance. No deposit was submitted. Try again once balances are available.",
|
|
3535
|
+
{ agentId: agent.id, chainId, asset, cause: error },
|
|
3536
|
+
agent.id
|
|
3537
|
+
);
|
|
3538
|
+
}
|
|
4347
3539
|
return false;
|
|
4348
3540
|
}
|
|
4349
3541
|
}
|
|
@@ -4379,34 +3571,6 @@ var OwneySDK = class {
|
|
|
4379
3571
|
}
|
|
4380
3572
|
return eligible;
|
|
4381
3573
|
}
|
|
4382
|
-
/**
|
|
4383
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
4384
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
4385
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
4386
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
4387
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
4388
|
-
*
|
|
4389
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
4390
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
4391
|
-
*/
|
|
4392
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
4393
|
-
try {
|
|
4394
|
-
await this.ensureAgentsInitialized();
|
|
4395
|
-
} catch (error) {
|
|
4396
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
4397
|
-
return [];
|
|
4398
|
-
}
|
|
4399
|
-
throw error;
|
|
4400
|
-
}
|
|
4401
|
-
return [...this.agents.values()].filter((agent) => {
|
|
4402
|
-
const chainAssets = agent.supportedAssets.find(
|
|
4403
|
-
(sa) => sa.chainId === chainId
|
|
4404
|
-
);
|
|
4405
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
4406
|
-
}).map((agent) => agent.id).sort(
|
|
4407
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
4408
|
-
);
|
|
4409
|
-
}
|
|
4410
3574
|
// --- Fund operations ---
|
|
4411
3575
|
/**
|
|
4412
3576
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -4443,17 +3607,9 @@ var OwneySDK = class {
|
|
|
4443
3607
|
}
|
|
4444
3608
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
4445
3609
|
if (!amount) {
|
|
4446
|
-
const aggregated2 = await this.getBalances();
|
|
4447
|
-
const funded = projectAgentBalancesForAsset(
|
|
4448
|
-
eligibleAgents,
|
|
4449
|
-
aggregated2.agentBalances,
|
|
4450
|
-
chainId,
|
|
4451
|
-
asset,
|
|
4452
|
-
assetInfo.decimals
|
|
4453
|
-
).filter((b) => b.balance > 0n);
|
|
4454
3610
|
const results2 = {};
|
|
4455
3611
|
const agentErrors2 = {};
|
|
4456
|
-
for (const
|
|
3612
|
+
for (const agent of eligibleAgents) {
|
|
4457
3613
|
try {
|
|
4458
3614
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
4459
3615
|
} catch (err) {
|
|
@@ -4475,10 +3631,9 @@ var OwneySDK = class {
|
|
|
4475
3631
|
{ asset, agentErrors: agentErrors2 }
|
|
4476
3632
|
);
|
|
4477
3633
|
}
|
|
4478
|
-
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
4479
3634
|
return {
|
|
4480
3635
|
agentResult: results2,
|
|
4481
|
-
totalWithdrawn:
|
|
3636
|
+
totalWithdrawn: sumWithdrawnAmount(results2).toString()
|
|
4482
3637
|
};
|
|
4483
3638
|
}
|
|
4484
3639
|
const requested = BigInt(amount);
|
|
@@ -4583,7 +3738,8 @@ var OwneySDK = class {
|
|
|
4583
3738
|
const state = this.requireState();
|
|
4584
3739
|
const chainId = this.requireChainId();
|
|
4585
3740
|
if (agentId) {
|
|
4586
|
-
const
|
|
3741
|
+
const agent = this.getAgent(agentId);
|
|
3742
|
+
const result = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
4587
3743
|
return result;
|
|
4588
3744
|
}
|
|
4589
3745
|
let totalBalance = 0;
|
|
@@ -4591,12 +3747,13 @@ var OwneySDK = class {
|
|
|
4591
3747
|
const entries = [...this.getActiveAgents().entries()];
|
|
4592
3748
|
const balanceResults = await Promise.allSettled(
|
|
4593
3749
|
entries.map(async ([id, agent]) => {
|
|
4594
|
-
const b = await agent.getBalances(state, chainId);
|
|
3750
|
+
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
4595
3751
|
return [id, b];
|
|
4596
3752
|
})
|
|
4597
3753
|
);
|
|
4598
3754
|
let successCount = 0;
|
|
4599
3755
|
const agentErrors = {};
|
|
3756
|
+
const agentFailures = [];
|
|
4600
3757
|
for (let i = 0; i < balanceResults.length; i++) {
|
|
4601
3758
|
const settledResult = balanceResults[i];
|
|
4602
3759
|
const [agentId2] = entries[i];
|
|
@@ -4608,13 +3765,14 @@ var OwneySDK = class {
|
|
|
4608
3765
|
continue;
|
|
4609
3766
|
}
|
|
4610
3767
|
const reason = settledResult.reason;
|
|
3768
|
+
agentFailures.push(reason);
|
|
4611
3769
|
agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
|
|
4612
3770
|
}
|
|
4613
3771
|
if (successCount === 0) {
|
|
4614
3772
|
throw new OwneyError(
|
|
4615
3773
|
"BALANCE_ALL_FAILED",
|
|
4616
3774
|
"Failed to fetch balances for all active agents.",
|
|
4617
|
-
{ agentErrors }
|
|
3775
|
+
{ agentErrors, failures: agentFailures }
|
|
4618
3776
|
);
|
|
4619
3777
|
}
|
|
4620
3778
|
return {
|
|
@@ -4632,14 +3790,15 @@ var OwneySDK = class {
|
|
|
4632
3790
|
const state = this.requireState();
|
|
4633
3791
|
const chainId = this.requireChainId();
|
|
4634
3792
|
if (agentId) {
|
|
4635
|
-
|
|
3793
|
+
const agent = this.getAgent(agentId);
|
|
3794
|
+
return this.readAgent(agent, "earnings", () => agent.getEarnings(state, chainId));
|
|
4636
3795
|
}
|
|
4637
3796
|
let totalEarnings = 0;
|
|
4638
3797
|
const results = {};
|
|
4639
3798
|
const entries = [...this.getActiveAgents().entries()];
|
|
4640
3799
|
const earningsResults = await Promise.all(
|
|
4641
3800
|
entries.map(async ([id, agent]) => {
|
|
4642
|
-
const e = await agent.getEarnings(state, chainId);
|
|
3801
|
+
const e = await this.readAgent(agent, "earnings", () => agent.getEarnings(state, chainId));
|
|
4643
3802
|
return [id, e];
|
|
4644
3803
|
})
|
|
4645
3804
|
);
|
|
@@ -4659,7 +3818,11 @@ var OwneySDK = class {
|
|
|
4659
3818
|
async refreshEarnings(agentId) {
|
|
4660
3819
|
const state = this.requireState();
|
|
4661
3820
|
const chainId = this.requireChainId();
|
|
4662
|
-
const refreshAgent = (agent) =>
|
|
3821
|
+
const refreshAgent = (agent) => this.readAgent(
|
|
3822
|
+
agent,
|
|
3823
|
+
agent.refreshEarnings ? "refreshEarnings" : "earnings",
|
|
3824
|
+
() => agent.refreshEarnings?.(state, chainId) ?? agent.getEarnings(state, chainId)
|
|
3825
|
+
);
|
|
4663
3826
|
if (agentId) return refreshAgent(this.getAgent(agentId));
|
|
4664
3827
|
let totalEarnings = 0;
|
|
4665
3828
|
const agentEarnings = {};
|
|
@@ -4690,11 +3853,12 @@ var OwneySDK = class {
|
|
|
4690
3853
|
const state = this.requireState();
|
|
4691
3854
|
const chainId = this.requireChainId();
|
|
4692
3855
|
if (agentId) {
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
tokenSymbol
|
|
3856
|
+
const agent = this.getAgent(agentId);
|
|
3857
|
+
return this.readAgent(
|
|
3858
|
+
agent,
|
|
3859
|
+
"accountApy",
|
|
3860
|
+
() => agent.getAccountApy(state, chainId, days, tokenSymbol),
|
|
3861
|
+
{ days, tokenSymbol }
|
|
4698
3862
|
);
|
|
4699
3863
|
}
|
|
4700
3864
|
const activeAgents = this.getActiveAgents();
|
|
@@ -4702,18 +3866,18 @@ var OwneySDK = class {
|
|
|
4702
3866
|
const [apyResults, balanceResults] = await Promise.all([
|
|
4703
3867
|
Promise.all(
|
|
4704
3868
|
entries.map(async ([id, agent]) => {
|
|
4705
|
-
const apy = await
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
days,
|
|
4709
|
-
tokenSymbol
|
|
3869
|
+
const apy = await this.readAgent(
|
|
3870
|
+
agent,
|
|
3871
|
+
"accountApy",
|
|
3872
|
+
() => agent.getAccountApy(state, chainId, days, tokenSymbol),
|
|
3873
|
+
{ days, tokenSymbol }
|
|
4710
3874
|
);
|
|
4711
3875
|
return [id, apy];
|
|
4712
3876
|
})
|
|
4713
3877
|
),
|
|
4714
3878
|
Promise.all(
|
|
4715
3879
|
entries.map(async ([id, agent]) => {
|
|
4716
|
-
const b = await agent.getBalances(state, chainId);
|
|
3880
|
+
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
4717
3881
|
return [id, Number(b.totalBalance)];
|
|
4718
3882
|
})
|
|
4719
3883
|
)
|
|
@@ -4770,7 +3934,8 @@ var OwneySDK = class {
|
|
|
4770
3934
|
const chainId = this.requireChainId();
|
|
4771
3935
|
const { agentId, filters } = options ?? {};
|
|
4772
3936
|
if (agentId) {
|
|
4773
|
-
|
|
3937
|
+
const agent = this.getAgent(agentId);
|
|
3938
|
+
return this.readAgent(agent, "history", () => agent.getHistory(state, chainId, filters), filters);
|
|
4774
3939
|
}
|
|
4775
3940
|
const activeAgents = [...this.getActiveAgents().values()];
|
|
4776
3941
|
const cursorMap = filters?.cursor ? decodeMultiAgentCursor(filters.cursor) : {};
|
|
@@ -4780,10 +3945,13 @@ var OwneySDK = class {
|
|
|
4780
3945
|
if (filters?.cursor && agentCursor === void 0) {
|
|
4781
3946
|
return { agentId: agent.id, page: null };
|
|
4782
3947
|
}
|
|
4783
|
-
const
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
3948
|
+
const agentFilters = { ...filters, cursor: agentCursor };
|
|
3949
|
+
const page = await this.readAgent(
|
|
3950
|
+
agent,
|
|
3951
|
+
"history",
|
|
3952
|
+
() => agent.getHistory(state, chainId, agentFilters),
|
|
3953
|
+
agentFilters
|
|
3954
|
+
);
|
|
4787
3955
|
return { agentId: agent.id, page };
|
|
4788
3956
|
})
|
|
4789
3957
|
);
|
|
@@ -4823,13 +3991,14 @@ var OwneySDK = class {
|
|
|
4823
3991
|
const state = this.requireState();
|
|
4824
3992
|
const chainId = this.requireChainId();
|
|
4825
3993
|
if (agentId) {
|
|
4826
|
-
|
|
3994
|
+
const agent = this.getAgent(agentId);
|
|
3995
|
+
return this.readAgent(agent, "profile", () => agent.getUserProfile(state, chainId));
|
|
4827
3996
|
}
|
|
4828
3997
|
const results = {};
|
|
4829
3998
|
const entries = [...this.getActiveAgents().entries()];
|
|
4830
3999
|
const profileResults = await Promise.all(
|
|
4831
4000
|
entries.map(async ([id, agent]) => {
|
|
4832
|
-
const p = await agent.getUserProfile(state, chainId);
|
|
4001
|
+
const p = await this.readAgent(agent, "profile", () => agent.getUserProfile(state, chainId));
|
|
4833
4002
|
return [id, p];
|
|
4834
4003
|
})
|
|
4835
4004
|
);
|
|
@@ -4852,7 +4021,20 @@ var OwneySDK = class {
|
|
|
4852
4021
|
const chainId = this.requireChainId();
|
|
4853
4022
|
const agent = this.getAgent(agentId);
|
|
4854
4023
|
if (typeof agent.ensureAutoSelectProtocols !== "function") return false;
|
|
4855
|
-
|
|
4024
|
+
const key2 = JSON.stringify([
|
|
4025
|
+
state.walletAddress.toLowerCase(),
|
|
4026
|
+
agentId,
|
|
4027
|
+
chainId,
|
|
4028
|
+
asset
|
|
4029
|
+
]);
|
|
4030
|
+
const existing = this.activationChecks.get(key2);
|
|
4031
|
+
if (existing) return existing;
|
|
4032
|
+
const pending = Promise.resolve().then(() => agent.ensureAutoSelectProtocols(state, chainId, asset)).finally(() => {
|
|
4033
|
+
if (this.activationChecks.get(key2) === pending)
|
|
4034
|
+
this.activationChecks.delete(key2);
|
|
4035
|
+
});
|
|
4036
|
+
this.activationChecks.set(key2, pending);
|
|
4037
|
+
return pending;
|
|
4856
4038
|
}
|
|
4857
4039
|
/**
|
|
4858
4040
|
* One-time, user-paid approval of Permit2 on the sponsored WETH token for
|
|
@@ -4875,10 +4057,10 @@ var OwneySDK = class {
|
|
|
4875
4057
|
);
|
|
4876
4058
|
}
|
|
4877
4059
|
const provider = this.requireConnectedProvider();
|
|
4878
|
-
const wallet = (0,
|
|
4060
|
+
const wallet = (0, import_viem6.createWalletClient)({
|
|
4879
4061
|
account: state.walletAddress,
|
|
4880
4062
|
chain: VIEM_CHAIN2[chainId],
|
|
4881
|
-
transport: (0,
|
|
4063
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4882
4064
|
});
|
|
4883
4065
|
const hash = await wallet.writeContract({
|
|
4884
4066
|
address: token,
|
|
@@ -4888,9 +4070,9 @@ var OwneySDK = class {
|
|
|
4888
4070
|
account: state.walletAddress,
|
|
4889
4071
|
chain: VIEM_CHAIN2[chainId]
|
|
4890
4072
|
});
|
|
4891
|
-
const publicClient = (0,
|
|
4073
|
+
const publicClient = (0, import_viem6.createPublicClient)({
|
|
4892
4074
|
chain: VIEM_CHAIN2[chainId],
|
|
4893
|
-
transport: (0,
|
|
4075
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4894
4076
|
});
|
|
4895
4077
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
4896
4078
|
hash,
|
|
@@ -4923,13 +4105,14 @@ var OwneySDK = class {
|
|
|
4923
4105
|
await this.ensureAgentsInitialized();
|
|
4924
4106
|
const agentOptions = { tokenSymbol, chainId };
|
|
4925
4107
|
if (agentId) {
|
|
4926
|
-
|
|
4108
|
+
const agent = this.getAgent(agentId);
|
|
4109
|
+
return this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
|
|
4927
4110
|
}
|
|
4928
4111
|
const results = {};
|
|
4929
4112
|
const agentEntries = [...this.agents.entries()];
|
|
4930
4113
|
const apyResults = await Promise.all(
|
|
4931
4114
|
agentEntries.map(async ([id, agent]) => {
|
|
4932
|
-
const apy = await agent.getAgentApy(days, agentOptions);
|
|
4115
|
+
const apy = await this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
|
|
4933
4116
|
return [id, apy];
|
|
4934
4117
|
})
|
|
4935
4118
|
);
|
|
@@ -4956,7 +4139,7 @@ var OwneySDK = class {
|
|
|
4956
4139
|
const entries = [...activeAgents.entries()];
|
|
4957
4140
|
const balanceResults = await Promise.allSettled(
|
|
4958
4141
|
entries.map(async ([id, agent]) => {
|
|
4959
|
-
const b = await agent.getBalances(state, chainId);
|
|
4142
|
+
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
4960
4143
|
return [id, b.positions ?? []];
|
|
4961
4144
|
})
|
|
4962
4145
|
);
|
|
@@ -4964,6 +4147,7 @@ var OwneySDK = class {
|
|
|
4964
4147
|
const allPositions = [];
|
|
4965
4148
|
let successCount = 0;
|
|
4966
4149
|
const agentErrors = {};
|
|
4150
|
+
const agentFailures = [];
|
|
4967
4151
|
for (let i = 0; i < balanceResults.length; i++) {
|
|
4968
4152
|
const settled = balanceResults[i];
|
|
4969
4153
|
const [aid] = entries[i];
|
|
@@ -4978,6 +4162,7 @@ var OwneySDK = class {
|
|
|
4978
4162
|
successCount += 1;
|
|
4979
4163
|
} else {
|
|
4980
4164
|
const reason = settled.reason;
|
|
4165
|
+
agentFailures.push(reason);
|
|
4981
4166
|
agentErrors[aid] = reason instanceof Error ? reason.message : String(reason);
|
|
4982
4167
|
console.error(`getAllocationApy agent "${aid}" failed:`, reason);
|
|
4983
4168
|
}
|
|
@@ -4986,7 +4171,7 @@ var OwneySDK = class {
|
|
|
4986
4171
|
throw new OwneyError(
|
|
4987
4172
|
"ALLOCATION_ALL_FAILED",
|
|
4988
4173
|
"Failed to fetch allocation APY: all agents failed.",
|
|
4989
|
-
{ agentErrors }
|
|
4174
|
+
{ agentErrors, failures: agentFailures }
|
|
4990
4175
|
);
|
|
4991
4176
|
}
|
|
4992
4177
|
const overall = computeAllocationApy(allPositions);
|
|
@@ -4998,12 +4183,8 @@ var OwneySDK = class {
|
|
|
4998
4183
|
}
|
|
4999
4184
|
};
|
|
5000
4185
|
|
|
5001
|
-
// src/index.ts
|
|
5002
|
-
init_errors();
|
|
5003
|
-
init_debug();
|
|
5004
|
-
|
|
5005
4186
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
5006
|
-
var
|
|
4187
|
+
var import_viem7 = require("viem");
|
|
5007
4188
|
var import_siwe = require("siwe");
|
|
5008
4189
|
var import_sdk2 = require("@zyfai/sdk");
|
|
5009
4190
|
|
|
@@ -5130,7 +4311,7 @@ function buildSIWXConfig(deps) {
|
|
|
5130
4311
|
issuedAt,
|
|
5131
4312
|
toString() {
|
|
5132
4313
|
return new import_siwe.SiweMessage({
|
|
5133
|
-
address: (0,
|
|
4314
|
+
address: (0, import_viem7.getAddress)(accountAddress),
|
|
5134
4315
|
chainId: numericChainId(chainId),
|
|
5135
4316
|
domain,
|
|
5136
4317
|
uri,
|
|
@@ -5207,9 +4388,9 @@ function buildSIWXConfig(deps) {
|
|
|
5207
4388
|
}
|
|
5208
4389
|
function createOwneySIWX(config) {
|
|
5209
4390
|
const zyfai = new import_sdk2.ZyfaiSDK({ apiKey: config.apiKey });
|
|
5210
|
-
const
|
|
4391
|
+
const http2 = zyfai.httpClient;
|
|
5211
4392
|
return buildSIWXConfig({
|
|
5212
|
-
post: (url, data) =>
|
|
4393
|
+
post: (url, data) => http2.post(url, data),
|
|
5213
4394
|
referralSource: config.referralSource
|
|
5214
4395
|
});
|
|
5215
4396
|
}
|