@owney/sdk 0.7.12-beta.0 → 0.7.12-beta.2

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,14 +3,6 @@ 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 });
@@ -25,645 +17,6 @@ var __copyProps = (to, from, except, desc) => {
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 queryMorpho(query, 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,
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
- return json.data ?? null;
351
- } catch (error) {
352
- console.warn("surfliquid: Morpho vault stats fetch failed", {
353
- vaultAddress,
354
- chainId,
355
- error
356
- });
357
- return null;
358
- }
359
- }
360
- function toStats(name, tvlUsd, liquidityUsd) {
361
- if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
362
- return null;
363
- }
364
- return {
365
- name: typeof name === "string" ? name : null,
366
- tvlUsd,
367
- liquidityUsd
368
- };
369
- }
370
- async function fetchMorphoVaultStats(vaultAddress, chainId) {
371
- const v1 = await queryMorpho(VAULT_STATS_QUERY, vaultAddress, chainId);
372
- const vault = v1?.vaultByAddress;
373
- const v1Stats = toStats(
374
- vault?.name,
375
- vault?.state?.totalAssetsUsd,
376
- vault?.liquidity?.usd
377
- );
378
- if (v1Stats) return v1Stats;
379
- const v2 = await queryMorpho(VAULT_V2_STATS_QUERY, vaultAddress, chainId);
380
- const vaultV2 = v2?.vaultV2ByAddress;
381
- return toStats(vaultV2?.name, vaultV2?.totalAssetsUsd, vaultV2?.liquidityUsd);
382
- }
383
- async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
384
- const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
385
- const entries = await Promise.all(
386
- unique.map(
387
- async (address) => [address, await fetchMorphoVaultStats(address, chainId)]
388
- )
389
- );
390
- const byVault = /* @__PURE__ */ new Map();
391
- for (const [address, stats] of entries) {
392
- if (stats) byVault.set(address, stats);
393
- }
394
- return byVault;
395
- }
396
- var MORPHO_API_URL, VAULT_STATS_QUERY, VAULT_V2_STATS_QUERY;
397
- var init_surfliquid_morpho = __esm({
398
- "src/agents/surfliquid/surfliquid.morpho.ts"() {
399
- "use strict";
400
- MORPHO_API_URL = "https://api.morpho.org/graphql";
401
- VAULT_STATS_QUERY = `
402
- query VaultStats($address: String!, $chainId: Int!) {
403
- vaultByAddress(address: $address, chainId: $chainId) {
404
- name
405
- state { totalAssetsUsd }
406
- liquidity { usd }
407
- }
408
- }
409
- `;
410
- VAULT_V2_STATS_QUERY = `
411
- query VaultV2Stats($address: String!, $chainId: Int!) {
412
- vaultV2ByAddress(address: $address, chainId: $chainId) {
413
- name
414
- totalAssetsUsd
415
- liquidityUsd
416
- }
417
- }
418
- `;
419
- }
420
- });
421
-
422
- // src/agents/surfliquid/surfliquid.agent.ts
423
- var surfliquid_agent_exports = {};
424
- __export(surfliquid_agent_exports, {
425
- SurfLiquidAgent: () => SurfLiquidAgent
426
- });
427
- var import_core_sdk2, import_viem6, import_chains2, APY_WINDOW_KEY2, SurfLiquidAgent;
428
- var init_surfliquid_agent = __esm({
429
- "src/agents/surfliquid/surfliquid.agent.ts"() {
430
- "use strict";
431
- import_core_sdk2 = require("@surf_liquid/core-sdk");
432
- import_viem6 = require("viem");
433
- import_chains2 = require("viem/chains");
434
- init_errors();
435
- init_surfliquid_constants();
436
- init_permit2();
437
- init_surfliquid_mapper();
438
- init_surfliquid_wallet_adapter();
439
- init_surfliquid_morpho();
440
- APY_WINDOW_KEY2 = {
441
- "7D": "apy7d",
442
- "14D": "apy14d",
443
- "30D": "apy30d"
444
- };
445
- SurfLiquidAgent = class {
446
- constructor(config) {
447
- this.config = config;
448
- }
449
- config;
450
- id = "surfliquid";
451
- supportedChainIds = [SURFLIQUID_CHAIN_ID];
452
- supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
453
- surf = null;
454
- connectedAddress = null;
455
- // In-flight connect+auth, shared by concurrent callers to dedupe SIWE.
456
- connectPromise = null;
457
- ensureSurf() {
458
- if (this.surf) return this.surf;
459
- this.surf = import_core_sdk2.SurfClient.create({
460
- projectName: this.config.projectName,
461
- appId: this.config.appId,
462
- environment: "mainnet",
463
- chainId: SURFLIQUID_CHAIN_ID,
464
- apiBaseUrl: this.config.apiBaseUrl,
465
- rpcUrl: this.config.rpcUrl,
466
- // Let the SDK auto-approve USDC to the vault before depositing.
467
- autoApprove: true
468
- });
469
- return this.surf;
470
- }
471
- /**
472
- * Connects + authenticates the SurfClient against owney's provider. Skips the
473
- * SIWE prompt when already authenticated for this wallet (cookie session).
474
- */
475
- async connect(state) {
476
- const surf = this.ensureSurf();
477
- const sameWallet = this.connectedAddress?.toLowerCase() === state.walletAddress.toLowerCase();
478
- if (sameWallet && surf.getAuthState().authenticated) {
479
- return surf;
480
- }
481
- if (this.connectPromise) return this.connectPromise;
482
- this.connectPromise = (async () => {
483
- surf.registerWalletAdapter(
484
- "owney",
485
- new OwneyWalletAdapter(state.provider)
486
- );
487
- await surf.connectWallet("owney");
488
- await surf.authenticate();
489
- this.connectedAddress = state.walletAddress;
490
- return surf;
491
- })();
492
- try {
493
- return await this.connectPromise;
494
- } finally {
495
- this.connectPromise = null;
496
- }
497
- }
498
- /**
499
- * Returns the user's vault address, deploying one on first use. SurfLiquid's
500
- * deposit requires the vault to exist, so this must run before depositing.
501
- * Existing vault → returned as-is; otherwise `deployVault()` is sent
502
- * (user-pays) and the freshly deployed address is returned.
503
- */
504
- async resolveVaultAddress(surf, owner) {
505
- const vault = await surf.getVault(owner).catch(() => null);
506
- if (vault?.exists && vault.userVaultAddress) {
507
- return vault.userVaultAddress;
508
- }
509
- const { vaultAddress } = await surf.deployVault();
510
- return vaultAddress;
511
- }
512
- /**
513
- * Grants the user's vault a standing USDC allowance so SurfLiquid's
514
- * `autoApprove` has nothing to do — see {@link SURFLIQUID_APPROVAL_TARGET}
515
- * for why one prompt per deposit is worth removing.
516
- *
517
- * Fails OPEN on a read error: if the allowance can't be checked we simply
518
- * return and let SurfLiquid's own per-deposit approve run, because a flaky
519
- * RPC must never block a deposit. A failed or rejected APPROVE does
520
- * propagate — the user declined a transaction, and letting SurfLiquid
521
- * immediately ask again for a smaller one is exactly the double prompt this
522
- * removes.
523
- */
524
- async ensureVaultAllowance(state, vaultAddress, amount) {
525
- const spender = vaultAddress;
526
- const transport = (0, import_viem6.custom)(state.provider);
527
- const publicClient = (0, import_viem6.createPublicClient)({ chain: import_chains2.base, transport });
528
- let allowance;
529
- try {
530
- allowance = await publicClient.readContract({
531
- address: SURFLIQUID_USDC_ADDRESS,
532
- abi: ERC20_ALLOWANCE_ABI,
533
- functionName: "allowance",
534
- args: [state.walletAddress, spender]
535
- });
536
- } catch (error) {
537
- console.warn(
538
- "[owney-sdk] SurfLiquid allowance pre-check failed; deferring to its per-deposit approve:",
539
- error instanceof Error ? error.message : String(error)
540
- );
541
- return;
542
- }
543
- if (allowance >= amount) return;
544
- const target = amount > SURFLIQUID_APPROVAL_TARGET ? amount : SURFLIQUID_APPROVAL_TARGET;
545
- const wallet = (0, import_viem6.createWalletClient)({
546
- account: state.walletAddress,
547
- chain: import_chains2.base,
548
- transport
549
- });
550
- const hash = await wallet.writeContract({
551
- address: SURFLIQUID_USDC_ADDRESS,
552
- abi: ERC20_ALLOWANCE_ABI,
553
- functionName: "approve",
554
- args: [spender, target],
555
- account: state.walletAddress,
556
- chain: import_chains2.base
557
- });
558
- const receipt = await publicClient.waitForTransactionReceipt({
559
- hash,
560
- confirmations: 1
561
- });
562
- if (receipt.status !== "success") {
563
- throw new Error(`SurfLiquid USDC approval reverted (tx ${hash})`);
564
- }
565
- }
566
- // --- IAgent: lifecycle ---
567
- async disconnect() {
568
- if (this.surf) {
569
- await this.surf.disconnectWallet();
570
- }
571
- this.connectedAddress = null;
572
- }
573
- async activateAgent(state) {
574
- await this.connect(state);
575
- }
576
- // --- IAgent: funds (user-pays; asset is always USDC, callback ignored) ---
577
- async deposit(state, _chainId, amount, _asset, _depositCallback) {
578
- const surf = await this.connect(state);
579
- const human = (0, import_viem6.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS);
580
- const smartWallet = await this.resolveVaultAddress(
581
- surf,
582
- state.walletAddress
583
- );
584
- await this.ensureVaultAllowance(state, smartWallet, BigInt(amount));
585
- const tx = await surf.deposit({
586
- asset: SURFLIQUID_USDC_ADDRESS,
587
- amount: human
588
- });
589
- await tx.wait();
590
- return { txHash: tx.hash, smartWallet, amount };
591
- }
592
- async withdraw(state, _chainId, _token, amount) {
593
- const surf = await this.connect(state);
594
- const human = amount != null ? (0, import_viem6.formatUnits)(BigInt(amount), SURFLIQUID_USDC_DECIMALS) : void 0;
595
- try {
596
- const tx = await surf.withdraw({
597
- asset: SURFLIQUID_USDC_ADDRESS,
598
- amount: human
599
- });
600
- await tx.wait();
601
- return {
602
- txHash: tx.hash,
603
- type: amount != null ? "partial" : "full",
604
- amount: amount ?? "0"
605
- };
606
- } catch (error) {
607
- throw new OwneyError(
608
- "WITHDRAW_FAILED",
609
- error instanceof Error ? error.message : "SurfLiquid withdraw failed.",
610
- { chainId: SURFLIQUID_CHAIN_ID, amount },
611
- this.id
612
- );
613
- }
614
- }
615
- // --- IAgent: portfolio reads ---
616
- async getBalances(state, chainId) {
617
- const surf = await this.connect(state);
618
- const vault = await surf.getVault(state.walletAddress);
619
- const morphoVaultAddresses = (vault.assets ?? []).filter((asset) => asset.assetSymbol === "USDC" && asset.chainId === chainId).map((asset) => asset.morphoVaultAddress).filter((address) => Boolean(address));
620
- const morphoStats = await fetchMorphoStatsByVault(
621
- morphoVaultAddresses,
622
- chainId
623
- );
624
- return mapBalances2(vault, chainId, morphoStats);
625
- }
626
- async getEarnings(state) {
627
- const surf = await this.connect(state);
628
- const vault = await surf.getVault(state.walletAddress);
629
- return mapEarnings2(vault, vault.userVaultAddress ?? state.walletAddress);
630
- }
631
- async getAccountApy(state, _chainId, days, _tokenSymbol) {
632
- const surf = await this.connect(state);
633
- const vault = await surf.getVault(state.walletAddress);
634
- return mapAccountApy(vault, days);
635
- }
636
- async getHistory(state, chainId, options) {
637
- const surf = await this.connect(state);
638
- const page = options?.cursor ? Number(options.cursor) : 1;
639
- const limit = options?.limit ?? 10;
640
- const result = await surf.getAgentMessages(
641
- state.walletAddress,
642
- page,
643
- limit,
644
- options?.fromDate,
645
- options?.toDate
646
- );
647
- return mapHistory(result, chainId);
648
- }
649
- async getUserProfile(state) {
650
- const surf = await this.connect(state);
651
- const vault = await surf.getVault(state.walletAddress);
652
- return mapUserProfile2(vault, state.walletAddress);
653
- }
654
- // --- IAgent: discovery (no wallet) ---
655
- async getAgentApy(days, _options) {
656
- const surf = this.ensureSurf();
657
- const assets = await surf.getSupportedAssets(SURFLIQUID_CHAIN_ID);
658
- const usdc = assets.find((asset) => asset.assetSymbol === "USDC");
659
- if (!usdc) return { averageApy: 0 };
660
- const windowed = usdc[APY_WINDOW_KEY2[days]];
661
- return { averageApy: windowed != null ? windowed : usdc.currentAPY };
662
- }
663
- };
664
- }
665
- });
666
-
667
20
  // src/index.ts
668
21
  var index_exports = {};
669
22
  __export(index_exports, {
@@ -736,8 +89,56 @@ var SupportedAssets = [
736
89
  }
737
90
  ];
738
91
 
92
+ // src/errors.ts
93
+ var OwneyError = class extends Error {
94
+ code;
95
+ details;
96
+ agentId;
97
+ constructor(code, message, details, agentId) {
98
+ const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
99
+ super(`${prefix} ${message}`);
100
+ this.name = "OwneyError";
101
+ this.code = code;
102
+ this.details = details;
103
+ this.agentId = agentId;
104
+ }
105
+ };
106
+ var AgentNotFoundError = class extends OwneyError {
107
+ constructor(agentId, available) {
108
+ super(
109
+ "AGENT_NOT_FOUND",
110
+ `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
111
+ { agentId, available },
112
+ agentId
113
+ );
114
+ this.name = "AgentNotFoundError";
115
+ }
116
+ };
117
+ var NotConnectedError = class extends OwneyError {
118
+ constructor() {
119
+ super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
120
+ this.name = "NotConnectedError";
121
+ }
122
+ };
123
+ var AgentChainIncompatibleError = class extends OwneyError {
124
+ incompatibleAgents;
125
+ connectedChainId;
126
+ constructor(incompatibleAgents, connectedChainId) {
127
+ const details = incompatibleAgents.map(
128
+ ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
129
+ ).join("; ");
130
+ super(
131
+ "AGENT_CHAIN_INCOMPATIBLE",
132
+ `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
133
+ { incompatibleAgents, connectedChainId }
134
+ );
135
+ this.name = "AgentChainIncompatibleError";
136
+ this.incompatibleAgents = incompatibleAgents;
137
+ this.connectedChainId = connectedChainId;
138
+ }
139
+ };
140
+
739
141
  // src/lib/utils.ts
740
- init_errors();
741
142
  var isValidChainId = (chainId) => {
742
143
  if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
743
144
  throw new OwneyError(
@@ -748,12 +149,6 @@ var isValidChainId = (chainId) => {
748
149
  }
749
150
  return chainId;
750
151
  };
751
- function isSameAsset(tokenSymbol, asset) {
752
- const token = tokenSymbol.toLowerCase();
753
- const target = asset.toLowerCase();
754
- if (token === target) return true;
755
- return target === "weth" && token === "eth" || target === "eth" && token === "weth";
756
- }
757
152
  function hexToDecimal(hex, decimals = 6) {
758
153
  const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
759
154
  const parsed = BigInt(normalized);
@@ -787,10 +182,6 @@ var DECIMALS_BY_SYMBOL = {
787
182
  wbtc: 8,
788
183
  cbbtc: 8
789
184
  };
790
- function canonicalSymbol(symbol) {
791
- const upper = symbol.toUpperCase();
792
- return upper === "ETH" ? "WETH" : upper;
793
- }
794
185
  function tokenDecimals(symbol, explicit) {
795
186
  if (typeof explicit === "number" && Number.isFinite(explicit))
796
187
  return explicit;
@@ -855,89 +246,55 @@ function mapPendingAllocations(raw) {
855
246
  function mapBalances(raw, _chainId, smartWallet) {
856
247
  const portfolio = raw.portfolio;
857
248
  const portfolioByChain = portfolio.portfolioByChain ?? {};
858
- const rawPositions = portfolio.positions ?? [];
859
- const detailByKey = /* @__PURE__ */ new Map();
860
- for (const p of rawPositions) {
861
- const cid = resolveChainId(p.chain ?? "");
862
- const symbol = canonicalSymbol(p.token_symbol ?? "");
863
- if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
864
- }
865
249
  let totalBalance = 0;
866
250
  const tokens = [];
867
- const positions = [];
868
251
  for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
869
252
  const positionChainId = Number(chainIdKey);
870
- const chainName2 = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
871
253
  for (const [
872
254
  symbol,
873
255
  { balance, balanceWithFee, decimals }
874
256
  ] of Object.entries(tokensBySymbol ?? {})) {
875
- const amount = hexToDecimal(
876
- balanceWithFee ?? balance ?? "0",
877
- tokenDecimals(symbol, decimals)
878
- );
257
+ const amount = hexToDecimal(balanceWithFee ?? balance ?? "0", decimals);
879
258
  totalBalance += amount;
880
259
  tokens.push({
881
- chain: chainName2,
260
+ chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
882
261
  chainId: positionChainId,
883
262
  asset: symbol,
884
263
  amount: String(amount)
885
264
  });
886
- const detail = detailByKey.get(
887
- `${positionChainId}:${canonicalSymbol(symbol)}`
888
- );
889
- positions.push({
890
- chain: chainName2,
891
- protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
892
- protocolId: detail?.protocol_id,
893
- pool: detail?.pool,
894
- // Report the token the way the rest of owney spells it ("WETH", as the
895
- // pre-portfolioByChain mapper did), not Zyfai's internal "eth".
896
- asset: canonicalSymbol(symbol),
897
- amount: String(amount),
898
- apy: detail?.pool_apy,
899
- tvl: detail?.pool_tvl,
900
- // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
901
- // structural read keeps it undefined today and auto-populates later.
902
- liquidity: detail?.liquidity
903
- });
904
265
  }
905
266
  }
906
- if (positions.length === 0) {
907
- positions.push(
908
- ...(portfolio.positions ?? []).map((p) => ({
909
- chain: p.chain ?? "",
910
- protocol: p.protocol_name ?? p.protocol_id ?? "",
911
- protocolId: p.protocol_id,
912
- pool: p.pool,
913
- asset: p.token_symbol ?? "",
914
- // Fee-adjusted underlying amounts are decimal base-unit strings; the
915
- // legacy `amount` fallback is hex. Runtime getBalances payloads often
916
- // carry `decimals` (e.g. 18 for WETH) — prefer it when present,
917
- // otherwise fall back to the per-symbol lookup.
918
- amount: String(
919
- p.underlyingAmountWithFee ?? p.underlyingAmount ? normalizeDecimalPlace(
920
- p.underlyingAmountWithFee ?? p.underlyingAmount ?? "0",
921
- tokenDecimals(
922
- p.token_symbol,
923
- p.decimals
924
- )
925
- ) : hexToDecimal(
926
- p.amount || "0",
927
- tokenDecimals(
928
- p.token_symbol,
929
- p.decimals
930
- )
931
- )
932
- ),
933
- apy: p.pool_apy,
934
- tvl: p.pool_tvl,
935
- // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
936
- // structural read keeps it undefined today and auto-populates later.
937
- liquidity: p.liquidity
938
- }))
939
- );
940
- }
267
+ const positions = (portfolio.positions ?? []).map((p) => ({
268
+ chain: p.chain ?? "",
269
+ protocol: p.protocol_name ?? p.protocol_id ?? "",
270
+ protocolId: p.protocol_id,
271
+ pool: p.pool,
272
+ asset: p.token_symbol ?? "",
273
+ // Fee-adjusted underlying amounts are decimal base-unit strings. The
274
+ // legacy `amount` fallback is hex. Runtime
275
+ // getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
276
+ // when present, otherwise fall back to the per-symbol lookup.
277
+ amount: String(
278
+ p.underlyingAmountWithFee ?? p.underlyingAmount ? normalizeDecimalPlace(
279
+ p.underlyingAmountWithFee ?? p.underlyingAmount ?? "0",
280
+ tokenDecimals(
281
+ p.token_symbol,
282
+ p.decimals
283
+ )
284
+ ) : hexToDecimal(
285
+ p.amount || "0",
286
+ tokenDecimals(
287
+ p.token_symbol,
288
+ p.decimals
289
+ )
290
+ )
291
+ ),
292
+ apy: p.pool_apy,
293
+ tvl: p.pool_tvl,
294
+ // PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
295
+ // structural read keeps it undefined today and auto-populates later.
296
+ liquidity: p.liquidity
297
+ }));
941
298
  const pendingAllocations = mapPendingAllocations(
942
299
  portfolio.staleBalances
943
300
  );
@@ -1232,9 +589,6 @@ function decodeHistoryCursor(token) {
1232
589
  return parsed;
1233
590
  }
1234
591
 
1235
- // src/agents/zyfai/zyfai.agent.ts
1236
- init_errors();
1237
-
1238
592
  // src/agents/zyfai/zyfai.auth-cache.ts
1239
593
  var KEY_PREFIX = "owney.zyfai.session";
1240
594
  var storage = () => {
@@ -2023,37 +1377,6 @@ var ZyfaiAgent = class _ZyfaiAgent {
2023
1377
  );
2024
1378
  }
2025
1379
  }
2026
- /**
2027
- * Records the deposit with Zyfai, retrying transient failures.
2028
- *
2029
- * This runs AFTER the transfer has already landed on-chain, so it must never
2030
- * fail the deposit — the funds moved. But it is also the ONLY source of the
2031
- * "Top up wallet" entry the history is built from: Zyfai auto-deploys the
2032
- * balance it detects either way, so when this call is lost the user's deposit
2033
- * never appears in Activity (an earlier withdrawal stays the newest row) and
2034
- * nothing ever backfills it. Retry, then log loudly enough to be recoverable.
2035
- */
2036
- async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
2037
- const ATTEMPTS = 3;
2038
- const RETRY_DELAY_MS = 1e3;
2039
- for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
2040
- try {
2041
- await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
2042
- return;
2043
- } catch (logError) {
2044
- if (attempt === ATTEMPTS) {
2045
- console.error(
2046
- "[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
2047
- { txHash, chainId, amount, tokenAddress, error: logError }
2048
- );
2049
- return;
2050
- }
2051
- await new Promise(
2052
- (resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
2053
- );
2054
- }
2055
- }
2056
- }
2057
1380
  /**
2058
1381
  * True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
2059
1382
  * to this EOA — the "new wallet" kind that is predeployed on the chains it
@@ -2357,12 +1680,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
2357
1680
  );
2358
1681
  const txHash = await depositCallback(smartWallet, validChainId, amount);
2359
1682
  const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
2360
- await this.logDepositWithRetry(
2361
- validChainId,
2362
- txHash,
2363
- amount,
2364
- tokenAddress
2365
- );
1683
+ try {
1684
+ await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
1685
+ } catch (logError) {
1686
+ console.warn(
1687
+ "[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
1688
+ logError
1689
+ );
1690
+ }
2366
1691
  return { txHash, smartWallet, amount };
2367
1692
  }
2368
1693
  await this.ensureWalletDeployed(this.getAddress(), validChainId);
@@ -2543,11 +1868,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2543
1868
  }
2544
1869
  };
2545
1870
 
2546
- // src/client.ts
2547
- init_errors();
2548
-
2549
1871
  // src/lib/routing-api.ts
2550
- init_errors();
2551
1872
  var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2552
1873
  async function fetchOrgAgentConfig(apiKey) {
2553
1874
  const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
@@ -2612,7 +1933,6 @@ async function fetchAgentKeys(apiKey) {
2612
1933
  }
2613
1934
 
2614
1935
  // src/lib/health-report.ts
2615
- init_errors();
2616
1936
  var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2617
1937
  async function reportAgentFailure(apiKey, agentType, errorCode) {
2618
1938
  try {
@@ -2648,10 +1968,11 @@ async function withFailureReporting(apiKey, agentType, fn) {
2648
1968
  // src/lib/helpers/withdraw-helper.ts
2649
1969
  var import_viem2 = require("viem");
2650
1970
  function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
1971
+ const target = asset.toUpperCase();
2651
1972
  return agents.map((agent) => {
2652
1973
  const agentBalance = aggregated[agent.id];
2653
1974
  const tokenBalance = agentBalance?.tokens.find(
2654
- (t) => t.chainId === chainId && isSameAsset(t.asset, asset)
1975
+ (t) => t.chainId === chainId && t.asset.toUpperCase() === target
2655
1976
  );
2656
1977
  if (!tokenBalance) return { agent, balance: 0n };
2657
1978
  return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
@@ -2761,11 +2082,8 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
2761
2082
  }
2762
2083
 
2763
2084
  // src/client.ts
2764
- var import_viem7 = require("viem");
2765
- var import_chains3 = require("viem/chains");
2766
-
2767
- // src/lib/sponsored-deposit.ts
2768
- init_errors();
2085
+ var import_viem6 = require("viem");
2086
+ var import_chains2 = require("viem/chains");
2769
2087
 
2770
2088
  // src/lib/transfer-auth.ts
2771
2089
  var import_viem3 = require("viem");
@@ -2804,13 +2122,12 @@ function randomAuthNonce() {
2804
2122
  }
2805
2123
 
2806
2124
  // src/lib/sponsor-client.ts
2807
- init_errors();
2808
2125
  var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2809
2126
  async function postSponsorTransferAuth(input) {
2810
- const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2127
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2811
2128
  let res;
2812
2129
  try {
2813
- res = await fetch(`${base4}/api/v1/sponsor/erc20-transfer-auth`, {
2130
+ res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2814
2131
  method: "POST",
2815
2132
  headers: {
2816
2133
  "content-type": "application/json",
@@ -2847,10 +2164,10 @@ async function postSponsorTransferAuth(input) {
2847
2164
  return parsed.data;
2848
2165
  }
2849
2166
  async function postSponsorPermit2Transfer(input) {
2850
- const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2167
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2851
2168
  let res;
2852
2169
  try {
2853
- res = await fetch(`${base4}/api/v1/sponsor/permit2-transfer`, {
2170
+ res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2854
2171
  method: "POST",
2855
2172
  headers: {
2856
2173
  "content-type": "application/json",
@@ -2885,11 +2202,11 @@ async function postSponsorPermit2Transfer(input) {
2885
2202
  return parsed.data;
2886
2203
  }
2887
2204
  async function getSponsorRelayerAddress(input) {
2888
- const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2205
+ const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2889
2206
  let res;
2890
2207
  try {
2891
2208
  res = await fetch(
2892
- `${base4}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2209
+ `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2893
2210
  {
2894
2211
  headers: { "x-owney-api-key": input.apiKey }
2895
2212
  }
@@ -2921,11 +2238,85 @@ async function getSponsorRelayerAddress(input) {
2921
2238
  return parsed.data.relayer;
2922
2239
  }
2923
2240
 
2924
- // src/lib/sponsored-deposit.ts
2925
- init_permit2();
2241
+ // src/lib/permit2.ts
2242
+ var import_viem4 = require("viem");
2243
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2244
+ var MAX_UINT256 = 2n ** 256n - 1n;
2245
+ var ERC20_ALLOWANCE_ABI = [
2246
+ {
2247
+ type: "function",
2248
+ name: "allowance",
2249
+ stateMutability: "view",
2250
+ inputs: [
2251
+ { name: "owner", type: "address" },
2252
+ { name: "spender", type: "address" }
2253
+ ],
2254
+ outputs: [{ name: "", type: "uint256" }]
2255
+ },
2256
+ {
2257
+ type: "function",
2258
+ name: "approve",
2259
+ stateMutability: "nonpayable",
2260
+ inputs: [
2261
+ { name: "spender", type: "address" },
2262
+ { name: "amount", type: "uint256" }
2263
+ ],
2264
+ outputs: [{ name: "", type: "bool" }]
2265
+ },
2266
+ {
2267
+ type: "function",
2268
+ name: "balanceOf",
2269
+ stateMutability: "view",
2270
+ inputs: [{ name: "account", type: "address" }],
2271
+ outputs: [{ name: "", type: "uint256" }]
2272
+ }
2273
+ ];
2274
+ function buildPermitTransferFromTypedData(input) {
2275
+ return {
2276
+ domain: {
2277
+ name: "Permit2",
2278
+ chainId: input.chainId,
2279
+ verifyingContract: PERMIT2_ADDRESS
2280
+ },
2281
+ types: {
2282
+ PermitTransferFrom: [
2283
+ { name: "permitted", type: "TokenPermissions" },
2284
+ { name: "spender", type: "address" },
2285
+ { name: "nonce", type: "uint256" },
2286
+ { name: "deadline", type: "uint256" }
2287
+ ],
2288
+ TokenPermissions: [
2289
+ { name: "token", type: "address" },
2290
+ { name: "amount", type: "uint256" }
2291
+ ]
2292
+ },
2293
+ primaryType: "PermitTransferFrom",
2294
+ message: input.message
2295
+ };
2296
+ }
2297
+ function randomPermit2Nonce() {
2298
+ const bytes = new Uint8Array(32);
2299
+ globalThis.crypto.getRandomValues(bytes);
2300
+ return BigInt((0, import_viem4.bytesToHex)(bytes));
2301
+ }
2302
+ async function readPermit2Allowance(publicClient, token, owner) {
2303
+ return publicClient.readContract({
2304
+ address: token,
2305
+ abi: ERC20_ALLOWANCE_ABI,
2306
+ functionName: "allowance",
2307
+ args: [owner, PERMIT2_ADDRESS]
2308
+ });
2309
+ }
2310
+ async function readErc20Balance(publicClient, token, owner) {
2311
+ return publicClient.readContract({
2312
+ address: token,
2313
+ abi: ERC20_ALLOWANCE_ABI,
2314
+ functionName: "balanceOf",
2315
+ args: [owner]
2316
+ });
2317
+ }
2926
2318
 
2927
2319
  // src/lib/chain-guard.ts
2928
- init_errors();
2929
2320
  var CHAIN_NAMES = {
2930
2321
  1: "Ethereum",
2931
2322
  8453: "Base",
@@ -3039,8 +2430,6 @@ function makeSponsoredDepositCallback(deps) {
3039
2430
  }
3040
2431
 
3041
2432
  // src/lib/sponsored-weth-deposit.ts
3042
- init_errors();
3043
- init_permit2();
3044
2433
  var PERMIT_WINDOW_SECONDS = 15 * 60;
3045
2434
  function makeSponsoredWethCallback(deps) {
3046
2435
  const get = deps.httpGet ?? getSponsorRelayerAddress;
@@ -3125,7 +2514,6 @@ function makeSponsoredWethCallback(deps) {
3125
2514
 
3126
2515
  // src/lib/sponsored-calls-deposit.ts
3127
2516
  var import_viem5 = require("viem");
3128
- init_errors();
3129
2517
  var DEFAULT_POLL_INTERVAL_MS = 1500;
3130
2518
  var DEFAULT_MAX_POLLS = 30;
3131
2519
  async function paymasterSupported(provider, owner, chainId) {
@@ -3216,7 +2604,6 @@ function makeSponsoredCallsCallback(deps) {
3216
2604
  }
3217
2605
 
3218
2606
  // src/client.ts
3219
- init_permit2();
3220
2607
  function encodeMultiAgentCursor(map) {
3221
2608
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
3222
2609
  }
@@ -3243,11 +2630,10 @@ var SPONSORED_USDC_BY_CHAIN = {
3243
2630
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
3244
2631
  };
3245
2632
  var VIEM_CHAIN2 = {
3246
- 8453: import_chains3.base,
3247
- 42161: import_chains3.arbitrum,
3248
- 1: import_chains3.mainnet
2633
+ 8453: import_chains2.base,
2634
+ 42161: import_chains2.arbitrum,
2635
+ 1: import_chains2.mainnet
3249
2636
  };
3250
- var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
3251
2637
  var SPONSORED_WETH_BY_CHAIN = {
3252
2638
  8453: "0x4200000000000000000000000000000000000006",
3253
2639
  42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
@@ -3276,7 +2662,6 @@ var OwneySDK = class {
3276
2662
  zyfaiRpcUrls;
3277
2663
  routingApiBaseUrl;
3278
2664
  referralSource;
3279
- surfliquidApiBaseUrl;
3280
2665
  cachedSponsoredCallback = null;
3281
2666
  cachedWethSponsoredCallback = null;
3282
2667
  paymasterServiceUrl;
@@ -3289,7 +2674,6 @@ var OwneySDK = class {
3289
2674
  this.routingApiBaseUrl = config.routingApiBaseUrl;
3290
2675
  this.paymasterServiceUrl = config.paymasterServiceUrl;
3291
2676
  this.referralSource = config.referralSource;
3292
- this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
3293
2677
  }
3294
2678
  /**
3295
2679
  * Establish connection state for all subsequent SDK calls.
@@ -3389,14 +2773,14 @@ var OwneySDK = class {
3389
2773
  // Casts work around viem's chain-narrowed Client vs the generic
3390
2774
  // PublicClient/WalletClient param types — structurally identical at
3391
2775
  // runtime, but the two share a name TS treats as unrelated.
3392
- getPublicClient: (cid) => (0, import_viem7.createPublicClient)({
2776
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
3393
2777
  chain: VIEM_CHAIN2[cid],
3394
- transport: (0, import_viem7.custom)(provider)
2778
+ transport: (0, import_viem6.custom)(provider)
3395
2779
  }),
3396
- getWalletClient: (cid) => (0, import_viem7.createWalletClient)({
2780
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
3397
2781
  account: owner,
3398
2782
  chain: VIEM_CHAIN2[cid],
3399
- transport: (0, import_viem7.custom)(provider)
2783
+ transport: (0, import_viem6.custom)(provider)
3400
2784
  })
3401
2785
  });
3402
2786
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -3442,14 +2826,14 @@ var OwneySDK = class {
3442
2826
  // Casts work around viem's chain-narrowed Client vs the generic
3443
2827
  // PublicClient/WalletClient param types — structurally identical at
3444
2828
  // runtime, but the two share a name TS treats as unrelated.
3445
- getPublicClient: (cid) => (0, import_viem7.createPublicClient)({
2829
+ getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
3446
2830
  chain: VIEM_CHAIN2[cid],
3447
- transport: (0, import_viem7.custom)(provider)
2831
+ transport: (0, import_viem6.custom)(provider)
3448
2832
  }),
3449
- getWalletClient: (cid) => (0, import_viem7.createWalletClient)({
2833
+ getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
3450
2834
  account: owner,
3451
2835
  chain: VIEM_CHAIN2[cid],
3452
- transport: (0, import_viem7.custom)(provider)
2836
+ transport: (0, import_viem6.custom)(provider)
3453
2837
  })
3454
2838
  });
3455
2839
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -3519,8 +2903,8 @@ var OwneySDK = class {
3519
2903
  this.initializingAgentsPromise = (async () => {
3520
2904
  const agentKeys = await fetchAgentKeys(this.apiKey);
3521
2905
  this.disabledAgents.clear();
3522
- for (const { key: key2, agent_type, project_name, is_enabled } of agentKeys) {
3523
- const agent = await this.createAgent(agent_type, key2, project_name);
2906
+ for (const { key: key2, agent_type, is_enabled } of agentKeys) {
2907
+ const agent = this.createAgent(agent_type, key2);
3524
2908
  if (!agent) continue;
3525
2909
  this.agents.set(agent_type, agent);
3526
2910
  if (is_enabled === false) {
@@ -3541,22 +2925,10 @@ var OwneySDK = class {
3541
2925
  this.initializingAgentsPromise = null;
3542
2926
  }
3543
2927
  }
3544
- async createAgent(agentId, key2, projectName) {
2928
+ createAgent(agentId, key2) {
3545
2929
  if (agentId === "zyfai") {
3546
2930
  return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
3547
2931
  }
3548
- if (agentId === "surfliquid") {
3549
- if (!projectName) return null;
3550
- const { SurfLiquidAgent: SurfLiquidAgent2 } = await Promise.resolve().then(() => (init_surfliquid_agent(), surfliquid_agent_exports));
3551
- return new SurfLiquidAgent2({
3552
- projectName,
3553
- appId: key2,
3554
- // Same-origin proxy override — SurfLiquid auth is an httpOnly cookie,
3555
- // which WebKit (iOS) discards when it is third-party. See
3556
- // OwneySDKConfig.surfliquidApiBaseUrl.
3557
- apiBaseUrl: this.surfliquidApiBaseUrl
3558
- });
3559
- }
3560
2932
  return null;
3561
2933
  }
3562
2934
  // --- Account lifecycle ---
@@ -3606,12 +2978,7 @@ var OwneySDK = class {
3606
2978
  this.activeAgents.add(id);
3607
2979
  }
3608
2980
  state.chainId = chainId;
3609
- Promise.all(
3610
- agents.map(async (agent) => {
3611
- await agent.activateAgent(state, chainId);
3612
- await this.applyOrgPolicyTo(agent, state, chainId);
3613
- })
3614
- ).catch((error) => {
2981
+ this.activateAgentsInTurn(agents, state, chainId).catch((error) => {
3615
2982
  console.error("activateAgent background init failed:", error);
3616
2983
  });
3617
2984
  return;
@@ -3634,14 +3001,48 @@ var OwneySDK = class {
3634
3001
  const enabledCompatible = compatible.filter(
3635
3002
  (agent) => !this.isAgentDisabled(agent.id)
3636
3003
  );
3637
- Promise.all(
3638
- enabledCompatible.map(async (agent) => {
3004
+ this.activateAgentsInTurn(enabledCompatible, state, chainId).catch(
3005
+ (error) => {
3006
+ console.error("activateAgent background init failed:", error);
3007
+ }
3008
+ );
3009
+ }
3010
+ /**
3011
+ * Activate agents ONE AT A TIME, each followed by its org policy.
3012
+ *
3013
+ * Every agent opens its activation with its own wallet signature, each
3014
+ * exchanged for that agent's own backend session — Zyfai's SIWX for a JWT,
3015
+ * Sail's SIWE. Run in parallel, that puts two `personal_sign` requests on one
3016
+ * wallet connection in the same instant. Over WalletConnect both are
3017
+ * delivered to the wallet, which renders one signing request at a time and
3018
+ * queues or silently drops the other: neither promise settles, so activation
3019
+ * hangs until the caller's timeout with no prompt the user can act on. The
3020
+ * single-agent era never hit this — there was no second prompt to collide
3021
+ * with — so it appeared the moment a second agent became eligible.
3022
+ *
3023
+ * Serializing costs no real wall-clock: the user can only approve one prompt
3024
+ * at a time anyway.
3025
+ *
3026
+ * Every agent is attempted even if an earlier one fails, so one declined
3027
+ * signature can't deny the remaining agents their turn. The first failure is
3028
+ * rethrown (matching the previous `Promise.all` rejection) once all agents
3029
+ * have had a chance to activate.
3030
+ */
3031
+ async activateAgentsInTurn(agents, state, chainId) {
3032
+ let firstError = null;
3033
+ for (const agent of agents) {
3034
+ try {
3639
3035
  await agent.activateAgent(state, chainId);
3640
3036
  await this.applyOrgPolicyTo(agent, state, chainId);
3641
- })
3642
- ).catch((error) => {
3643
- console.error("activateAgent background init failed:", error);
3644
- });
3037
+ } catch (error) {
3038
+ if (firstError === null) {
3039
+ firstError = error;
3040
+ } else {
3041
+ console.error(`activateAgent(${agent.id}) failed:`, error);
3042
+ }
3043
+ }
3044
+ }
3045
+ if (firstError !== null) throw firstError;
3645
3046
  }
3646
3047
  /**
3647
3048
  * Deposit funds into a specific agent, or split equally across all agents if agentId is omitted.
@@ -3711,30 +3112,18 @@ var OwneySDK = class {
3711
3112
  );
3712
3113
  }
3713
3114
  const agentResults = {};
3714
- const agentErrors = {};
3715
3115
  for (const { agent, amount: agentAmount } of agentAmounts) {
3716
- try {
3717
- agentResults[agent.id] = await this.depositWithFallback(
3718
- agent,
3719
- state,
3720
- chainId,
3721
- agentAmount,
3722
- asset,
3723
- effectiveCallback,
3724
- depositCallback
3725
- );
3726
- } catch (error) {
3727
- agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
3728
- }
3729
- }
3730
- if (Object.keys(agentResults).length === 0) {
3731
- throw new OwneyError(
3732
- "DEPOSIT_ALL_FAILED",
3733
- `All ${agentAmounts.length} agent deposit(s) failed.`,
3734
- { agentErrors }
3116
+ agentResults[agent.id] = await this.depositWithFallback(
3117
+ agent,
3118
+ state,
3119
+ chainId,
3120
+ agentAmount,
3121
+ asset,
3122
+ effectiveCallback,
3123
+ depositCallback
3735
3124
  );
3736
3125
  }
3737
- return Object.keys(agentErrors).length > 0 ? { agentResults, agentErrors } : { agentResults };
3126
+ return { agentResults };
3738
3127
  }
3739
3128
  /**
3740
3129
  * Invokes `agent.deposit` with the resolved sponsored callback, composing
@@ -3850,8 +3239,9 @@ var OwneySDK = class {
3850
3239
  async hasExistingBalance(agent, state, chainId, asset) {
3851
3240
  try {
3852
3241
  const balance = await agent.getBalances(state, chainId);
3242
+ const target = asset.toLowerCase();
3853
3243
  const token = balance.tokens.find(
3854
- (t) => t.chainId === chainId && isSameAsset(t.asset, asset)
3244
+ (t) => t.chainId === chainId && t.asset.toLowerCase() === target
3855
3245
  );
3856
3246
  return !!token && Number(token.amount) > 0;
3857
3247
  } catch {
@@ -3890,34 +3280,6 @@ var OwneySDK = class {
3890
3280
  }
3891
3281
  return eligible;
3892
3282
  }
3893
- /**
3894
- * Agent ids the routing API provisioned for this org that support the given
3895
- * chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
3896
- * surfliquid first). Returns `[]` when the org has no compatible agent — never
3897
- * throws on an empty org. Loads agent keys on first call (apiKey only, no
3898
- * wallet), so the UI can resolve which agent to use before the user connects.
3899
- *
3900
- * This is the source of truth for agent availability: an agent appears here
3901
- * iff the routing API returned its key. No per-app feature flags.
3902
- */
3903
- async getEligibleAgentIds(chainId, asset) {
3904
- try {
3905
- await this.ensureAgentsInitialized();
3906
- } catch (error) {
3907
- if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
3908
- return [];
3909
- }
3910
- throw error;
3911
- }
3912
- return [...this.agents.values()].filter((agent) => {
3913
- const chainAssets = agent.supportedAssets.find(
3914
- (sa) => sa.chainId === chainId
3915
- );
3916
- return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
3917
- }).map((agent) => agent.id).sort(
3918
- (a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
3919
- );
3920
- }
3921
3283
  // --- Fund operations ---
3922
3284
  /**
3923
3285
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
@@ -3953,17 +3315,9 @@ var OwneySDK = class {
3953
3315
  }
3954
3316
  const eligibleAgents = this.getEligibleAgents(chainId, asset);
3955
3317
  if (!amount) {
3956
- const aggregated2 = await this.getBalances();
3957
- const funded = projectAgentBalancesForAsset(
3958
- eligibleAgents,
3959
- aggregated2.agentBalances,
3960
- chainId,
3961
- asset,
3962
- assetInfo.decimals
3963
- ).filter((b) => b.balance > 0n);
3964
3318
  const results2 = {};
3965
3319
  const agentErrors2 = {};
3966
- for (const { agent } of funded) {
3320
+ for (const agent of eligibleAgents) {
3967
3321
  try {
3968
3322
  results2[agent.id] = await agent.withdraw(state, chainId, token);
3969
3323
  } catch (err) {
@@ -3980,10 +3334,9 @@ var OwneySDK = class {
3980
3334
  { asset, agentErrors: agentErrors2 }
3981
3335
  );
3982
3336
  }
3983
- const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
3984
3337
  return {
3985
3338
  agentResult: results2,
3986
- totalWithdrawn: totalWithdrawn.toString()
3339
+ totalWithdrawn: sumWithdrawnAmount(results2).toString()
3987
3340
  };
3988
3341
  }
3989
3342
  const requested = BigInt(amount);
@@ -4375,10 +3728,10 @@ var OwneySDK = class {
4375
3728
  );
4376
3729
  }
4377
3730
  const provider = this.requireConnectedProvider();
4378
- const wallet = (0, import_viem7.createWalletClient)({
3731
+ const wallet = (0, import_viem6.createWalletClient)({
4379
3732
  account: state.walletAddress,
4380
3733
  chain: VIEM_CHAIN2[chainId],
4381
- transport: (0, import_viem7.custom)(provider)
3734
+ transport: (0, import_viem6.custom)(provider)
4382
3735
  });
4383
3736
  const hash = await wallet.writeContract({
4384
3737
  address: token,
@@ -4388,9 +3741,9 @@ var OwneySDK = class {
4388
3741
  account: state.walletAddress,
4389
3742
  chain: VIEM_CHAIN2[chainId]
4390
3743
  });
4391
- const publicClient = (0, import_viem7.createPublicClient)({
3744
+ const publicClient = (0, import_viem6.createPublicClient)({
4392
3745
  chain: VIEM_CHAIN2[chainId],
4393
- transport: (0, import_viem7.custom)(provider)
3746
+ transport: (0, import_viem6.custom)(provider)
4394
3747
  });
4395
3748
  const receipt = await publicClient.waitForTransactionReceipt({
4396
3749
  hash,
@@ -4498,11 +3851,8 @@ var OwneySDK = class {
4498
3851
  }
4499
3852
  };
4500
3853
 
4501
- // src/index.ts
4502
- init_errors();
4503
-
4504
3854
  // src/agents/zyfai/zyfai.siwx.ts
4505
- var import_viem8 = require("viem");
3855
+ var import_viem7 = require("viem");
4506
3856
  var import_siwe = require("siwe");
4507
3857
  var import_sdk2 = require("@zyfai/sdk");
4508
3858
 
@@ -4629,7 +3979,7 @@ function buildSIWXConfig(deps) {
4629
3979
  issuedAt,
4630
3980
  toString() {
4631
3981
  return new import_siwe.SiweMessage({
4632
- address: (0, import_viem8.getAddress)(accountAddress),
3982
+ address: (0, import_viem7.getAddress)(accountAddress),
4633
3983
  chainId: numericChainId(chainId),
4634
3984
  domain,
4635
3985
  uri,