@owney/sdk 0.6.9-beta.7 → 0.7.0-beta.1

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 CHANGED
@@ -3,642 +3,20 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __esm = (fn, res, err) => function __init() {
7
- if (err) throw err[0];
8
- try {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
- } catch (e) {
11
- throw err = [e], e;
12
- }
13
- };
14
6
  var __export = (target, all) => {
15
7
  for (var name in all)
16
8
  __defProp(target, name, { get: all[name], enumerable: true });
17
9
  };
18
10
  var __copyProps = (to, from, except, desc) => {
19
11
  if (from && typeof from === "object" || typeof from === "function") {
20
- for (let key2 of __getOwnPropNames(from))
21
- if (!__hasOwnProp.call(to, key2) && key2 !== except)
22
- __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
15
  }
24
16
  return to;
25
17
  };
26
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
19
 
28
- // src/errors.ts
29
- var OwneyError, AgentNotFoundError, NotConnectedError, AgentChainIncompatibleError;
30
- var init_errors = __esm({
31
- "src/errors.ts"() {
32
- "use strict";
33
- OwneyError = class extends Error {
34
- code;
35
- details;
36
- agentId;
37
- constructor(code, message, details, agentId) {
38
- const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
39
- super(`${prefix} ${message}`);
40
- this.name = "OwneyError";
41
- this.code = code;
42
- this.details = details;
43
- this.agentId = agentId;
44
- }
45
- };
46
- AgentNotFoundError = class extends OwneyError {
47
- constructor(agentId, available) {
48
- super(
49
- "AGENT_NOT_FOUND",
50
- `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
51
- { agentId, available },
52
- agentId
53
- );
54
- this.name = "AgentNotFoundError";
55
- }
56
- };
57
- NotConnectedError = class extends OwneyError {
58
- constructor() {
59
- super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
60
- this.name = "NotConnectedError";
61
- }
62
- };
63
- AgentChainIncompatibleError = class extends OwneyError {
64
- incompatibleAgents;
65
- connectedChainId;
66
- constructor(incompatibleAgents, connectedChainId) {
67
- const details = incompatibleAgents.map(
68
- ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
69
- ).join("; ");
70
- super(
71
- "AGENT_CHAIN_INCOMPATIBLE",
72
- `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
73
- { incompatibleAgents, connectedChainId }
74
- );
75
- this.name = "AgentChainIncompatibleError";
76
- this.incompatibleAgents = incompatibleAgents;
77
- this.connectedChainId = connectedChainId;
78
- }
79
- };
80
- }
81
- });
82
-
83
- // src/lib/permit2.ts
84
- function buildPermitTransferFromTypedData(input) {
85
- return {
86
- domain: {
87
- name: "Permit2",
88
- chainId: input.chainId,
89
- verifyingContract: PERMIT2_ADDRESS
90
- },
91
- types: {
92
- PermitTransferFrom: [
93
- { name: "permitted", type: "TokenPermissions" },
94
- { name: "spender", type: "address" },
95
- { name: "nonce", type: "uint256" },
96
- { name: "deadline", type: "uint256" }
97
- ],
98
- TokenPermissions: [
99
- { name: "token", type: "address" },
100
- { name: "amount", type: "uint256" }
101
- ]
102
- },
103
- primaryType: "PermitTransferFrom",
104
- message: input.message
105
- };
106
- }
107
- function randomPermit2Nonce() {
108
- const bytes = new Uint8Array(32);
109
- globalThis.crypto.getRandomValues(bytes);
110
- return BigInt((0, import_viem4.bytesToHex)(bytes));
111
- }
112
- async function readPermit2Allowance(publicClient, token, owner) {
113
- return publicClient.readContract({
114
- address: token,
115
- abi: ERC20_ALLOWANCE_ABI,
116
- functionName: "allowance",
117
- args: [owner, PERMIT2_ADDRESS]
118
- });
119
- }
120
- async function readErc20Balance(publicClient, token, owner) {
121
- return publicClient.readContract({
122
- address: token,
123
- abi: ERC20_ALLOWANCE_ABI,
124
- functionName: "balanceOf",
125
- args: [owner]
126
- });
127
- }
128
- var import_viem4, PERMIT2_ADDRESS, MAX_UINT256, ERC20_ALLOWANCE_ABI;
129
- var init_permit2 = __esm({
130
- "src/lib/permit2.ts"() {
131
- "use strict";
132
- import_viem4 = require("viem");
133
- PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
134
- MAX_UINT256 = 2n ** 256n - 1n;
135
- ERC20_ALLOWANCE_ABI = [
136
- {
137
- type: "function",
138
- name: "allowance",
139
- stateMutability: "view",
140
- inputs: [
141
- { name: "owner", type: "address" },
142
- { name: "spender", type: "address" }
143
- ],
144
- outputs: [{ name: "", type: "uint256" }]
145
- },
146
- {
147
- type: "function",
148
- name: "approve",
149
- stateMutability: "nonpayable",
150
- inputs: [
151
- { name: "spender", type: "address" },
152
- { name: "amount", type: "uint256" }
153
- ],
154
- outputs: [{ name: "", type: "bool" }]
155
- },
156
- {
157
- type: "function",
158
- name: "balanceOf",
159
- stateMutability: "view",
160
- inputs: [{ name: "account", type: "address" }],
161
- outputs: [{ name: "", type: "uint256" }]
162
- }
163
- ];
164
- }
165
- });
166
-
167
- // src/agents/surfliquid/surfliquid.constants.ts
168
- 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;
169
- var init_surfliquid_constants = __esm({
170
- "src/agents/surfliquid/surfliquid.constants.ts"() {
171
- "use strict";
172
- SURFLIQUID_CHAIN_ID = 8453;
173
- SURFLIQUID_CHAIN_NAME = "BASE";
174
- SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
175
- SURFLIQUID_USDC_DECIMALS = 6;
176
- SURFLIQUID_MIN_DEPOSIT = "0";
177
- SURFLIQUID_APPROVAL_TARGET = 100000000000n;
178
- SURFLIQUID_SUPPORTED_ASSETS = [
179
- {
180
- chainId: SURFLIQUID_CHAIN_ID,
181
- chain: SURFLIQUID_CHAIN_NAME,
182
- assets: [{ symbol: "USDC", minDepositAmount: SURFLIQUID_MIN_DEPOSIT }]
183
- }
184
- ];
185
- SURFLIQUID_ACTION_MAP = {
186
- // INITIAL_DEPOSIT is the user's real first deposit, so surface it like any
187
- // other funding ("Top up"). The mini-app intentionally hides the "Deposit"
188
- // action (it marks Zyfai's smart-account-creation event), which would
189
- // otherwise drop a SurfLiquid user's only history row.
190
- INITIAL_DEPOSIT: "Top up",
191
- DEPOSIT: "Top up",
192
- USER_DEPOSIT: "Top up",
193
- WITHDRAWAL: "Withdraw",
194
- USER_WITHDRAWAL: "Withdraw",
195
- REBALANCE: "Rebalance",
196
- REBALANCE_COMPLETED: "Rebalance",
197
- CROSS_CHAIN_REBALANCE: "Rebalance",
198
- MERKL_CLAIM: "Earned"
199
- };
200
- }
201
- });
202
-
203
- // src/agents/surfliquid/surfliquid.mapper.ts
204
- function mapMessage(message) {
205
- const action = SURFLIQUID_ACTION_MAP[message.transactionType];
206
- if (!action) return null;
207
- return {
208
- agent: "surfliquid",
209
- action,
210
- date: message.timestamp,
211
- oldApy: message.apyBefore != null ? String(message.apyBefore) : null,
212
- newApy: message.apyAfter != null ? String(message.apyAfter) : null,
213
- transactions: [
214
- {
215
- txHashes: [message.txHash],
216
- chainId: message.chainId,
217
- tokenSymbol: message.token ?? void 0,
218
- amount: message.amount != null ? String(message.amount) : void 0
219
- }
220
- ],
221
- rebalanceLog: []
222
- };
223
- }
224
- function mapHistory(result, _chainId) {
225
- const data = result.messages.map(mapMessage).filter((entry) => entry !== null);
226
- const hasMore = result.page < result.pages;
227
- return {
228
- data,
229
- hasMore,
230
- nextCursor: hasMore ? String(result.page + 1) : void 0
231
- };
232
- }
233
- function mapBalances2(vault, chainId, morphoStats) {
234
- const assets = (vault.assets ?? []).filter(
235
- (asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId
236
- );
237
- const tokens = assets.map((asset) => ({
238
- chain: SURFLIQUID_CHAIN_NAME,
239
- chainId: SURFLIQUID_CHAIN_ID,
240
- asset: "USDC",
241
- amount: String(asset.currentValueUSD)
242
- }));
243
- const positions = assets.map((asset) => {
244
- const stats = morphoStats?.get(asset.morphoVaultAddress?.toLowerCase() ?? "");
245
- return {
246
- chain: SURFLIQUID_CHAIN_NAME,
247
- protocol: "Morpho",
248
- // The specific MetaMorpho vault (e.g. "Gauntlet USDC Frontier"), read from
249
- // Morpho — renders as "Morpho <vault>" alongside zyfai's vault detail.
250
- pool: stats?.name ?? void 0,
251
- asset: "USDC",
252
- amount: String(asset.currentValueUSD),
253
- apy: asset.currentAPY,
254
- // TVL + liquidity come straight from Morpho (SurfLiquid's API omits them).
255
- tvl: stats?.tvlUsd,
256
- liquidity: stats?.liquidityUsd
257
- };
258
- });
259
- const total = assets.reduce(
260
- (sum, asset) => sum + asset.currentValueUSD,
261
- 0
262
- );
263
- return {
264
- smartWallet: vault.userVaultAddress ?? void 0,
265
- totalBalance: String(total),
266
- totalBalanceAsset: "usdc",
267
- tokens,
268
- positions
269
- };
270
- }
271
- function mapAccountApy(vault, days) {
272
- const breakdown = vault.apyBreakdown;
273
- const windowed = breakdown ? breakdown[APY_WINDOW_KEY[days]] : void 0;
274
- const apy = windowed != null ? windowed : breakdown?.currentAPY ?? 0;
275
- return {
276
- walletAddress: vault.walletAddress ?? "",
277
- weightedApyAfterFee: apy,
278
- apyByChainAndAsset: { [SURFLIQUID_CHAIN_ID]: { USDC: apy } },
279
- // Parity with Sail: SurfLiquid's core-sdk exposes no daily net-APY series.
280
- history: []
281
- };
282
- }
283
- function mapEarnings2(vault, vaultAddress) {
284
- return {
285
- smartWallet: vaultAddress,
286
- lifetimeEarnings: vault.earned?.totalEarningsUSD ?? 0,
287
- tokens: []
288
- };
289
- }
290
- function mapUserProfile2(vault, address) {
291
- return {
292
- address,
293
- smartWallet: vault.userVaultAddress ?? "",
294
- chains: [SURFLIQUID_CHAIN_ID],
295
- // SurfLiquid uses cookie-based session auth — no session-key concept.
296
- hasActiveSessionKey: false,
297
- protocols: ["SurfLiquid"]
298
- };
299
- }
300
- var APY_WINDOW_KEY;
301
- var init_surfliquid_mapper = __esm({
302
- "src/agents/surfliquid/surfliquid.mapper.ts"() {
303
- "use strict";
304
- init_surfliquid_constants();
305
- APY_WINDOW_KEY = {
306
- "7D": "apy7d",
307
- "14D": "apy14d",
308
- "30D": "apy30d"
309
- };
310
- }
311
- });
312
-
313
- // src/agents/surfliquid/surfliquid.wallet-adapter.ts
314
- var import_core_sdk, OwneyWalletAdapter;
315
- var init_surfliquid_wallet_adapter = __esm({
316
- "src/agents/surfliquid/surfliquid.wallet-adapter.ts"() {
317
- "use strict";
318
- import_core_sdk = require("@surf_liquid/core-sdk");
319
- OwneyWalletAdapter = class extends import_core_sdk.BaseWalletAdapter {
320
- constructor(eip1193Provider) {
321
- super();
322
- this.eip1193Provider = eip1193Provider;
323
- }
324
- eip1193Provider;
325
- name = "owney";
326
- get installed() {
327
- return true;
328
- }
329
- resolveProvider() {
330
- return this.eip1193Provider;
331
- }
332
- };
333
- }
334
- });
335
-
336
- // src/agents/surfliquid/surfliquid.morpho.ts
337
- async function fetchMorphoVaultStats(vaultAddress, chainId) {
338
- try {
339
- const res = await fetch(MORPHO_API_URL, {
340
- method: "POST",
341
- headers: { "Content-Type": "application/json" },
342
- body: JSON.stringify({
343
- query: VAULT_STATS_QUERY,
344
- variables: { address: vaultAddress, chainId }
345
- })
346
- });
347
- if (!res.ok) return null;
348
- const json = await res.json();
349
- if (json.errors) return null;
350
- const vault = json.data?.vaultByAddress;
351
- const tvlUsd = vault?.state?.totalAssetsUsd;
352
- const liquidityUsd = vault?.liquidity?.usd;
353
- if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
354
- return null;
355
- }
356
- const name = typeof vault?.name === "string" ? vault.name : null;
357
- return { name, tvlUsd, liquidityUsd };
358
- } catch (error) {
359
- console.warn("surfliquid: Morpho vault stats fetch failed", {
360
- vaultAddress,
361
- chainId,
362
- error
363
- });
364
- return null;
365
- }
366
- }
367
- async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
368
- const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
369
- const entries = await Promise.all(
370
- unique.map(
371
- async (address) => [address, await fetchMorphoVaultStats(address, chainId)]
372
- )
373
- );
374
- const byVault = /* @__PURE__ */ new Map();
375
- for (const [address, stats] of entries) {
376
- if (stats) byVault.set(address, stats);
377
- }
378
- return byVault;
379
- }
380
- var MORPHO_API_URL, VAULT_STATS_QUERY;
381
- var init_surfliquid_morpho = __esm({
382
- "src/agents/surfliquid/surfliquid.morpho.ts"() {
383
- "use strict";
384
- MORPHO_API_URL = "https://api.morpho.org/graphql";
385
- VAULT_STATS_QUERY = `
386
- query VaultStats($address: String!, $chainId: Int!) {
387
- vaultByAddress(address: $address, chainId: $chainId) {
388
- name
389
- state { totalAssetsUsd }
390
- liquidity { usd }
391
- }
392
- }
393
- `;
394
- }
395
- });
396
-
397
- // src/agents/surfliquid/surfliquid.agent.ts
398
- var surfliquid_agent_exports = {};
399
- __export(surfliquid_agent_exports, {
400
- SurfLiquidAgent: () => SurfLiquidAgent
401
- });
402
- var import_core_sdk2, import_viem5, import_chains2, APY_WINDOW_KEY2, SurfLiquidAgent;
403
- var init_surfliquid_agent = __esm({
404
- "src/agents/surfliquid/surfliquid.agent.ts"() {
405
- "use strict";
406
- import_core_sdk2 = require("@surf_liquid/core-sdk");
407
- import_viem5 = require("viem");
408
- import_chains2 = require("viem/chains");
409
- init_errors();
410
- init_surfliquid_constants();
411
- init_permit2();
412
- init_surfliquid_mapper();
413
- init_surfliquid_wallet_adapter();
414
- init_surfliquid_morpho();
415
- APY_WINDOW_KEY2 = {
416
- "7D": "apy7d",
417
- "14D": "apy14d",
418
- "30D": "apy30d"
419
- };
420
- SurfLiquidAgent = class {
421
- constructor(config) {
422
- this.config = config;
423
- }
424
- config;
425
- id = "surfliquid";
426
- supportedChainIds = [SURFLIQUID_CHAIN_ID];
427
- supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
428
- surf = null;
429
- connectedAddress = null;
430
- // In-flight connect+auth, shared by concurrent callers to dedupe SIWE.
431
- connectPromise = null;
432
- ensureSurf() {
433
- if (this.surf) return this.surf;
434
- this.surf = import_core_sdk2.SurfClient.create({
435
- projectName: this.config.projectName,
436
- appId: this.config.appId,
437
- environment: "mainnet",
438
- chainId: SURFLIQUID_CHAIN_ID,
439
- apiBaseUrl: this.config.apiBaseUrl,
440
- rpcUrl: this.config.rpcUrl,
441
- // Let the SDK auto-approve USDC to the vault before depositing.
442
- autoApprove: true
443
- });
444
- return this.surf;
445
- }
446
- /**
447
- * Connects + authenticates the SurfClient against owney's provider. Skips the
448
- * SIWE prompt when already authenticated for this wallet (cookie session).
449
- */
450
- async connect(state) {
451
- const surf = this.ensureSurf();
452
- const sameWallet = this.connectedAddress?.toLowerCase() === state.walletAddress.toLowerCase();
453
- if (sameWallet && surf.getAuthState().authenticated) {
454
- return surf;
455
- }
456
- if (this.connectPromise) return this.connectPromise;
457
- this.connectPromise = (async () => {
458
- surf.registerWalletAdapter(
459
- "owney",
460
- new OwneyWalletAdapter(state.provider)
461
- );
462
- await surf.connectWallet("owney");
463
- await surf.authenticate();
464
- this.connectedAddress = state.walletAddress;
465
- return surf;
466
- })();
467
- try {
468
- return await this.connectPromise;
469
- } finally {
470
- this.connectPromise = null;
471
- }
472
- }
473
- /**
474
- * Returns the user's vault address, deploying one on first use. SurfLiquid's
475
- * deposit requires the vault to exist, so this must run before depositing.
476
- * Existing vault → returned as-is; otherwise `deployVault()` is sent
477
- * (user-pays) and the freshly deployed address is returned.
478
- */
479
- async resolveVaultAddress(surf, owner) {
480
- const vault = await surf.getVault(owner).catch(() => null);
481
- if (vault?.exists && vault.userVaultAddress) {
482
- return vault.userVaultAddress;
483
- }
484
- const { vaultAddress } = await surf.deployVault();
485
- return vaultAddress;
486
- }
487
- /**
488
- * Grants the user's vault a standing USDC allowance so SurfLiquid's
489
- * `autoApprove` has nothing to do — see {@link SURFLIQUID_APPROVAL_TARGET}
490
- * for why one prompt per deposit is worth removing.
491
- *
492
- * Fails OPEN on a read error: if the allowance can't be checked we simply
493
- * return and let SurfLiquid's own per-deposit approve run, because a flaky
494
- * RPC must never block a deposit. A failed or rejected APPROVE does
495
- * propagate — the user declined a transaction, and letting SurfLiquid
496
- * immediately ask again for a smaller one is exactly the double prompt this
497
- * removes.
498
- */
499
- async ensureVaultAllowance(state, vaultAddress, amount) {
500
- const spender = vaultAddress;
501
- const transport = (0, import_viem5.custom)(state.provider);
502
- const publicClient = (0, import_viem5.createPublicClient)({ chain: import_chains2.base, transport });
503
- let allowance;
504
- try {
505
- allowance = await publicClient.readContract({
506
- address: SURFLIQUID_USDC_ADDRESS,
507
- abi: ERC20_ALLOWANCE_ABI,
508
- functionName: "allowance",
509
- args: [state.walletAddress, spender]
510
- });
511
- } catch (error) {
512
- console.warn(
513
- "[owney-sdk] SurfLiquid allowance pre-check failed; deferring to its per-deposit approve:",
514
- error instanceof Error ? error.message : String(error)
515
- );
516
- return;
517
- }
518
- if (allowance >= amount) return;
519
- const target = amount > SURFLIQUID_APPROVAL_TARGET ? amount : SURFLIQUID_APPROVAL_TARGET;
520
- const wallet = (0, import_viem5.createWalletClient)({
521
- account: state.walletAddress,
522
- chain: import_chains2.base,
523
- transport
524
- });
525
- const hash = await wallet.writeContract({
526
- address: SURFLIQUID_USDC_ADDRESS,
527
- abi: ERC20_ALLOWANCE_ABI,
528
- functionName: "approve",
529
- args: [spender, target],
530
- account: state.walletAddress,
531
- chain: import_chains2.base
532
- });
533
- const receipt = await publicClient.waitForTransactionReceipt({
534
- hash,
535
- confirmations: 1
536
- });
537
- if (receipt.status !== "success") {
538
- throw new Error(`SurfLiquid USDC approval reverted (tx ${hash})`);
539
- }
540
- }
541
- // --- IAgent: lifecycle ---
542
- async disconnect() {
543
- if (this.surf) {
544
- await this.surf.disconnectWallet();
545
- }
546
- this.connectedAddress = null;
547
- }
548
- async activateAgent(state) {
549
- await this.connect(state);
550
- }
551
- // --- IAgent: funds (user-pays; asset is always USDC, callback ignored) ---
552
- async deposit(state, _chainId, amount, _asset, _depositCallback) {
553
- const surf = await this.connect(state);
554
- const human = (0, import_viem5.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS);
555
- const smartWallet = await this.resolveVaultAddress(
556
- surf,
557
- state.walletAddress
558
- );
559
- await this.ensureVaultAllowance(state, smartWallet, BigInt(amount));
560
- const tx = await surf.deposit({
561
- asset: SURFLIQUID_USDC_ADDRESS,
562
- amount: human
563
- });
564
- await tx.wait();
565
- return { txHash: tx.hash, smartWallet, amount };
566
- }
567
- async withdraw(state, _chainId, _token, amount) {
568
- const surf = await this.connect(state);
569
- const human = amount != null ? (0, import_viem5.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS) : void 0;
570
- try {
571
- const tx = await surf.withdraw({
572
- asset: SURFLIQUID_USDC_ADDRESS,
573
- amount: human
574
- });
575
- await tx.wait();
576
- return {
577
- txHash: tx.hash,
578
- type: amount != null ? "partial" : "full",
579
- amount: amount ?? "0"
580
- };
581
- } catch (error) {
582
- throw new OwneyError(
583
- "WITHDRAW_FAILED",
584
- error instanceof Error ? error.message : "SurfLiquid withdraw failed.",
585
- { chainId: SURFLIQUID_CHAIN_ID, amount },
586
- this.id
587
- );
588
- }
589
- }
590
- // --- IAgent: portfolio reads ---
591
- async getBalances(state, chainId) {
592
- const surf = await this.connect(state);
593
- const vault = await surf.getVault(state.walletAddress);
594
- const morphoVaultAddresses = (vault.assets ?? []).filter((asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId).map((asset) => asset.morphoVaultAddress).filter((address) => Boolean(address));
595
- const morphoStats = await fetchMorphoStatsByVault(
596
- morphoVaultAddresses,
597
- chainId
598
- );
599
- return mapBalances2(vault, chainId, morphoStats);
600
- }
601
- async getEarnings(state) {
602
- const surf = await this.connect(state);
603
- const vault = await surf.getVault(state.walletAddress);
604
- return mapEarnings2(vault, vault.userVaultAddress ?? state.walletAddress);
605
- }
606
- async getAccountApy(state, _chainId, days, _tokenSymbol) {
607
- const surf = await this.connect(state);
608
- const vault = await surf.getVault(state.walletAddress);
609
- return mapAccountApy(vault, days);
610
- }
611
- async getHistory(state, chainId, options) {
612
- const surf = await this.connect(state);
613
- const page = options?.cursor ? Number(options.cursor) : 1;
614
- const limit = options?.limit ?? 10;
615
- const result = await surf.getAgentMessages(
616
- state.walletAddress,
617
- page,
618
- limit,
619
- options?.fromDate,
620
- options?.toDate
621
- );
622
- return mapHistory(result, chainId);
623
- }
624
- async getUserProfile(state) {
625
- const surf = await this.connect(state);
626
- const vault = await surf.getVault(state.walletAddress);
627
- return mapUserProfile2(vault, state.walletAddress);
628
- }
629
- // --- IAgent: discovery (no wallet) ---
630
- async getAgentApy(days, _options) {
631
- const surf = this.ensureSurf();
632
- const assets = await surf.getSupportedAssets(SURFLIQUID_CHAIN_ID);
633
- const usdc = assets.find((asset) => asset.assetSymbol === "USDC");
634
- if (!usdc) return { averageApy: 0 };
635
- const windowed = usdc[APY_WINDOW_KEY2[days]];
636
- return { averageApy: windowed != null ? windowed : usdc.currentAPY };
637
- }
638
- };
639
- }
640
- });
641
-
642
20
  // src/index.ts
643
21
  var index_exports = {};
644
22
  __export(index_exports, {
@@ -648,8 +26,7 @@ __export(index_exports, {
648
26
  NotConnectedError: () => NotConnectedError,
649
27
  OwneyError: () => OwneyError,
650
28
  OwneySDK: () => OwneySDK,
651
- createOwneySIWX: () => createOwneySIWX,
652
- setOwneyDebug: () => setOwneyDebug
29
+ createOwneySIWX: () => createOwneySIWX
653
30
  });
654
31
  module.exports = __toCommonJS(index_exports);
655
32
 
@@ -711,8 +88,56 @@ var SupportedAssets = [
711
88
  }
712
89
  ];
713
90
 
91
+ // src/errors.ts
92
+ var OwneyError = class extends Error {
93
+ code;
94
+ details;
95
+ agentId;
96
+ constructor(code, message, details, agentId) {
97
+ const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
98
+ super(`${prefix} ${message}`);
99
+ this.name = "OwneyError";
100
+ this.code = code;
101
+ this.details = details;
102
+ this.agentId = agentId;
103
+ }
104
+ };
105
+ var AgentNotFoundError = class extends OwneyError {
106
+ constructor(agentId, available) {
107
+ super(
108
+ "AGENT_NOT_FOUND",
109
+ `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
110
+ { agentId, available },
111
+ agentId
112
+ );
113
+ this.name = "AgentNotFoundError";
114
+ }
115
+ };
116
+ var NotConnectedError = class extends OwneyError {
117
+ constructor() {
118
+ super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
119
+ this.name = "NotConnectedError";
120
+ }
121
+ };
122
+ var AgentChainIncompatibleError = class extends OwneyError {
123
+ incompatibleAgents;
124
+ connectedChainId;
125
+ constructor(incompatibleAgents, connectedChainId) {
126
+ const details = incompatibleAgents.map(
127
+ ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
128
+ ).join("; ");
129
+ super(
130
+ "AGENT_CHAIN_INCOMPATIBLE",
131
+ `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
132
+ { incompatibleAgents, connectedChainId }
133
+ );
134
+ this.name = "AgentChainIncompatibleError";
135
+ this.incompatibleAgents = incompatibleAgents;
136
+ this.connectedChainId = connectedChainId;
137
+ }
138
+ };
139
+
714
140
  // src/lib/utils.ts
715
- init_errors();
716
141
  var isValidChainId = (chainId) => {
717
142
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
718
143
  throw new OwneyError(
@@ -786,46 +211,46 @@ function resolveChainId(chain) {
786
211
  function mapBalances(raw, _chainId, smartWallet) {
787
212
  const portfolio = raw.portfolio;
788
213
  const portfolioByChain = portfolio.portfolioByChain ?? {};
789
- const rawPositions = portfolio.positions ?? [];
790
- const detailByKey = /* @__PURE__ */ new Map();
791
- for (const p of rawPositions) {
792
- const cid = resolveChainId(p.chain ?? "");
793
- const symbol = (p.token_symbol ?? "").toUpperCase();
794
- if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
795
- }
796
214
  let totalBalance = 0;
797
215
  const tokens = [];
798
- const positions = [];
799
216
  for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
800
217
  const positionChainId = Number(chainIdKey);
801
- const chainName = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
802
218
  for (const [symbol, { balance, decimals }] of Object.entries(
803
219
  tokensBySymbol ?? {}
804
220
  )) {
805
- const amount = hexToDecimal(balance || "0", tokenDecimals(symbol, decimals));
221
+ const amount = hexToDecimal(balance || "0", decimals);
806
222
  totalBalance += amount;
807
223
  tokens.push({
808
- chain: chainName,
224
+ chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
809
225
  chainId: positionChainId,
810
226
  asset: symbol,
811
227
  amount: String(amount)
812
228
  });
813
- const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
814
- positions.push({
815
- chain: chainName,
816
- protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
817
- protocolId: detail?.protocol_id,
818
- pool: detail?.pool,
819
- asset: symbol,
820
- amount: String(amount),
821
- apy: detail?.pool_apy,
822
- tvl: detail?.pool_tvl,
823
- // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
824
- // structural read keeps it undefined today and auto-populates later.
825
- liquidity: detail?.liquidity
826
- });
827
229
  }
828
230
  }
231
+ const positions = (portfolio.positions ?? []).map((p) => ({
232
+ chain: p.chain ?? "",
233
+ protocol: p.protocol_name ?? p.protocol_id ?? "",
234
+ protocolId: p.protocol_id,
235
+ pool: p.pool,
236
+ asset: p.token_symbol ?? "",
237
+ // Position amount is hex-encoded base units (like the token balances
238
+ // above). `PositionSlot` doesn't type a `decimals` field, but runtime
239
+ // getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
240
+ // when present, otherwise fall back to the per-symbol lookup so
241
+ // non-6-decimal assets like WETH don't render 1e12 too large.
242
+ amount: String(
243
+ hexToDecimal(
244
+ p.amount || "0",
245
+ tokenDecimals(p.token_symbol, p.decimals)
246
+ )
247
+ ),
248
+ apy: p.pool_apy,
249
+ tvl: p.pool_tvl,
250
+ // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
251
+ // structural read keeps it undefined today and auto-populates later.
252
+ liquidity: p.liquidity
253
+ }));
829
254
  return {
830
255
  smartWallet,
831
256
  totalBalance: String(totalBalance),
@@ -987,9 +412,7 @@ function mapUserProfile(raw, userAddress) {
987
412
  chains: raw.chains || [],
988
413
  strategy: raw.strategy,
989
414
  hasActiveSessionKey: raw.hasActiveSessionKey || false,
990
- protocols: raw.protocols || [],
991
- splitting: raw.splitting,
992
- minSplits: raw.minSplits
415
+ protocols: raw.protocols || []
993
416
  };
994
417
  }
995
418
  function mapApyByStrategy(raw) {
@@ -1102,9 +525,6 @@ function decodeHistoryCursor(token) {
1102
525
  return parsed;
1103
526
  }
1104
527
 
1105
- // src/agents/zyfai/zyfai.agent.ts
1106
- init_errors();
1107
-
1108
528
  // src/agents/zyfai/zyfai.auth-cache.ts
1109
529
  var KEY_PREFIX = "owney.zyfai.session";
1110
530
  var storage = () => {
@@ -1139,23 +559,23 @@ var readLegacySession = (store, address) => {
1139
559
  const legacyKeys = [];
1140
560
  try {
1141
561
  for (let i = 0; i < store.length; i++) {
1142
- const key2 = store.key(i);
1143
- if (key2?.startsWith(prefix)) legacyKeys.push(key2);
562
+ const key = store.key(i);
563
+ if (key?.startsWith(prefix)) legacyKeys.push(key);
1144
564
  }
1145
565
  } catch {
1146
566
  return null;
1147
567
  }
1148
568
  let adopted = null;
1149
- for (const key2 of legacyKeys) {
569
+ for (const key of legacyKeys) {
1150
570
  if (!adopted) {
1151
571
  try {
1152
- const parsed = JSON.parse(store.getItem(key2) ?? "");
572
+ const parsed = JSON.parse(store.getItem(key) ?? "");
1153
573
  if (isFreshSession(parsed)) adopted = parsed;
1154
574
  } catch {
1155
575
  }
1156
576
  }
1157
577
  try {
1158
- store.removeItem(key2);
578
+ store.removeItem(key);
1159
579
  } catch {
1160
580
  }
1161
581
  }
@@ -1163,11 +583,11 @@ var readLegacySession = (store, address) => {
1163
583
  };
1164
584
  var readSession = (address, _chainId) => {
1165
585
  if (typeof window === "undefined") return null;
1166
- const key2 = buildKey(address);
586
+ const key = buildKey(address);
1167
587
  const store = storage();
1168
588
  let raw = null;
1169
589
  try {
1170
- raw = store?.getItem(key2) ?? null;
590
+ raw = store?.getItem(key) ?? null;
1171
591
  } catch {
1172
592
  raw = null;
1173
593
  }
@@ -1177,9 +597,9 @@ var readSession = (address, _chainId) => {
1177
597
  if (isFreshSession(parsed)) return parsed;
1178
598
  } catch {
1179
599
  }
1180
- memorySessions.delete(key2);
600
+ memorySessions.delete(key);
1181
601
  try {
1182
- store?.removeItem(key2);
602
+ store?.removeItem(key);
1183
603
  } catch {
1184
604
  }
1185
605
  return null;
@@ -1189,27 +609,27 @@ var readSession = (address, _chainId) => {
1189
609
  writeSession(address, _chainId, legacy);
1190
610
  return legacy;
1191
611
  }
1192
- const cached = memorySessions.get(key2);
612
+ const cached = memorySessions.get(key);
1193
613
  if (isFreshSession(cached)) return cached;
1194
- if (cached) memorySessions.delete(key2);
614
+ if (cached) memorySessions.delete(key);
1195
615
  return null;
1196
616
  };
1197
617
  var writeSession = (address, _chainId, session) => {
1198
618
  if (typeof window === "undefined") return;
1199
- const key2 = buildKey(address);
1200
- memorySessions.set(key2, session);
619
+ const key = buildKey(address);
620
+ memorySessions.set(key, session);
1201
621
  const store = storage();
1202
622
  try {
1203
- store?.setItem(key2, JSON.stringify(session));
623
+ store?.setItem(key, JSON.stringify(session));
1204
624
  } catch {
1205
625
  }
1206
626
  };
1207
627
  var clearSession = (address, _chainId) => {
1208
- const key2 = buildKey(address);
1209
- memorySessions.delete(key2);
628
+ const key = buildKey(address);
629
+ memorySessions.delete(key);
1210
630
  const store = storage();
1211
631
  try {
1212
- store?.removeItem(key2);
632
+ store?.removeItem(key);
1213
633
  } catch {
1214
634
  }
1215
635
  readLegacySession(store, address);
@@ -1240,149 +660,6 @@ function buildProtocolMergeUpdate(available, current, asset) {
1240
660
  };
1241
661
  }
1242
662
 
1243
- // src/agents/zyfai/splitting.ts
1244
- var MAX_MIN_SPLITS = 4;
1245
- var MIN_FORCE_SPLITS = 2;
1246
- var AUTOMATIC_MIN_SPLITS = 1;
1247
- function toZyfaiSplitting(policy) {
1248
- switch (policy.splittingMode) {
1249
- case "none":
1250
- return { splitting: false };
1251
- case "automatic":
1252
- return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
1253
- case "force":
1254
- return {
1255
- splitting: true,
1256
- minSplits: clampForceSplits(policy.minSplits)
1257
- };
1258
- }
1259
- }
1260
- function clampForceSplits(minSplits) {
1261
- if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
1262
- return MIN_FORCE_SPLITS;
1263
- }
1264
- const rounded = Math.round(minSplits);
1265
- if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
1266
- if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
1267
- return rounded;
1268
- }
1269
- function splittingNeedsUpdate(current, desired) {
1270
- if (!current) return true;
1271
- if (current.splitting !== desired.splitting) return true;
1272
- if (desired.minSplits === void 0) return false;
1273
- return current.minSplits !== desired.minSplits;
1274
- }
1275
-
1276
- // src/agents/zyfai/pool-policy.ts
1277
- function toZyfaiCustomizations(policy, availableByProtocol, chainsByProtocol) {
1278
- const selectionByKey = /* @__PURE__ */ new Map();
1279
- for (const selection of policy.selections) {
1280
- selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
1281
- }
1282
- const customizations = [];
1283
- for (const [protocolId, chainIds] of Object.entries(chainsByProtocol)) {
1284
- const available = availableByProtocol.get(protocolId);
1285
- if (available === void 0) {
1286
- continue;
1287
- }
1288
- const availableSet = new Set(available);
1289
- for (const chainId of chainIds) {
1290
- const stored = selectionByKey.get(key(protocolId, chainId));
1291
- if (stored === void 0) {
1292
- customizations.push({
1293
- protocolId,
1294
- chainId,
1295
- pools: [],
1296
- autoselect: true
1297
- });
1298
- continue;
1299
- }
1300
- const pools = stored.pools.filter((pool) => availableSet.has(pool));
1301
- customizations.push({
1302
- protocolId,
1303
- chainId,
1304
- pools,
1305
- autoselect: false
1306
- });
1307
- }
1308
- }
1309
- return customizations;
1310
- }
1311
- function deriveProtocols(policy, universe, chainsByProtocol) {
1312
- if (policy.selections.length === 0) {
1313
- return null;
1314
- }
1315
- const selectionByKey = /* @__PURE__ */ new Map();
1316
- for (const selection of policy.selections) {
1317
- selectionByKey.set(key(selection.protocolId, selection.chainId), selection);
1318
- }
1319
- return universe.filter((protocolId) => {
1320
- const chainIds = chainsByProtocol[protocolId];
1321
- if (chainIds === void 0 || chainIds.length === 0) {
1322
- return true;
1323
- }
1324
- const fullyDisabled = chainIds.every((chainId) => {
1325
- const stored = selectionByKey.get(key(protocolId, chainId));
1326
- return stored !== void 0 && stored.pools.length === 0;
1327
- });
1328
- return !fullyDisabled;
1329
- });
1330
- }
1331
- function key(protocolId, chainId) {
1332
- return `${protocolId}:${chainId}`;
1333
- }
1334
- function buildChainsByProtocol(protocols, dashboardChainIds) {
1335
- const allowed = new Set(dashboardChainIds);
1336
- const result = {};
1337
- for (const protocol of protocols) {
1338
- result[protocol.id] = (protocol.chains ?? []).filter(
1339
- (chainId) => allowed.has(chainId)
1340
- );
1341
- }
1342
- return result;
1343
- }
1344
- function flattenAvailablePools(raw) {
1345
- const byChain = raw ?? {};
1346
- const names = [];
1347
- for (const byToken of Object.values(byChain ?? {})) {
1348
- for (const entry of Object.values(byToken ?? {})) {
1349
- for (const pool of entry?.pools ?? []) {
1350
- if (pool?.name) names.push(pool.name);
1351
- }
1352
- }
1353
- }
1354
- return names;
1355
- }
1356
- function protocolListsEqual(a, b) {
1357
- const left = [...a ?? []].sort();
1358
- const right = [...b ?? []].sort();
1359
- if (left.length !== right.length) return false;
1360
- return left.every((value, index) => value === right[index]);
1361
- }
1362
- function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect) {
1363
- if (!current) return true;
1364
- if (current.autoSelectProtocols !== desiredAutoSelect) return true;
1365
- if (desiredProtocols === null) return false;
1366
- return !protocolListsEqual(current.protocols, desiredProtocols);
1367
- }
1368
-
1369
- // src/lib/debug.ts
1370
- var configuredDebug = false;
1371
- function setOwneyDebug(enabled) {
1372
- configuredDebug = enabled;
1373
- }
1374
- function isOwneyDebug() {
1375
- return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
1376
- }
1377
- function debugLog(scope, message, data) {
1378
- if (!isOwneyDebug()) return;
1379
- if (data === void 0) {
1380
- console.log(`[${scope}] ${message}`);
1381
- } else {
1382
- console.log(`[${scope}] ${message}`, data);
1383
- }
1384
- }
1385
-
1386
663
  // src/agents/zyfai/zyfai.agent.ts
1387
664
  var DEFAULT_ZYFAI_RPC_URLS = {
1388
665
  8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
@@ -1395,12 +672,6 @@ var WETH_ADDRESS_BY_CHAIN = {
1395
672
  1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
1396
673
  };
1397
674
  var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
1398
- var SPLITTING_ASSETS = ["USDC", "WETH"];
1399
- var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
1400
- function isAlreadyActiveSessionKeyError(error) {
1401
- const message = error instanceof Error ? error.message : String(error);
1402
- return /already has an active session key/i.test(message);
1403
- }
1404
675
  var ZyfaiAgent = class {
1405
676
  id = "zyfai";
1406
677
  supportedChainIds = [8453, 42161, 1];
@@ -1627,71 +898,21 @@ var ZyfaiAgent = class {
1627
898
  return await this.sdk.connectAccount(provider, chainId);
1628
899
  }
1629
900
  }
1630
- /** Full connect: SIWE auth + Safe deploy check + session key. */
1631
- async connectFull(state, chainId) {
1632
- await this.connectAuth(state, chainId);
1633
- const validChainId = isValidChainId(chainId);
1634
- const address = this.getAddress();
1635
- const wallet = await this.sdk.getSmartWalletAddress(address, validChainId);
1636
- this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
1637
- if (!wallet.isDeployed) {
1638
- await this.sdk.deploySafe(address, validChainId, "aggressive", false);
1639
- try {
1640
- if (validChainId === 42161) {
1641
- await this.sdk.updateUserProfile({
1642
- asset: "WETH",
1643
- chains: [validChainId],
1644
- protocols: ["c24a33fa-4a87-4376-b756-93bd3957d3ea"],
1645
- // AAVE protocol ID
1646
- autoSelectProtocols: false
1647
- });
1648
- }
1649
- } catch (err) {
1650
- console.warn(
1651
- "Failed to configure AAVE protocol after Safe deployment:",
1652
- err instanceof Error ? err.message : String(err)
1653
- );
1654
- }
1655
- }
1656
- await this.ensureSessionKey(state, address, validChainId);
1657
- }
1658
901
  /**
1659
- * Ensures the user has an active session key, creating one if absent.
1660
- *
1661
- * The Zyfai session key is a single **per-user** record, not per-chain: its
1662
- * config (`/session-keys/config`) spans every supported chain and is signed
1663
- * in one shot, and the backend rejects `POST /session-keys/add` with 400
1664
- * "User already has an active session key" if one exists. So we must NOT try
1665
- * to (re)create a key per chain — that 400s and blocks the deposit. We only
1666
- * create when the user has none.
1667
- *
1668
- * The one wrapper-side hardening that IS needed: a chain/account switch can
1669
- * fire the provider's `accountsChanged` → `disconnectAccount`, tearing down
1670
- * the zyfai connection (walletClient + authenticatedUserId both null) while
1671
- * our own `connectAuth` guard still believes this chain is connected and
1672
- * early-returns without reconnecting. `createSessionKey` then fails with
1673
- * "No account connected". Detect that and reconnect first.
1674
- *
1675
- * NOTE: whether a globally-active session key actually authorizes activity on
1676
- * a freshly-deployed Safe on a new chain is a backend/zyf question — the
1677
- * wrapper cannot force per-chain activation given the global 400 guard.
1678
- * See [[zyfai-per-chain-session-key]].
902
+ * Reconnect if the Zyfai connection was torn down behind our back: a
903
+ * chain/account switch fires the provider's `accountsChanged` →
904
+ * `disconnectAccount` (nulls walletClient + authenticatedUserId) while our
905
+ * own `connectAuth` guard still believes this chain is connected and
906
+ * early-returns. Without this, authenticated calls (depositFunds,
907
+ * withdrawFunds) fail with "No account connected".
1679
908
  */
1680
- async ensureSessionKey(state, address, chainId) {
909
+ async ensureConnected(state, chainId) {
910
+ await this.connectAuth(state, chainId);
1681
911
  const internals = this.sdk;
1682
912
  if (!internals.walletClient || internals.authenticatedUserId === null) {
1683
913
  this.connectedChainId = null;
1684
914
  await this.connectAuth(state, chainId);
1685
915
  }
1686
- const user = await this.sdk.getUserDetails();
1687
- if (!user.hasActiveSessionKey) {
1688
- try {
1689
- await this.sdk.createSessionKey(address, chainId);
1690
- } catch (error) {
1691
- if (!isAlreadyActiveSessionKeyError(error)) throw error;
1692
- internals.hasActiveSessionKey = true;
1693
- }
1694
- }
1695
916
  }
1696
917
  /**
1697
918
  * Sync newly-available protocols onto an existing user's profile at wallet
@@ -1761,180 +982,10 @@ var ZyfaiAgent = class {
1761
982
  throw error;
1762
983
  }
1763
984
  }
1764
- /**
1765
- * Apply the org's capital splitting policy to this user's Zyfai profile.
1766
- *
1767
- * Per ASSET, not per chain: Zyfai stores splitting under
1768
- * `assetTypeSettings[asset]`, so one call would only configure USDC and leave a
1769
- * WETH holder's real setting untouched.
1770
- *
1771
- * Non-fatal throughout. This is a side effect of connecting, so a Zyfai hiccup
1772
- * must leave the user connected with their profile unchanged, never fail
1773
- * activation.
1774
- */
1775
- async applyOrgPolicy(_state, _chainId, policy) {
1776
- debugLog("zyfai:splitting", "applying org policy", {
1777
- policy,
1778
- // Per asset because Zyfai stores splitting under assetTypeSettings[asset].
1779
- assets: SPLITTING_ASSETS
1780
- });
1781
- await Promise.all(
1782
- SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
1783
- );
1784
- if (policy.poolPolicy) {
1785
- await this.applyPoolPolicy(policy.poolPolicy);
1786
- }
1787
- }
1788
- async applySplitting(asset, policy) {
1789
- try {
1790
- const desired = toZyfaiSplitting(policy);
1791
- const current = await this.sdk.getUserDetails(asset);
1792
- const currentSplitting = {
1793
- splitting: current?.splitting,
1794
- minSplits: current?.minSplits
1795
- };
1796
- const needsUpdate = splittingNeedsUpdate(current, desired);
1797
- debugLog("zyfai:splitting", `${asset}: comparing`, {
1798
- mode: policy.splittingMode,
1799
- current: currentSplitting,
1800
- desired,
1801
- // Spelled out because the "why" is the non-obvious part: minSplits is
1802
- // what separates automatic (1) from force (2-4), not `splitting`.
1803
- decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
1804
- });
1805
- if (!needsUpdate) return;
1806
- const result = await this.sdk.updateUserProfile({ asset, ...desired });
1807
- debugLog("zyfai:splitting", `${asset}: wrote updateUserProfile`, {
1808
- sent: { asset, ...desired },
1809
- // updateUserProfile re-reads the profile after PATCHing, so this is
1810
- // Zyfai's own view of the result rather than an echo of what we sent.
1811
- zyfaiNowReports: {
1812
- splitting: result?.splitting,
1813
- minSplits: result?.minSplits
1814
- }
1815
- });
1816
- } catch (error) {
1817
- console.warn(
1818
- `[zyfai] applyOrgPolicy(${asset}) failed (non-fatal):`,
1819
- error instanceof Error ? error.message : String(error)
1820
- );
1821
- }
1822
- }
1823
- /**
1824
- * Apply the org's protocol/pool policy to this user's Zyfai profile.
1825
- *
1826
- * Two Zyfai writes, in a strict order:
1827
- * 1. `updateUserProfile({ protocols, autoSelectProtocols })` per asset —
1828
- * the explicit allow-list. Chain-agnostic, mirrors `applySplitting`.
1829
- * 2. `customizeBatch(...)` once — per (protocol, chain), asset-agnostic
1830
- * pool narrowing.
1831
- *
1832
- * Order matters: constraining a protocol's pools (step 2) while that
1833
- * protocol is not yet in the allow-list (step 1 not yet applied) lands the
1834
- * constraint on something the rebalance engine isn't considering.
1835
- *
1836
- * Wrapped so a failure anywhere is non-fatal — this runs as a side effect of
1837
- * connecting, so a Zyfai hiccup must leave the user connected with their
1838
- * profile unchanged, never fail activation.
1839
- */
1840
- async applyPoolPolicy(policy) {
1841
- try {
1842
- const { protocols: universe } = await this.sdk.getAvailableProtocols(
1843
- this.supportedChainIds[0]
1844
- );
1845
- const universeIds = universe.map((p) => p.id);
1846
- const chainsByProtocol = buildChainsByProtocol(
1847
- universe,
1848
- POOL_POLICY_CHAIN_IDS
1849
- );
1850
- debugLog("zyfai:pools", "protocol universe", {
1851
- universeIds,
1852
- chainsByProtocol
1853
- });
1854
- let strategy;
1855
- const desiredProtocols = deriveProtocols(
1856
- policy,
1857
- universeIds,
1858
- chainsByProtocol
1859
- );
1860
- const desiredAutoSelect = policy.autoApproveProtocols;
1861
- for (const asset of SPLITTING_ASSETS) {
1862
- const current = await this.sdk.getUserDetails(asset);
1863
- if (strategy === void 0 && (current.strategy === "conservative" || current.strategy === "aggressive")) {
1864
- strategy = current.strategy;
1865
- }
1866
- const needsUpdate = protocolsPolicyNeedsUpdate(
1867
- current,
1868
- desiredProtocols,
1869
- desiredAutoSelect
1870
- );
1871
- debugLog("zyfai:pools", `${asset}: comparing protocols`, {
1872
- current: {
1873
- protocols: current.protocols,
1874
- autoSelectProtocols: current.autoSelectProtocols
1875
- },
1876
- desired: {
1877
- protocols: desiredProtocols,
1878
- autoSelectProtocols: desiredAutoSelect
1879
- },
1880
- decision: needsUpdate ? "will write \u2014 profile differs from the org policy" : "skipping \u2014 profile already matches"
1881
- });
1882
- if (!needsUpdate) continue;
1883
- const update = {
1884
- asset,
1885
- autoSelectProtocols: desiredAutoSelect
1886
- };
1887
- if (desiredProtocols !== null) update.protocols = desiredProtocols;
1888
- await this.sdk.updateUserProfile(update);
1889
- debugLog("zyfai:pools", `${asset}: wrote protocols update`, update);
1890
- }
1891
- const poolResults = await Promise.all(
1892
- universe.map(async (protocol) => {
1893
- try {
1894
- const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
1895
- return [protocol.id, flattenAvailablePools(raw)];
1896
- } catch (error) {
1897
- console.warn(
1898
- `[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
1899
- error instanceof Error ? error.message : String(error)
1900
- );
1901
- return null;
1902
- }
1903
- })
1904
- );
1905
- const availableByProtocol = /* @__PURE__ */ new Map();
1906
- for (const result of poolResults) {
1907
- if (result) availableByProtocol.set(result[0], result[1]);
1908
- }
1909
- const customizations = toZyfaiCustomizations(
1910
- policy,
1911
- availableByProtocol,
1912
- chainsByProtocol
1913
- );
1914
- debugLog("zyfai:pools", "derived customizeBatch payload", {
1915
- strategy,
1916
- availableProtocolCount: availableByProtocol.size,
1917
- customizations
1918
- });
1919
- if (customizations.length === 0) {
1920
- debugLog("zyfai:pools", "skipping customizeBatch \u2014 nothing to send");
1921
- return;
1922
- }
1923
- await this.sdk.customizeBatch(customizations);
1924
- debugLog("zyfai:pools", "wrote customizeBatch", {
1925
- count: customizations.length
1926
- });
1927
- } catch (error) {
1928
- console.warn(
1929
- "[zyfai] applyPoolPolicy failed (non-fatal):",
1930
- error instanceof Error ? error.message : String(error)
1931
- );
1932
- }
1933
- }
1934
985
  async deposit(state, chainId, amount, asset, depositCallback) {
1935
986
  try {
1936
- await this.connectFull(state, chainId);
1937
987
  const validChainId = isValidChainId(chainId);
988
+ await this.ensureConnected(state, validChainId);
1938
989
  if (depositCallback) {
1939
990
  const wallet = await this.sdk.getSmartWalletAddress(
1940
991
  this.getAddress(),
@@ -1960,7 +1011,8 @@ var ZyfaiAgent = class {
1960
1011
  this.getAddress(),
1961
1012
  validChainId,
1962
1013
  amount,
1963
- asset
1014
+ asset,
1015
+ "aggressive"
1964
1016
  );
1965
1017
  return mapDeposit(raw);
1966
1018
  } catch (error) {
@@ -1969,8 +1021,8 @@ var ZyfaiAgent = class {
1969
1021
  }
1970
1022
  // --- IAgent: Fund operations ---
1971
1023
  async withdraw(state, chainId, token, amount) {
1972
- await this.connectFull(state, chainId);
1973
1024
  const validChainId = isValidChainId(chainId);
1025
+ await this.ensureConnected(state, validChainId);
1974
1026
  const raw = await this.sdk.withdrawFunds(
1975
1027
  this.getAddress(),
1976
1028
  validChainId,
@@ -2049,19 +1101,7 @@ var ZyfaiAgent = class {
2049
1101
  }
2050
1102
  async getUserProfile(state, chainId) {
2051
1103
  await this.connectAuth(state, chainId);
2052
- const validChainId = isValidChainId(chainId);
2053
1104
  const raw = await this.sdk.getUserDetails();
2054
- debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
2055
- asset: "USDC (default \u2014 no asset passed)",
2056
- splitting: raw.splitting,
2057
- minSplits: raw.minSplits,
2058
- strategy: raw.strategy,
2059
- chains: raw.chains,
2060
- protocolCount: raw.protocols?.length,
2061
- hasActiveSessionKey: raw.hasActiveSessionKey,
2062
- smartWallet: raw.smartWallet
2063
- });
2064
- await this.ensureSessionKey(state, this.getAddress(), validChainId);
2065
1105
  return mapUserProfile(raw, this.connectedAddress);
2066
1106
  }
2067
1107
  async ensureAutoSelectProtocols(state, chainId, asset) {
@@ -2092,46 +1132,8 @@ var ZyfaiAgent = class {
2092
1132
  }
2093
1133
  };
2094
1134
 
2095
- // src/client.ts
2096
- init_errors();
2097
-
2098
1135
  // src/lib/routing-api.ts
2099
- init_errors();
2100
1136
  var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2101
- async function fetchOrgAgentConfig(apiKey) {
2102
- const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
2103
- try {
2104
- const res = await fetch(url, {
2105
- method: "GET",
2106
- headers: {
2107
- "Content-Type": "application/json",
2108
- "x-owney-api-key": `${apiKey}`
2109
- }
2110
- });
2111
- if (!res.ok) {
2112
- if (res.status !== 404) {
2113
- console.warn(
2114
- `[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
2115
- );
2116
- }
2117
- return null;
2118
- }
2119
- const json = await res.json();
2120
- const policy = json.success ? json.data ?? null : null;
2121
- debugLog(
2122
- "owney-sdk",
2123
- policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
2124
- policy ?? void 0
2125
- );
2126
- return policy;
2127
- } catch (error) {
2128
- console.warn(
2129
- "[owney-sdk] Could not read org agent config (non-fatal):",
2130
- error instanceof Error ? error.message : String(error)
2131
- );
2132
- return null;
2133
- }
2134
- }
2135
1137
  async function fetchAgentKeys(apiKey) {
2136
1138
  const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
2137
1139
  const res = await fetch(url, {
@@ -2161,7 +1163,6 @@ async function fetchAgentKeys(apiKey) {
2161
1163
  }
2162
1164
 
2163
1165
  // src/lib/health-report.ts
2164
- init_errors();
2165
1166
  var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2166
1167
  async function reportAgentFailure(apiKey, agentType, errorCode) {
2167
1168
  try {
@@ -2311,11 +1312,8 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
2311
1312
  }
2312
1313
 
2313
1314
  // src/client.ts
2314
- var import_viem6 = require("viem");
2315
- var import_chains3 = require("viem/chains");
2316
-
2317
- // src/lib/sponsored-deposit.ts
2318
- init_errors();
1315
+ var import_viem5 = require("viem");
1316
+ var import_chains2 = require("viem/chains");
2319
1317
 
2320
1318
  // src/lib/transfer-auth.ts
2321
1319
  var import_viem3 = require("viem");
@@ -2354,13 +1352,12 @@ function randomAuthNonce() {
2354
1352
  }
2355
1353
 
2356
1354
  // src/lib/sponsor-client.ts
2357
- init_errors();
2358
1355
  var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2359
1356
  async function postSponsorTransferAuth(input) {
2360
- const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1357
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2361
1358
  let res;
2362
1359
  try {
2363
- res = await fetch(`${base4}/api/v1/sponsor/erc20-transfer-auth`, {
1360
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2364
1361
  method: "POST",
2365
1362
  headers: {
2366
1363
  "content-type": "application/json",
@@ -2397,10 +1394,10 @@ async function postSponsorTransferAuth(input) {
2397
1394
  return parsed.data;
2398
1395
  }
2399
1396
  async function postSponsorPermit2Transfer(input) {
2400
- const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1397
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2401
1398
  let res;
2402
1399
  try {
2403
- res = await fetch(`${base4}/api/v1/sponsor/permit2-transfer`, {
1400
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2404
1401
  method: "POST",
2405
1402
  headers: {
2406
1403
  "content-type": "application/json",
@@ -2435,11 +1432,11 @@ async function postSponsorPermit2Transfer(input) {
2435
1432
  return parsed.data;
2436
1433
  }
2437
1434
  async function getSponsorRelayerAddress(input) {
2438
- const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
1435
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2439
1436
  let res;
2440
1437
  try {
2441
1438
  res = await fetch(
2442
- `${base4}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
1439
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2443
1440
  {
2444
1441
  headers: { "x-owney-api-key": input.apiKey }
2445
1442
  }
@@ -2471,8 +1468,85 @@ async function getSponsorRelayerAddress(input) {
2471
1468
  return parsed.data.relayer;
2472
1469
  }
2473
1470
 
1471
+ // src/lib/permit2.ts
1472
+ var import_viem4 = require("viem");
1473
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
1474
+ var MAX_UINT256 = 2n ** 256n - 1n;
1475
+ var ERC20_ALLOWANCE_ABI = [
1476
+ {
1477
+ type: "function",
1478
+ name: "allowance",
1479
+ stateMutability: "view",
1480
+ inputs: [
1481
+ { name: "owner", type: "address" },
1482
+ { name: "spender", type: "address" }
1483
+ ],
1484
+ outputs: [{ name: "", type: "uint256" }]
1485
+ },
1486
+ {
1487
+ type: "function",
1488
+ name: "approve",
1489
+ stateMutability: "nonpayable",
1490
+ inputs: [
1491
+ { name: "spender", type: "address" },
1492
+ { name: "amount", type: "uint256" }
1493
+ ],
1494
+ outputs: [{ name: "", type: "bool" }]
1495
+ },
1496
+ {
1497
+ type: "function",
1498
+ name: "balanceOf",
1499
+ stateMutability: "view",
1500
+ inputs: [{ name: "account", type: "address" }],
1501
+ outputs: [{ name: "", type: "uint256" }]
1502
+ }
1503
+ ];
1504
+ function buildPermitTransferFromTypedData(input) {
1505
+ return {
1506
+ domain: {
1507
+ name: "Permit2",
1508
+ chainId: input.chainId,
1509
+ verifyingContract: PERMIT2_ADDRESS
1510
+ },
1511
+ types: {
1512
+ PermitTransferFrom: [
1513
+ { name: "permitted", type: "TokenPermissions" },
1514
+ { name: "spender", type: "address" },
1515
+ { name: "nonce", type: "uint256" },
1516
+ { name: "deadline", type: "uint256" }
1517
+ ],
1518
+ TokenPermissions: [
1519
+ { name: "token", type: "address" },
1520
+ { name: "amount", type: "uint256" }
1521
+ ]
1522
+ },
1523
+ primaryType: "PermitTransferFrom",
1524
+ message: input.message
1525
+ };
1526
+ }
1527
+ function randomPermit2Nonce() {
1528
+ const bytes = new Uint8Array(32);
1529
+ globalThis.crypto.getRandomValues(bytes);
1530
+ return BigInt((0, import_viem4.bytesToHex)(bytes));
1531
+ }
1532
+ async function readPermit2Allowance(publicClient, token, owner) {
1533
+ return publicClient.readContract({
1534
+ address: token,
1535
+ abi: ERC20_ALLOWANCE_ABI,
1536
+ functionName: "allowance",
1537
+ args: [owner, PERMIT2_ADDRESS]
1538
+ });
1539
+ }
1540
+ async function readErc20Balance(publicClient, token, owner) {
1541
+ return publicClient.readContract({
1542
+ address: token,
1543
+ abi: ERC20_ALLOWANCE_ABI,
1544
+ functionName: "balanceOf",
1545
+ args: [owner]
1546
+ });
1547
+ }
1548
+
2474
1549
  // src/lib/sponsored-deposit.ts
2475
- init_permit2();
2476
1550
  var AUTH_WINDOW_SECONDS = 15 * 60;
2477
1551
  function makeSponsoredDepositCallback(deps) {
2478
1552
  const post = deps.httpPost ?? postSponsorTransferAuth;
@@ -2546,8 +1620,6 @@ function makeSponsoredDepositCallback(deps) {
2546
1620
  }
2547
1621
 
2548
1622
  // src/lib/sponsored-weth-deposit.ts
2549
- init_errors();
2550
- init_permit2();
2551
1623
  var PERMIT_WINDOW_SECONDS = 15 * 60;
2552
1624
  function makeSponsoredWethCallback(deps) {
2553
1625
  const get = deps.httpGet ?? getSponsorRelayerAddress;
@@ -2626,7 +1698,6 @@ function makeSponsoredWethCallback(deps) {
2626
1698
  }
2627
1699
 
2628
1700
  // src/client.ts
2629
- init_permit2();
2630
1701
  function encodeMultiAgentCursor(map) {
2631
1702
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
2632
1703
  }
@@ -2653,11 +1724,10 @@ var SPONSORED_USDC_BY_CHAIN = {
2653
1724
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
2654
1725
  };
2655
1726
  var VIEM_CHAIN2 = {
2656
- 8453: import_chains3.base,
2657
- 42161: import_chains3.arbitrum,
2658
- 1: import_chains3.mainnet
1727
+ 8453: import_chains2.base,
1728
+ 42161: import_chains2.arbitrum,
1729
+ 1: import_chains2.mainnet
2659
1730
  };
2660
- var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
2661
1731
  var SPONSORED_WETH_BY_CHAIN = {
2662
1732
  8453: "0x4200000000000000000000000000000000000006",
2663
1733
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
@@ -2677,26 +1747,17 @@ var OwneySDK = class {
2677
1747
  disabledAgents = /* @__PURE__ */ new Set();
2678
1748
  state = null;
2679
1749
  apiKey;
2680
- // The org's agent policy, fetched once per client. Applied to each agent on
2681
- // activation (ROUT-229). `undefined` means "not fetched yet", `null` means
2682
- // "fetched, and the partner has no policy" — which is a real answer meaning
2683
- // leave every user's agent profile alone.
2684
- orgAgentConfig;
2685
- orgAgentConfigPromise = null;
2686
1750
  zyfaiRpcUrls;
2687
1751
  routingApiBaseUrl;
2688
1752
  referralSource;
2689
- surfliquidApiBaseUrl;
2690
1753
  cachedSponsoredCallback = null;
2691
1754
  cachedWethSponsoredCallback = null;
2692
1755
  initializingAgentsPromise = null;
2693
1756
  constructor(config) {
2694
1757
  this.apiKey = config.apiKey;
2695
- if (config.debug) setOwneyDebug(true);
2696
1758
  this.zyfaiRpcUrls = config.zyfaiRpcUrls;
2697
1759
  this.routingApiBaseUrl = config.routingApiBaseUrl;
2698
1760
  this.referralSource = config.referralSource;
2699
- this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
2700
1761
  }
2701
1762
  /**
2702
1763
  * Establish connection state for all subsequent SDK calls.
@@ -2794,14 +1855,14 @@ var OwneySDK = class {
2794
1855
  // Casts work around viem's chain-narrowed Client vs the generic
2795
1856
  // PublicClient/WalletClient param types — structurally identical at
2796
1857
  // runtime, but the two share a name TS treats as unrelated.
2797
- getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
1858
+ getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
2798
1859
  chain: VIEM_CHAIN2[cid],
2799
- transport: (0, import_viem6.custom)(provider)
1860
+ transport: (0, import_viem5.custom)(provider)
2800
1861
  }),
2801
- getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
1862
+ getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
2802
1863
  account: owner,
2803
1864
  chain: VIEM_CHAIN2[cid],
2804
- transport: (0, import_viem6.custom)(provider)
1865
+ transport: (0, import_viem5.custom)(provider)
2805
1866
  })
2806
1867
  });
2807
1868
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -2827,14 +1888,14 @@ var OwneySDK = class {
2827
1888
  // Casts work around viem's chain-narrowed Client vs the generic
2828
1889
  // PublicClient/WalletClient param types — structurally identical at
2829
1890
  // runtime, but the two share a name TS treats as unrelated.
2830
- getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
1891
+ getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
2831
1892
  chain: VIEM_CHAIN2[cid],
2832
- transport: (0, import_viem6.custom)(provider)
1893
+ transport: (0, import_viem5.custom)(provider)
2833
1894
  }),
2834
- getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
1895
+ getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
2835
1896
  account: owner,
2836
1897
  chain: VIEM_CHAIN2[cid],
2837
- transport: (0, import_viem6.custom)(provider)
1898
+ transport: (0, import_viem5.custom)(provider)
2838
1899
  })
2839
1900
  });
2840
1901
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -2855,57 +1916,14 @@ var OwneySDK = class {
2855
1916
  }
2856
1917
  return active;
2857
1918
  }
2858
- /**
2859
- * Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
2860
- * throws — it degrades to null — so this cannot break activation.
2861
- */
2862
- async getOrgAgentConfig() {
2863
- if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
2864
- if (!this.orgAgentConfigPromise) {
2865
- this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
2866
- (config) => {
2867
- this.orgAgentConfig = config;
2868
- return config;
2869
- }
2870
- );
2871
- }
2872
- return this.orgAgentConfigPromise;
2873
- }
2874
- /**
2875
- * Apply the org policy to one agent, after it has activated.
2876
- *
2877
- * Sequenced after activation rather than alongside it because applying the
2878
- * policy needs the authenticated session activation establishes. Every failure
2879
- * mode is swallowed: a partner's splitting preference is not worth failing a
2880
- * user's connect over.
2881
- */
2882
- async applyOrgPolicyTo(agent, state, chainId) {
2883
- if (!agent.applyOrgPolicy) {
2884
- debugLog(
2885
- "owney-sdk",
2886
- `${agent.id}: no applyOrgPolicy \u2014 agent has no org-level knobs, skipping`
2887
- );
2888
- return;
2889
- }
2890
- try {
2891
- const policy = await this.getOrgAgentConfig();
2892
- if (!policy) return;
2893
- await agent.applyOrgPolicy(state, chainId, policy);
2894
- } catch (error) {
2895
- console.warn(
2896
- `[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
2897
- error instanceof Error ? error.message : String(error)
2898
- );
2899
- }
2900
- }
2901
1919
  async ensureAgentsInitialized() {
2902
1920
  if (this.agents.size > 0) return;
2903
1921
  if (!this.initializingAgentsPromise) {
2904
1922
  this.initializingAgentsPromise = (async () => {
2905
1923
  const agentKeys = await fetchAgentKeys(this.apiKey);
2906
1924
  this.disabledAgents.clear();
2907
- for (const { key: key2, agent_type, project_name, is_enabled } of agentKeys) {
2908
- const agent = await this.createAgent(agent_type, key2, project_name);
1925
+ for (const { key, agent_type, is_enabled } of agentKeys) {
1926
+ const agent = this.createAgent(agent_type, key);
2909
1927
  if (!agent) continue;
2910
1928
  this.agents.set(agent_type, agent);
2911
1929
  if (is_enabled === false) {
@@ -2926,21 +1944,9 @@ var OwneySDK = class {
2926
1944
  this.initializingAgentsPromise = null;
2927
1945
  }
2928
1946
  }
2929
- async createAgent(agentId, key2, projectName) {
1947
+ createAgent(agentId, key) {
2930
1948
  if (agentId === "zyfai") {
2931
- return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
2932
- }
2933
- if (agentId === "surfliquid") {
2934
- if (!projectName) return null;
2935
- const { SurfLiquidAgent: SurfLiquidAgent2 } = await Promise.resolve().then(() => (init_surfliquid_agent(), surfliquid_agent_exports));
2936
- return new SurfLiquidAgent2({
2937
- projectName,
2938
- appId: key2,
2939
- // Same-origin proxy override — SurfLiquid auth is an httpOnly cookie,
2940
- // which WebKit (iOS) discards when it is third-party. See
2941
- // OwneySDKConfig.surfliquidApiBaseUrl.
2942
- apiBaseUrl: this.surfliquidApiBaseUrl
2943
- });
1949
+ return new ZyfaiAgent(key, this.zyfaiRpcUrls, this.referralSource);
2944
1950
  }
2945
1951
  return null;
2946
1952
  }
@@ -2994,7 +2000,6 @@ var OwneySDK = class {
2994
2000
  Promise.all(
2995
2001
  agents.map(async (agent) => {
2996
2002
  await agent.activateAgent(state, chainId);
2997
- await this.applyOrgPolicyTo(agent, state, chainId);
2998
2003
  })
2999
2004
  ).catch((error) => {
3000
2005
  console.error("activateAgent background init failed:", error);
@@ -3022,7 +2027,6 @@ var OwneySDK = class {
3022
2027
  Promise.all(
3023
2028
  enabledCompatible.map(async (agent) => {
3024
2029
  await agent.activateAgent(state, chainId);
3025
- await this.applyOrgPolicyTo(agent, state, chainId);
3026
2030
  })
3027
2031
  ).catch((error) => {
3028
2032
  console.error("activateAgent background init failed:", error);
@@ -3096,30 +2100,18 @@ var OwneySDK = class {
3096
2100
  );
3097
2101
  }
3098
2102
  const agentResults = {};
3099
- const agentErrors = {};
3100
2103
  for (const { agent, amount: agentAmount } of agentAmounts) {
3101
- try {
3102
- agentResults[agent.id] = await this.depositWithFallback(
3103
- agent,
3104
- state,
3105
- chainId,
3106
- agentAmount,
3107
- asset,
3108
- effectiveCallback,
3109
- depositCallback
3110
- );
3111
- } catch (error) {
3112
- agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
3113
- }
3114
- }
3115
- if (Object.keys(agentResults).length === 0) {
3116
- throw new OwneyError(
3117
- "DEPOSIT_ALL_FAILED",
3118
- `All ${agentAmounts.length} agent deposit(s) failed.`,
3119
- { agentErrors }
2104
+ agentResults[agent.id] = await this.depositWithFallback(
2105
+ agent,
2106
+ state,
2107
+ chainId,
2108
+ agentAmount,
2109
+ asset,
2110
+ effectiveCallback,
2111
+ depositCallback
3120
2112
  );
3121
2113
  }
3122
- return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
2114
+ return { agentResults };
3123
2115
  }
3124
2116
  /**
3125
2117
  * Invokes `agent.deposit` with the resolved sponsored callback, composing
@@ -3276,34 +2268,6 @@ var OwneySDK = class {
3276
2268
  }
3277
2269
  return eligible;
3278
2270
  }
3279
- /**
3280
- * Agent ids the routing API provisioned for this org that support the given
3281
- * chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
3282
- * surfliquid first). Returns `[]` when the org has no compatible agent — never
3283
- * throws on an empty org. Loads agent keys on first call (apiKey only, no
3284
- * wallet), so the UI can resolve which agent to use before the user connects.
3285
- *
3286
- * This is the source of truth for agent availability: an agent appears here
3287
- * iff the routing API returned its key. No per-app feature flags.
3288
- */
3289
- async getEligibleAgentIds(chainId, asset) {
3290
- try {
3291
- await this.ensureAgentsInitialized();
3292
- } catch (error) {
3293
- if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
3294
- return [];
3295
- }
3296
- throw error;
3297
- }
3298
- return [...this.agents.values()].filter((agent) => {
3299
- const chainAssets = agent.supportedAssets.find(
3300
- (sa) => sa.chainId === chainId
3301
- );
3302
- return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
3303
- }).map((agent) => agent.id).sort(
3304
- (a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
3305
- );
3306
- }
3307
2271
  // --- Fund operations ---
3308
2272
  /**
3309
2273
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
@@ -3339,17 +2303,9 @@ var OwneySDK = class {
3339
2303
  }
3340
2304
  const eligibleAgents = this.getEligibleAgents(chainId, asset);
3341
2305
  if (!amount) {
3342
- const aggregated2 = await this.getBalances();
3343
- const funded = projectAgentBalancesForAsset(
3344
- eligibleAgents,
3345
- aggregated2.agentBalances,
3346
- chainId,
3347
- asset,
3348
- assetInfo.decimals
3349
- ).filter((b) => b.balance > 0n);
3350
2306
  const results2 = {};
3351
2307
  const agentErrors2 = {};
3352
- for (const { agent } of funded) {
2308
+ for (const agent of eligibleAgents) {
3353
2309
  try {
3354
2310
  results2[agent.id] = await agent.withdraw(state, chainId, token);
3355
2311
  } catch (err) {
@@ -3366,10 +2322,9 @@ var OwneySDK = class {
3366
2322
  { asset, agentErrors: agentErrors2 }
3367
2323
  );
3368
2324
  }
3369
- const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
3370
2325
  return {
3371
2326
  agentResult: results2,
3372
- totalWithdrawn: totalWithdrawn.toString()
2327
+ totalWithdrawn: sumWithdrawnAmount(results2).toString()
3373
2328
  };
3374
2329
  }
3375
2330
  const requested = BigInt(amount);
@@ -3739,10 +2694,10 @@ var OwneySDK = class {
3739
2694
  );
3740
2695
  }
3741
2696
  const provider = this.requireConnectedProvider();
3742
- const wallet = (0, import_viem6.createWalletClient)({
2697
+ const wallet = (0, import_viem5.createWalletClient)({
3743
2698
  account: state.walletAddress,
3744
2699
  chain: VIEM_CHAIN2[chainId],
3745
- transport: (0, import_viem6.custom)(provider)
2700
+ transport: (0, import_viem5.custom)(provider)
3746
2701
  });
3747
2702
  const hash = await wallet.writeContract({
3748
2703
  address: token,
@@ -3752,9 +2707,9 @@ var OwneySDK = class {
3752
2707
  account: state.walletAddress,
3753
2708
  chain: VIEM_CHAIN2[chainId]
3754
2709
  });
3755
- const publicClient = (0, import_viem6.createPublicClient)({
2710
+ const publicClient = (0, import_viem5.createPublicClient)({
3756
2711
  chain: VIEM_CHAIN2[chainId],
3757
- transport: (0, import_viem6.custom)(provider)
2712
+ transport: (0, import_viem5.custom)(provider)
3758
2713
  });
3759
2714
  const receipt = await publicClient.waitForTransactionReceipt({
3760
2715
  hash,
@@ -3862,11 +2817,8 @@ var OwneySDK = class {
3862
2817
  }
3863
2818
  };
3864
2819
 
3865
- // src/index.ts
3866
- init_errors();
3867
-
3868
2820
  // src/agents/zyfai/zyfai.siwx.ts
3869
- var import_viem7 = require("viem");
2821
+ var import_viem6 = require("viem");
3870
2822
  var import_siwe = require("siwe");
3871
2823
  var import_sdk2 = require("@zyfai/sdk");
3872
2824
 
@@ -3889,22 +2841,22 @@ var readLegacySiwxSession = (store, address) => {
3889
2841
  const legacyKeys = [];
3890
2842
  try {
3891
2843
  for (let i = 0; i < store.length; i++) {
3892
- const key2 = store.key(i);
3893
- if (key2?.startsWith(prefix)) legacyKeys.push(key2);
2844
+ const key = store.key(i);
2845
+ if (key?.startsWith(prefix)) legacyKeys.push(key);
3894
2846
  }
3895
2847
  } catch {
3896
2848
  return null;
3897
2849
  }
3898
2850
  let adopted = null;
3899
- for (const key2 of legacyKeys) {
2851
+ for (const key of legacyKeys) {
3900
2852
  if (!adopted) {
3901
2853
  try {
3902
- adopted = JSON.parse(store.getItem(key2) ?? "");
2854
+ adopted = JSON.parse(store.getItem(key) ?? "");
3903
2855
  } catch {
3904
2856
  }
3905
2857
  }
3906
2858
  try {
3907
- store.removeItem(key2);
2859
+ store.removeItem(key);
3908
2860
  } catch {
3909
2861
  }
3910
2862
  }
@@ -3912,11 +2864,11 @@ var readLegacySiwxSession = (store, address) => {
3912
2864
  };
3913
2865
  var readSiwxSession = (address, chainId) => {
3914
2866
  if (typeof window === "undefined") return null;
3915
- const key2 = buildKey2(address);
2867
+ const key = buildKey2(address);
3916
2868
  const store = storage2();
3917
2869
  let raw = null;
3918
2870
  try {
3919
- raw = store?.getItem(key2) ?? null;
2871
+ raw = store?.getItem(key) ?? null;
3920
2872
  } catch {
3921
2873
  raw = null;
3922
2874
  }
@@ -3924,9 +2876,9 @@ var readSiwxSession = (address, chainId) => {
3924
2876
  try {
3925
2877
  return JSON.parse(raw);
3926
2878
  } catch {
3927
- memorySiwxSessions.delete(key2);
2879
+ memorySiwxSessions.delete(key);
3928
2880
  try {
3929
- store?.removeItem(key2);
2881
+ store?.removeItem(key);
3930
2882
  } catch {
3931
2883
  }
3932
2884
  return null;
@@ -3937,24 +2889,24 @@ var readSiwxSession = (address, chainId) => {
3937
2889
  writeSiwxSession(address, chainId, legacy);
3938
2890
  return legacy;
3939
2891
  }
3940
- return memorySiwxSessions.get(key2) ?? null;
2892
+ return memorySiwxSessions.get(key) ?? null;
3941
2893
  };
3942
2894
  var writeSiwxSession = (address, _chainId, session) => {
3943
2895
  if (typeof window === "undefined") return;
3944
- const key2 = buildKey2(address);
3945
- memorySiwxSessions.set(key2, session);
2896
+ const key = buildKey2(address);
2897
+ memorySiwxSessions.set(key, session);
3946
2898
  const store = storage2();
3947
2899
  try {
3948
- store?.setItem(key2, JSON.stringify(session));
2900
+ store?.setItem(key, JSON.stringify(session));
3949
2901
  } catch {
3950
2902
  }
3951
2903
  };
3952
2904
  var clearSiwxSession = (address, _chainId) => {
3953
- const key2 = buildKey2(address);
3954
- memorySiwxSessions.delete(key2);
2905
+ const key = buildKey2(address);
2906
+ memorySiwxSessions.delete(key);
3955
2907
  const store = storage2();
3956
2908
  try {
3957
- store?.removeItem(key2);
2909
+ store?.removeItem(key);
3958
2910
  } catch {
3959
2911
  }
3960
2912
  readLegacySiwxSession(store, address);
@@ -3993,7 +2945,7 @@ function buildSIWXConfig(deps) {
3993
2945
  issuedAt,
3994
2946
  toString() {
3995
2947
  return new import_siwe.SiweMessage({
3996
- address: (0, import_viem7.getAddress)(accountAddress),
2948
+ address: (0, import_viem6.getAddress)(accountAddress),
3997
2949
  chainId: numericChainId(chainId),
3998
2950
  domain,
3999
2951
  uri,
@@ -4084,6 +3036,5 @@ function createOwneySIWX(config) {
4084
3036
  NotConnectedError,
4085
3037
  OwneyError,
4086
3038
  OwneySDK,
4087
- createOwneySIWX,
4088
- setOwneyDebug
3039
+ createOwneySIWX
4089
3040
  });