@owney/sdk 0.7.28-beta.5 → 0.7.28-beta.7

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
@@ -523,23 +523,33 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
523
523
  function historyCoverage(raw) {
524
524
  const chains = /* @__PURE__ */ new Map();
525
525
  const assets = /* @__PURE__ */ new Map();
526
+ const pairs = /* @__PURE__ */ new Map();
526
527
  for (const date of Object.keys(raw.history ?? {}).sort()) {
527
528
  void date;
528
529
  const seenChains = /* @__PURE__ */ new Set();
529
530
  const seenAssets = /* @__PURE__ */ new Set();
531
+ const seenPairs = /* @__PURE__ */ new Map();
530
532
  for (const p of (raw.history ?? {})[date].positions ?? []) {
531
533
  const balance = p.balance ?? 0;
532
534
  const apy = netApy(p.apy_withFee, p.apy, "apy_withFee");
533
535
  if (balance <= 0 || typeof apy !== "number") continue;
534
536
  seenChains.add(p.chainId);
535
- if (p.tokenSymbol) seenAssets.add(p.tokenSymbol.toUpperCase());
537
+ if (p.tokenSymbol) {
538
+ const asset = p.tokenSymbol.toUpperCase();
539
+ seenAssets.add(asset);
540
+ seenPairs.set(`${p.chainId}:${asset}`, { chainId: p.chainId, asset });
541
+ }
536
542
  }
537
543
  for (const c of seenChains) chains.set(c, (chains.get(c) ?? 0) + 1);
538
544
  for (const a of seenAssets) assets.set(a, (assets.get(a) ?? 0) + 1);
545
+ for (const [key2, pair] of seenPairs) {
546
+ pairs.set(key2, { ...pair, days: (pairs.get(key2)?.days ?? 0) + 1 });
547
+ }
539
548
  }
540
549
  return {
541
550
  chains: [...chains].map(([chainId, days]) => ({ chainId, days })),
542
- assets: [...assets].map(([asset, days]) => ({ asset, days }))
551
+ assets: [...assets].map(([asset, days]) => ({ asset, days })),
552
+ pairs: [...pairs.values()]
543
553
  };
544
554
  }
545
555
  function mapApyHistory(raw, chainId, tokenSymbol) {
@@ -584,6 +594,9 @@ function mapEntries(rawEntries, chainId) {
584
594
  // "Top up wallet" and for slightly less (gas). `Deposit` already exists in
585
595
  // the public HistoryAction union, so no consumer type change is needed.
586
596
  "Deposit to protocol": "Deposit",
597
+ // Withdrawing from an async vault (Superform) is logged under its own
598
+ // label and paid out later in a separate batch (ROUT-624).
599
+ "Request async withdrawal": "Withdraw",
587
600
  Rebalance: "Rebalance"
588
601
  };
589
602
  void chainId;
@@ -626,8 +639,9 @@ function mapEntries(rawEntries, chainId) {
626
639
  ];
627
640
  }
628
641
  const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
642
+ const asyncRequest = entry.action === "Request async withdrawal";
629
643
  const rawAmount = entry?.positions?.[0]?.amount;
630
- const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
644
+ const hasAmount = (mappedAction !== "Withdraw" || asyncRequest) && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
631
645
  const mappedPositions = positions.filter((p) => p.protocol_name).map((p) => ({
632
646
  protocol: p.protocol_name,
633
647
  pool: p.pool ?? void 0,
@@ -641,6 +655,7 @@ function mapEntries(rawEntries, chainId) {
641
655
  newApy: newApy === null ? null : String(newApy),
642
656
  oldApy: oldApy === null ? null : String(oldApy),
643
657
  ...mappedPositions.length ? { positions: mappedPositions } : {},
658
+ ...asyncRequest ? { asyncRequest: true } : {},
644
659
  transactions: [
645
660
  {
646
661
  txHashes: entry.transactionHash ? [entry.transactionHash] : [],
@@ -1281,7 +1296,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1281
1296
  */
1282
1297
  async resolveWithdrawnAmounts(entries, chainId, recipient) {
1283
1298
  const withdrawals = entries.filter(
1284
- (e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
1299
+ (e) => e.action === "Withdraw" && !e.asyncRequest && e.transactions[0]?.txHashes[0]
1285
1300
  );
1286
1301
  if (withdrawals.length === 0) return;
1287
1302
  const client = this.getPublicClient(chainId);
@@ -1455,9 +1470,22 @@ var ZyfaiAgent = class _ZyfaiAgent {
1455
1470
  this.sdk.getUserDetails(asset),
1456
1471
  this.sdk.getAvailableProtocols(chainId)
1457
1472
  ]);
1473
+ debugLog("zyfai:protocol-sync", `${asset}: profile before sync`, {
1474
+ chains: current.chains,
1475
+ protocols: current.protocols,
1476
+ strategy: current.strategy
1477
+ });
1478
+ if ((current.chains?.length ?? 0) === 0 && (current.protocols?.length ?? 0) === 0) {
1479
+ debugLog(
1480
+ "zyfai:protocol-sync",
1481
+ `${asset}: skipping untouched profile until first deposit`
1482
+ );
1483
+ return;
1484
+ }
1458
1485
  const update = buildProtocolMergeUpdate(available, current, asset);
1459
1486
  if (!update) return;
1460
1487
  await this.sdk.updateUserProfile(update);
1488
+ debugLog("zyfai:protocol-sync", `${asset}: wrote profile update`, update);
1461
1489
  } catch (error) {
1462
1490
  console.warn(
1463
1491
  "[zyfai] ensureProtocolsSynced failed (non-fatal):",
@@ -1499,6 +1527,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
1499
1527
  // --- IAgent: Account lifecycle ---
1500
1528
  async activateAgent(state, chainId) {
1501
1529
  try {
1530
+ debugLog("zyfai:activation", "starting", {
1531
+ walletAddress: state.walletAddress,
1532
+ chainId
1533
+ });
1502
1534
  await this.connectAuth(state, chainId);
1503
1535
  const validChainId = isValidChainId(chainId);
1504
1536
  await Promise.all([
@@ -1510,6 +1542,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1510
1542
  // validator, so pool-wallet users see no prompt. Non-fatal.
1511
1543
  this.ensureSessionKeyIfDeployed(validChainId)
1512
1544
  ]);
1545
+ debugLog("zyfai:activation", "completed", { chainId: validChainId });
1513
1546
  } catch (error) {
1514
1547
  throw error;
1515
1548
  }
@@ -1592,6 +1625,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1592
1625
  */
1593
1626
  async applyPoolPolicy(policy, opts = {}) {
1594
1627
  try {
1628
+ await this.sdk.ensureFirstDepositSetup("aggressive");
1595
1629
  const { protocols: universe } = await this.sdk.getAvailableProtocols(
1596
1630
  this.supportedChainIds[0]
1597
1631
  );
@@ -1722,9 +1756,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
1722
1756
  * Persist an explicitly saved deposit-time draft at Zyfai profile level.
1723
1757
  * Pool choices are merged into protocol/chain records and each active asset
1724
1758
  * is kept at aggressive unless the draft includes a yieldmaxxing-only pool.
1759
+ * The whole operation must succeed before the caller starts moving funds.
1725
1760
  */
1726
1761
  async setPoolSelection(selection) {
1727
1762
  try {
1763
+ await this.sdk.ensureFirstDepositSetup("aggressive");
1728
1764
  const byPair = /* @__PURE__ */ new Map();
1729
1765
  for (const entry of selection.selections) {
1730
1766
  const pair = `${entry.protocolId}:${entry.chainId}`;
@@ -1732,39 +1768,31 @@ var ZyfaiAgent = class _ZyfaiAgent {
1732
1768
  group.push(entry);
1733
1769
  byPair.set(pair, group);
1734
1770
  }
1735
- const customizations = (await Promise.all(
1771
+ const customizations = await Promise.all(
1736
1772
  [...byPair.values()].map(async (scoped) => {
1737
1773
  const { protocolId, chainId } = scoped[0];
1738
- try {
1739
- const [current, rawAvailable] = await Promise.all([
1740
- this.sdk.getSelectedPools(protocolId, chainId),
1741
- this.sdk.getAvailablePools(protocolId, "yieldmaxxing")
1742
- ]);
1743
- const allAvailableNames = mapAvailablePools(rawAvailable).filter((pool) => pool.chainId === chainId).map((pool) => pool.name);
1744
- return {
1745
- protocolId,
1746
- chainId,
1747
- pools: mergeScopedPoolNames(
1748
- {
1749
- pools: current.pools ?? [],
1750
- autoselect: current.autoselect
1751
- },
1752
- scoped,
1753
- allAvailableNames
1754
- ),
1755
- // An explicit Save freezes exactly the choices the user saw.
1756
- // This also lets an empty list disable the pair deliberately.
1757
- autoselect: false
1758
- };
1759
- } catch (error) {
1760
- console.warn(
1761
- `[zyfai] setPoolSelection: preserving ${protocolId}/${chainId} failed; skipping the pair:`,
1762
- error instanceof Error ? error.message : String(error)
1763
- );
1764
- return null;
1765
- }
1774
+ const [current, rawAvailable] = await Promise.all([
1775
+ this.sdk.getSelectedPools(protocolId, chainId),
1776
+ this.sdk.getAvailablePools(protocolId, "yieldmaxxing")
1777
+ ]);
1778
+ const allAvailableNames = mapAvailablePools(rawAvailable).filter((pool) => pool.chainId === chainId).map((pool) => pool.name);
1779
+ return {
1780
+ protocolId,
1781
+ chainId,
1782
+ pools: mergeScopedPoolNames(
1783
+ {
1784
+ pools: current.pools ?? [],
1785
+ autoselect: current.autoselect
1786
+ },
1787
+ scoped,
1788
+ allAvailableNames
1789
+ ),
1790
+ // An explicit Save freezes exactly the choices the user saw.
1791
+ // This also lets an empty list disable the pair deliberately.
1792
+ autoselect: false
1793
+ };
1766
1794
  })
1767
- )).filter((value) => value !== null);
1795
+ );
1768
1796
  if (customizations.length > 0) {
1769
1797
  await this.sdk.customizeBatch(customizations);
1770
1798
  }
@@ -1782,11 +1810,51 @@ var ZyfaiAgent = class _ZyfaiAgent {
1782
1810
  );
1783
1811
  } catch (error) {
1784
1812
  console.warn(
1785
- "[zyfai] setPoolSelection failed (non-fatal):",
1813
+ "[zyfai] setPoolSelection failed:",
1786
1814
  error instanceof Error ? error.message : String(error)
1787
1815
  );
1816
+ throw error;
1788
1817
  }
1789
1818
  }
1819
+ /**
1820
+ * Read back what `setPoolSelection` wrote (ROUT-650). Zyfai keeps the saved
1821
+ * pools per protocol/chain and the strategy per asset; both are read for the
1822
+ * pairs and assets asked about. A pair still on autoselect, or one whose
1823
+ * lookup fails, is left out so the caller falls back to its default for it.
1824
+ */
1825
+ async getPoolSelection(state, chainId, params) {
1826
+ await this.connectAuth(state, chainId);
1827
+ const [pairs, strategies] = await Promise.all([
1828
+ Promise.all(
1829
+ params.pairs.map(async ({ protocolId, chainId: chainId2 }) => {
1830
+ try {
1831
+ const current = await this.sdk.getSelectedPools(
1832
+ protocolId,
1833
+ chainId2
1834
+ );
1835
+ if (current.autoselect) return null;
1836
+ return { protocolId, chainId: chainId2, pools: current.pools ?? [] };
1837
+ } catch {
1838
+ return null;
1839
+ }
1840
+ })
1841
+ ),
1842
+ Promise.all(
1843
+ params.assets.map(async (asset) => {
1844
+ try {
1845
+ const current = await this.sdk.getUserDetails(asset);
1846
+ return current.strategy ? { asset, strategy: current.strategy } : null;
1847
+ } catch {
1848
+ return null;
1849
+ }
1850
+ })
1851
+ )
1852
+ ]);
1853
+ return {
1854
+ pairs: pairs.filter((value) => value !== null),
1855
+ strategies: strategies.filter((value) => value !== null)
1856
+ };
1857
+ }
1790
1858
  /**
1791
1859
  * True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
1792
1860
  * to this EOA — the "new wallet" kind that is predeployed on the chains it
@@ -2082,6 +2150,33 @@ var ZyfaiAgent = class _ZyfaiAgent {
2082
2150
  const validChainId = isValidChainId(chainId);
2083
2151
  await this.ensureConnected(state, validChainId);
2084
2152
  if (depositCallback) {
2153
+ debugLog("zyfai:first-deposit", "starting sponsored deposit setup", {
2154
+ asset,
2155
+ chainId: validChainId,
2156
+ requestedStrategy: "aggressive"
2157
+ });
2158
+ const setupResult = await this.sdk.ensureFirstDepositSetup("aggressive");
2159
+ debugLog("zyfai:first-deposit", "setup call completed", {
2160
+ requestedStrategy: "aggressive",
2161
+ setupResult
2162
+ });
2163
+ if (isOwneyDebug()) {
2164
+ try {
2165
+ const profileAfterSetup = await this.sdk.getUserDetails(
2166
+ asset === "WETH" ? "WETH" : "USDC"
2167
+ );
2168
+ debugLog("zyfai:first-deposit", "profile immediately after setup", {
2169
+ asset,
2170
+ strategy: profileAfterSetup.strategy,
2171
+ chains: profileAfterSetup.chains,
2172
+ protocols: profileAfterSetup.protocols
2173
+ });
2174
+ } catch (debugError) {
2175
+ debugLog("zyfai:first-deposit", "post-setup profile read failed", {
2176
+ error: debugError instanceof Error ? debugError.message : String(debugError)
2177
+ });
2178
+ }
2179
+ }
2085
2180
  const smartWallet = await this.ensureWalletDeployed(
2086
2181
  this.getAddress(),
2087
2182
  validChainId
@@ -2099,7 +2194,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2099
2194
  return { txHash, smartWallet, amount };
2100
2195
  }
2101
2196
  await this.ensureWalletDeployed(this.getAddress(), validChainId);
2102
- const raw = await this.sdk.depositFunds(
2197
+ const raw = await this.sdk.sendDeposit(
2103
2198
  this.getAddress(),
2104
2199
  validChainId,
2105
2200
  amount,
@@ -2296,6 +2391,19 @@ var ZyfaiAgent = class _ZyfaiAgent {
2296
2391
  async ensureAutoSelectProtocols(state, chainId, asset) {
2297
2392
  await this.connectAuth(state, chainId);
2298
2393
  const current = await this.sdk.getUserDetails(asset);
2394
+ debugLog("zyfai:auto-select", `${asset}: profile before check`, {
2395
+ autoSelectProtocols: current.autoSelectProtocols,
2396
+ chains: current.chains,
2397
+ protocols: current.protocols,
2398
+ strategy: current.strategy
2399
+ });
2400
+ if ((current.chains?.length ?? 0) === 0) {
2401
+ debugLog(
2402
+ "zyfai:auto-select",
2403
+ `${asset}: skipping untouched profile until first deposit`
2404
+ );
2405
+ return false;
2406
+ }
2299
2407
  const update = buildAutoSelectUpdate(
2300
2408
  {
2301
2409
  autoSelectProtocols: current.autoSelectProtocols,
@@ -2306,6 +2414,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2306
2414
  );
2307
2415
  if (!update) return false;
2308
2416
  await this.sdk.updateUserProfile(update);
2417
+ debugLog("zyfai:auto-select", `${asset}: wrote profile update`, update);
2309
2418
  return true;
2310
2419
  }
2311
2420
  // --- IAgent: Discovery (no wallet required) ---
@@ -5512,6 +5621,19 @@ var OwneySDK = class {
5512
5621
  chain: dstChain,
5513
5622
  transport: swapReadTransport(quote.dst.chainId, this.zyfaiRpcUrls)
5514
5623
  });
5624
+ const walletPublic = (0, import_viem9.createPublicClient)({
5625
+ chain: srcChain,
5626
+ transport: (0, import_viem9.custom)(provider)
5627
+ });
5628
+ const signOnSource = (payload) => signWithChainRetry(
5629
+ walletPublic,
5630
+ wallet,
5631
+ quote.src.chainId,
5632
+ () => wallet.signTypedData({
5633
+ account: state.walletAddress,
5634
+ ...payload
5635
+ })
5636
+ );
5515
5637
  return {
5516
5638
  api: this.swapApi(),
5517
5639
  // Native-aware, like readSourceBalance below. Native ETH is never a
@@ -5552,10 +5674,7 @@ var OwneySDK = class {
5552
5674
  }
5553
5675
  return hash;
5554
5676
  },
5555
- signTypedData: (typedData) => wallet.signTypedData({
5556
- account: state.walletAddress,
5557
- ...typedData
5558
- }),
5677
+ signTypedData: signOnSource,
5559
5678
  // Chain-bound like every other read here: the wallet provider's chain is
5560
5679
  // not ours to rely on mid-swap.
5561
5680
  readSourceBalance: async () => {
@@ -5612,10 +5731,7 @@ var OwneySDK = class {
5612
5731
  spender,
5613
5732
  value: amount,
5614
5733
  chainId: quote.src.chainId,
5615
- signTypedData: (payload) => wallet.signTypedData({
5616
- account: state.walletAddress,
5617
- ...payload
5618
- })
5734
+ signTypedData: signOnSource
5619
5735
  }
5620
5736
  ),
5621
5737
  /**
@@ -6738,6 +6854,27 @@ var OwneySDK = class {
6738
6854
  }
6739
6855
  await agent.setPoolSelection(params.selection);
6740
6856
  }
6857
+ /**
6858
+ * The pool selection saved on the user's account (ROUT-650), so the Pools
6859
+ * step can show what applies now rather than the defaults. `pairs` and
6860
+ * `assets` say which protocol/chain lists and strategies to read.
6861
+ */
6862
+ async getPoolSelection(params) {
6863
+ const state = this.requireState();
6864
+ const chainId = this.requireChainId();
6865
+ await this.ensureAgentsInitialized();
6866
+ const agent = this.getAgent(params.agentId ?? "zyfai");
6867
+ if (!agent.getPoolSelection) {
6868
+ throw new OwneyError(
6869
+ "POOL_SELECTION_UNSUPPORTED",
6870
+ `Agent ${agent.id} does not support pool customization`
6871
+ );
6872
+ }
6873
+ return agent.getPoolSelection(state, chainId, {
6874
+ pairs: params.pairs,
6875
+ assets: params.assets
6876
+ });
6877
+ }
6741
6878
  async getAccountApy({
6742
6879
  agentId,
6743
6880
  days,
package/dist/index.d.cts CHANGED
@@ -563,6 +563,22 @@ type UserPoolSelectionRequest = {
563
563
  }>;
564
564
  selections: UserPoolSelection[];
565
565
  };
566
+ /**
567
+ * What a user's account currently has saved (ROUT-650): each asset's strategy,
568
+ * plus the pool list of every protocol/chain pair frozen by an earlier Save.
569
+ * Pairs Zyfai still autoselects are left out, so "no entry" means "default".
570
+ */
571
+ type SavedPoolSelection = {
572
+ strategies: Array<{
573
+ asset: "USDC" | "WETH";
574
+ strategy: string;
575
+ }>;
576
+ pairs: Array<{
577
+ protocolId: string;
578
+ chainId: number;
579
+ pools: string[];
580
+ }>;
581
+ };
566
582
  /** One protocol with its pools for the deposit asset — what the Pools step
567
583
  * renders: a protocol row that opens to a list of selectable pools. */
568
584
  type PoolCatalogProtocol = {
@@ -723,6 +739,14 @@ interface ApyCoverage {
723
739
  asset: string;
724
740
  days: number;
725
741
  }[];
742
+ /** Each asset on each chain, for a menu that offers the two together
743
+ * (ROUT-647). The lists above cannot say this: USDC on Base and WETH on
744
+ * Arbitrum put both chains and both assets in them, and no WETH on Base. */
745
+ pairs: {
746
+ chainId: number;
747
+ asset: string;
748
+ days: number;
749
+ }[];
726
750
  }
727
751
  interface AccountAgentApy {
728
752
  walletAddress: string;
@@ -802,6 +826,13 @@ interface AgentHistoryEntry {
802
826
  transactions: HistoryTransaction[];
803
827
  rebalanceLog: RebalanceLog[];
804
828
  positions?: AgentHistoryPosition[];
829
+ /**
830
+ * Set on a `Withdraw` that was only requested from an async vault
831
+ * (ROUT-624). The vault pays out in batches later, so the funds have not
832
+ * reached the wallet yet and `transactions[0].amount` is the amount
833
+ * requested.
834
+ */
835
+ asyncRequest?: true;
805
836
  }
806
837
  interface OwneyAgentHistory {
807
838
  data: AgentHistoryEntry[];
@@ -914,6 +945,17 @@ interface IAgent {
914
945
  * (ROUT-569)
915
946
  */
916
947
  setPoolSelection?(selection: UserPoolSelectionRequest): Promise<void>;
948
+ /**
949
+ * Read back what `setPoolSelection` saved, for the pairs and assets given,
950
+ * so the Pools step can open on the user's own choices. Optional. (ROUT-650)
951
+ */
952
+ getPoolSelection?(state: ConnectionState, chainId: number, params: {
953
+ pairs: Array<{
954
+ protocolId: string;
955
+ chainId: number;
956
+ }>;
957
+ assets: Array<"USDC" | "WETH">;
958
+ }): Promise<SavedPoolSelection>;
917
959
  deposit(state: ConnectionState, chainId: number, amount: string, asset: OwneySupportedTokens, depositCallback?: DepositCallback): Promise<OwneyDepositResult>;
918
960
  withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
919
961
  getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
@@ -1782,6 +1824,19 @@ declare class OwneySDK {
1782
1824
  selection: UserPoolSelectionRequest;
1783
1825
  agentId?: AgentId;
1784
1826
  }): Promise<void>;
1827
+ /**
1828
+ * The pool selection saved on the user's account (ROUT-650), so the Pools
1829
+ * step can show what applies now rather than the defaults. `pairs` and
1830
+ * `assets` say which protocol/chain lists and strategies to read.
1831
+ */
1832
+ getPoolSelection(params: {
1833
+ pairs: Array<{
1834
+ protocolId: string;
1835
+ chainId: number;
1836
+ }>;
1837
+ assets: Array<"USDC" | "WETH">;
1838
+ agentId?: AgentId;
1839
+ }): Promise<SavedPoolSelection>;
1785
1840
  getAccountApy({ agentId, days, tokenSymbol, chainId: scope, }: AccountApyOptions): Promise<OwneyAccountApy | AccountAgentApy>;
1786
1841
  /**
1787
1842
  * Get transaction history for a specific agent, or all agents.
@@ -1924,4 +1979,4 @@ type StoredOrder = {
1924
1979
  */
1925
1980
  declare function listOrders(now?: number): StoredOrder[];
1926
1981
 
1927
- export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyCoverage, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type AvailablePool, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OrgPoolPolicy, type OrgPoolSelection, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawAllLeg, type OwneyWithdrawAllResult, type OwneyWithdrawResult, type PendingDeposit, type PoolCatalogProtocol, type PoolSelectionStrategy, type RebalanceLog, type SwapChainTokens, type SwapDirection, type SwapOrderStatus, type SwapQuote, type SwapQuoteParams, type SwapRail, type SwapStage, type SwapTokenInfo, type SwapTokenSearchResult, type UserPoolSelection, type UserPoolSelectionRequest, type WithdrawOptions, type WithdrawSwapRecord, type WithdrawSwapStatus, clearWithdrawSwap, createOwneySIWX, listPendingDeposits, listOrders as listPendingSwaps, listWithdrawSwaps, saveWithdrawSwap, setOwneyDebug, subscribeWithdrawSwaps, updateWithdrawSwap };
1982
+ export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyCoverage, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type AvailablePool, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OrgPoolPolicy, type OrgPoolSelection, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawAllLeg, type OwneyWithdrawAllResult, type OwneyWithdrawResult, type PendingDeposit, type PoolCatalogProtocol, type PoolSelectionStrategy, type RebalanceLog, type SavedPoolSelection, type SwapChainTokens, type SwapDirection, type SwapOrderStatus, type SwapQuote, type SwapQuoteParams, type SwapRail, type SwapStage, type SwapTokenInfo, type SwapTokenSearchResult, type UserPoolSelection, type UserPoolSelectionRequest, type WithdrawOptions, type WithdrawSwapRecord, type WithdrawSwapStatus, clearWithdrawSwap, createOwneySIWX, listPendingDeposits, listOrders as listPendingSwaps, listWithdrawSwaps, saveWithdrawSwap, setOwneyDebug, subscribeWithdrawSwaps, updateWithdrawSwap };
package/dist/index.d.ts CHANGED
@@ -563,6 +563,22 @@ type UserPoolSelectionRequest = {
563
563
  }>;
564
564
  selections: UserPoolSelection[];
565
565
  };
566
+ /**
567
+ * What a user's account currently has saved (ROUT-650): each asset's strategy,
568
+ * plus the pool list of every protocol/chain pair frozen by an earlier Save.
569
+ * Pairs Zyfai still autoselects are left out, so "no entry" means "default".
570
+ */
571
+ type SavedPoolSelection = {
572
+ strategies: Array<{
573
+ asset: "USDC" | "WETH";
574
+ strategy: string;
575
+ }>;
576
+ pairs: Array<{
577
+ protocolId: string;
578
+ chainId: number;
579
+ pools: string[];
580
+ }>;
581
+ };
566
582
  /** One protocol with its pools for the deposit asset — what the Pools step
567
583
  * renders: a protocol row that opens to a list of selectable pools. */
568
584
  type PoolCatalogProtocol = {
@@ -723,6 +739,14 @@ interface ApyCoverage {
723
739
  asset: string;
724
740
  days: number;
725
741
  }[];
742
+ /** Each asset on each chain, for a menu that offers the two together
743
+ * (ROUT-647). The lists above cannot say this: USDC on Base and WETH on
744
+ * Arbitrum put both chains and both assets in them, and no WETH on Base. */
745
+ pairs: {
746
+ chainId: number;
747
+ asset: string;
748
+ days: number;
749
+ }[];
726
750
  }
727
751
  interface AccountAgentApy {
728
752
  walletAddress: string;
@@ -802,6 +826,13 @@ interface AgentHistoryEntry {
802
826
  transactions: HistoryTransaction[];
803
827
  rebalanceLog: RebalanceLog[];
804
828
  positions?: AgentHistoryPosition[];
829
+ /**
830
+ * Set on a `Withdraw` that was only requested from an async vault
831
+ * (ROUT-624). The vault pays out in batches later, so the funds have not
832
+ * reached the wallet yet and `transactions[0].amount` is the amount
833
+ * requested.
834
+ */
835
+ asyncRequest?: true;
805
836
  }
806
837
  interface OwneyAgentHistory {
807
838
  data: AgentHistoryEntry[];
@@ -914,6 +945,17 @@ interface IAgent {
914
945
  * (ROUT-569)
915
946
  */
916
947
  setPoolSelection?(selection: UserPoolSelectionRequest): Promise<void>;
948
+ /**
949
+ * Read back what `setPoolSelection` saved, for the pairs and assets given,
950
+ * so the Pools step can open on the user's own choices. Optional. (ROUT-650)
951
+ */
952
+ getPoolSelection?(state: ConnectionState, chainId: number, params: {
953
+ pairs: Array<{
954
+ protocolId: string;
955
+ chainId: number;
956
+ }>;
957
+ assets: Array<"USDC" | "WETH">;
958
+ }): Promise<SavedPoolSelection>;
917
959
  deposit(state: ConnectionState, chainId: number, amount: string, asset: OwneySupportedTokens, depositCallback?: DepositCallback): Promise<OwneyDepositResult>;
918
960
  withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
919
961
  getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
@@ -1782,6 +1824,19 @@ declare class OwneySDK {
1782
1824
  selection: UserPoolSelectionRequest;
1783
1825
  agentId?: AgentId;
1784
1826
  }): Promise<void>;
1827
+ /**
1828
+ * The pool selection saved on the user's account (ROUT-650), so the Pools
1829
+ * step can show what applies now rather than the defaults. `pairs` and
1830
+ * `assets` say which protocol/chain lists and strategies to read.
1831
+ */
1832
+ getPoolSelection(params: {
1833
+ pairs: Array<{
1834
+ protocolId: string;
1835
+ chainId: number;
1836
+ }>;
1837
+ assets: Array<"USDC" | "WETH">;
1838
+ agentId?: AgentId;
1839
+ }): Promise<SavedPoolSelection>;
1785
1840
  getAccountApy({ agentId, days, tokenSymbol, chainId: scope, }: AccountApyOptions): Promise<OwneyAccountApy | AccountAgentApy>;
1786
1841
  /**
1787
1842
  * Get transaction history for a specific agent, or all agents.
@@ -1924,4 +1979,4 @@ type StoredOrder = {
1924
1979
  */
1925
1980
  declare function listOrders(now?: number): StoredOrder[];
1926
1981
 
1927
- export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyCoverage, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type AvailablePool, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OrgPoolPolicy, type OrgPoolSelection, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawAllLeg, type OwneyWithdrawAllResult, type OwneyWithdrawResult, type PendingDeposit, type PoolCatalogProtocol, type PoolSelectionStrategy, type RebalanceLog, type SwapChainTokens, type SwapDirection, type SwapOrderStatus, type SwapQuote, type SwapQuoteParams, type SwapRail, type SwapStage, type SwapTokenInfo, type SwapTokenSearchResult, type UserPoolSelection, type UserPoolSelectionRequest, type WithdrawOptions, type WithdrawSwapRecord, type WithdrawSwapStatus, clearWithdrawSwap, createOwneySIWX, listPendingDeposits, listOrders as listPendingSwaps, listWithdrawSwaps, saveWithdrawSwap, setOwneyDebug, subscribeWithdrawSwaps, updateWithdrawSwap };
1982
+ export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyCoverage, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type AvailablePool, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OrgPoolPolicy, type OrgPoolSelection, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawAllLeg, type OwneyWithdrawAllResult, type OwneyWithdrawResult, type PendingDeposit, type PoolCatalogProtocol, type PoolSelectionStrategy, type RebalanceLog, type SavedPoolSelection, type SwapChainTokens, type SwapDirection, type SwapOrderStatus, type SwapQuote, type SwapQuoteParams, type SwapRail, type SwapStage, type SwapTokenInfo, type SwapTokenSearchResult, type UserPoolSelection, type UserPoolSelectionRequest, type WithdrawOptions, type WithdrawSwapRecord, type WithdrawSwapStatus, clearWithdrawSwap, createOwneySIWX, listPendingDeposits, listOrders as listPendingSwaps, listWithdrawSwaps, saveWithdrawSwap, setOwneyDebug, subscribeWithdrawSwaps, updateWithdrawSwap };
package/dist/index.js CHANGED
@@ -483,23 +483,33 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
483
483
  function historyCoverage(raw) {
484
484
  const chains = /* @__PURE__ */ new Map();
485
485
  const assets = /* @__PURE__ */ new Map();
486
+ const pairs = /* @__PURE__ */ new Map();
486
487
  for (const date of Object.keys(raw.history ?? {}).sort()) {
487
488
  void date;
488
489
  const seenChains = /* @__PURE__ */ new Set();
489
490
  const seenAssets = /* @__PURE__ */ new Set();
491
+ const seenPairs = /* @__PURE__ */ new Map();
490
492
  for (const p of (raw.history ?? {})[date].positions ?? []) {
491
493
  const balance = p.balance ?? 0;
492
494
  const apy = netApy(p.apy_withFee, p.apy, "apy_withFee");
493
495
  if (balance <= 0 || typeof apy !== "number") continue;
494
496
  seenChains.add(p.chainId);
495
- if (p.tokenSymbol) seenAssets.add(p.tokenSymbol.toUpperCase());
497
+ if (p.tokenSymbol) {
498
+ const asset = p.tokenSymbol.toUpperCase();
499
+ seenAssets.add(asset);
500
+ seenPairs.set(`${p.chainId}:${asset}`, { chainId: p.chainId, asset });
501
+ }
496
502
  }
497
503
  for (const c of seenChains) chains.set(c, (chains.get(c) ?? 0) + 1);
498
504
  for (const a of seenAssets) assets.set(a, (assets.get(a) ?? 0) + 1);
505
+ for (const [key2, pair] of seenPairs) {
506
+ pairs.set(key2, { ...pair, days: (pairs.get(key2)?.days ?? 0) + 1 });
507
+ }
499
508
  }
500
509
  return {
501
510
  chains: [...chains].map(([chainId, days]) => ({ chainId, days })),
502
- assets: [...assets].map(([asset, days]) => ({ asset, days }))
511
+ assets: [...assets].map(([asset, days]) => ({ asset, days })),
512
+ pairs: [...pairs.values()]
503
513
  };
504
514
  }
505
515
  function mapApyHistory(raw, chainId, tokenSymbol) {
@@ -544,6 +554,9 @@ function mapEntries(rawEntries, chainId) {
544
554
  // "Top up wallet" and for slightly less (gas). `Deposit` already exists in
545
555
  // the public HistoryAction union, so no consumer type change is needed.
546
556
  "Deposit to protocol": "Deposit",
557
+ // Withdrawing from an async vault (Superform) is logged under its own
558
+ // label and paid out later in a separate batch (ROUT-624).
559
+ "Request async withdrawal": "Withdraw",
547
560
  Rebalance: "Rebalance"
548
561
  };
549
562
  void chainId;
@@ -586,8 +599,9 @@ function mapEntries(rawEntries, chainId) {
586
599
  ];
587
600
  }
588
601
  const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
602
+ const asyncRequest = entry.action === "Request async withdrawal";
589
603
  const rawAmount = entry?.positions?.[0]?.amount;
590
- const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
604
+ const hasAmount = (mappedAction !== "Withdraw" || asyncRequest) && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
591
605
  const mappedPositions = positions.filter((p) => p.protocol_name).map((p) => ({
592
606
  protocol: p.protocol_name,
593
607
  pool: p.pool ?? void 0,
@@ -601,6 +615,7 @@ function mapEntries(rawEntries, chainId) {
601
615
  newApy: newApy === null ? null : String(newApy),
602
616
  oldApy: oldApy === null ? null : String(oldApy),
603
617
  ...mappedPositions.length ? { positions: mappedPositions } : {},
618
+ ...asyncRequest ? { asyncRequest: true } : {},
604
619
  transactions: [
605
620
  {
606
621
  txHashes: entry.transactionHash ? [entry.transactionHash] : [],
@@ -1241,7 +1256,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1241
1256
  */
1242
1257
  async resolveWithdrawnAmounts(entries, chainId, recipient) {
1243
1258
  const withdrawals = entries.filter(
1244
- (e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
1259
+ (e) => e.action === "Withdraw" && !e.asyncRequest && e.transactions[0]?.txHashes[0]
1245
1260
  );
1246
1261
  if (withdrawals.length === 0) return;
1247
1262
  const client = this.getPublicClient(chainId);
@@ -1415,9 +1430,22 @@ var ZyfaiAgent = class _ZyfaiAgent {
1415
1430
  this.sdk.getUserDetails(asset),
1416
1431
  this.sdk.getAvailableProtocols(chainId)
1417
1432
  ]);
1433
+ debugLog("zyfai:protocol-sync", `${asset}: profile before sync`, {
1434
+ chains: current.chains,
1435
+ protocols: current.protocols,
1436
+ strategy: current.strategy
1437
+ });
1438
+ if ((current.chains?.length ?? 0) === 0 && (current.protocols?.length ?? 0) === 0) {
1439
+ debugLog(
1440
+ "zyfai:protocol-sync",
1441
+ `${asset}: skipping untouched profile until first deposit`
1442
+ );
1443
+ return;
1444
+ }
1418
1445
  const update = buildProtocolMergeUpdate(available, current, asset);
1419
1446
  if (!update) return;
1420
1447
  await this.sdk.updateUserProfile(update);
1448
+ debugLog("zyfai:protocol-sync", `${asset}: wrote profile update`, update);
1421
1449
  } catch (error) {
1422
1450
  console.warn(
1423
1451
  "[zyfai] ensureProtocolsSynced failed (non-fatal):",
@@ -1459,6 +1487,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
1459
1487
  // --- IAgent: Account lifecycle ---
1460
1488
  async activateAgent(state, chainId) {
1461
1489
  try {
1490
+ debugLog("zyfai:activation", "starting", {
1491
+ walletAddress: state.walletAddress,
1492
+ chainId
1493
+ });
1462
1494
  await this.connectAuth(state, chainId);
1463
1495
  const validChainId = isValidChainId(chainId);
1464
1496
  await Promise.all([
@@ -1470,6 +1502,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1470
1502
  // validator, so pool-wallet users see no prompt. Non-fatal.
1471
1503
  this.ensureSessionKeyIfDeployed(validChainId)
1472
1504
  ]);
1505
+ debugLog("zyfai:activation", "completed", { chainId: validChainId });
1473
1506
  } catch (error) {
1474
1507
  throw error;
1475
1508
  }
@@ -1552,6 +1585,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1552
1585
  */
1553
1586
  async applyPoolPolicy(policy, opts = {}) {
1554
1587
  try {
1588
+ await this.sdk.ensureFirstDepositSetup("aggressive");
1555
1589
  const { protocols: universe } = await this.sdk.getAvailableProtocols(
1556
1590
  this.supportedChainIds[0]
1557
1591
  );
@@ -1682,9 +1716,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
1682
1716
  * Persist an explicitly saved deposit-time draft at Zyfai profile level.
1683
1717
  * Pool choices are merged into protocol/chain records and each active asset
1684
1718
  * is kept at aggressive unless the draft includes a yieldmaxxing-only pool.
1719
+ * The whole operation must succeed before the caller starts moving funds.
1685
1720
  */
1686
1721
  async setPoolSelection(selection) {
1687
1722
  try {
1723
+ await this.sdk.ensureFirstDepositSetup("aggressive");
1688
1724
  const byPair = /* @__PURE__ */ new Map();
1689
1725
  for (const entry of selection.selections) {
1690
1726
  const pair = `${entry.protocolId}:${entry.chainId}`;
@@ -1692,39 +1728,31 @@ var ZyfaiAgent = class _ZyfaiAgent {
1692
1728
  group.push(entry);
1693
1729
  byPair.set(pair, group);
1694
1730
  }
1695
- const customizations = (await Promise.all(
1731
+ const customizations = await Promise.all(
1696
1732
  [...byPair.values()].map(async (scoped) => {
1697
1733
  const { protocolId, chainId } = scoped[0];
1698
- try {
1699
- const [current, rawAvailable] = await Promise.all([
1700
- this.sdk.getSelectedPools(protocolId, chainId),
1701
- this.sdk.getAvailablePools(protocolId, "yieldmaxxing")
1702
- ]);
1703
- const allAvailableNames = mapAvailablePools(rawAvailable).filter((pool) => pool.chainId === chainId).map((pool) => pool.name);
1704
- return {
1705
- protocolId,
1706
- chainId,
1707
- pools: mergeScopedPoolNames(
1708
- {
1709
- pools: current.pools ?? [],
1710
- autoselect: current.autoselect
1711
- },
1712
- scoped,
1713
- allAvailableNames
1714
- ),
1715
- // An explicit Save freezes exactly the choices the user saw.
1716
- // This also lets an empty list disable the pair deliberately.
1717
- autoselect: false
1718
- };
1719
- } catch (error) {
1720
- console.warn(
1721
- `[zyfai] setPoolSelection: preserving ${protocolId}/${chainId} failed; skipping the pair:`,
1722
- error instanceof Error ? error.message : String(error)
1723
- );
1724
- return null;
1725
- }
1734
+ const [current, rawAvailable] = await Promise.all([
1735
+ this.sdk.getSelectedPools(protocolId, chainId),
1736
+ this.sdk.getAvailablePools(protocolId, "yieldmaxxing")
1737
+ ]);
1738
+ const allAvailableNames = mapAvailablePools(rawAvailable).filter((pool) => pool.chainId === chainId).map((pool) => pool.name);
1739
+ return {
1740
+ protocolId,
1741
+ chainId,
1742
+ pools: mergeScopedPoolNames(
1743
+ {
1744
+ pools: current.pools ?? [],
1745
+ autoselect: current.autoselect
1746
+ },
1747
+ scoped,
1748
+ allAvailableNames
1749
+ ),
1750
+ // An explicit Save freezes exactly the choices the user saw.
1751
+ // This also lets an empty list disable the pair deliberately.
1752
+ autoselect: false
1753
+ };
1726
1754
  })
1727
- )).filter((value) => value !== null);
1755
+ );
1728
1756
  if (customizations.length > 0) {
1729
1757
  await this.sdk.customizeBatch(customizations);
1730
1758
  }
@@ -1742,11 +1770,51 @@ var ZyfaiAgent = class _ZyfaiAgent {
1742
1770
  );
1743
1771
  } catch (error) {
1744
1772
  console.warn(
1745
- "[zyfai] setPoolSelection failed (non-fatal):",
1773
+ "[zyfai] setPoolSelection failed:",
1746
1774
  error instanceof Error ? error.message : String(error)
1747
1775
  );
1776
+ throw error;
1748
1777
  }
1749
1778
  }
1779
+ /**
1780
+ * Read back what `setPoolSelection` wrote (ROUT-650). Zyfai keeps the saved
1781
+ * pools per protocol/chain and the strategy per asset; both are read for the
1782
+ * pairs and assets asked about. A pair still on autoselect, or one whose
1783
+ * lookup fails, is left out so the caller falls back to its default for it.
1784
+ */
1785
+ async getPoolSelection(state, chainId, params) {
1786
+ await this.connectAuth(state, chainId);
1787
+ const [pairs, strategies] = await Promise.all([
1788
+ Promise.all(
1789
+ params.pairs.map(async ({ protocolId, chainId: chainId2 }) => {
1790
+ try {
1791
+ const current = await this.sdk.getSelectedPools(
1792
+ protocolId,
1793
+ chainId2
1794
+ );
1795
+ if (current.autoselect) return null;
1796
+ return { protocolId, chainId: chainId2, pools: current.pools ?? [] };
1797
+ } catch {
1798
+ return null;
1799
+ }
1800
+ })
1801
+ ),
1802
+ Promise.all(
1803
+ params.assets.map(async (asset) => {
1804
+ try {
1805
+ const current = await this.sdk.getUserDetails(asset);
1806
+ return current.strategy ? { asset, strategy: current.strategy } : null;
1807
+ } catch {
1808
+ return null;
1809
+ }
1810
+ })
1811
+ )
1812
+ ]);
1813
+ return {
1814
+ pairs: pairs.filter((value) => value !== null),
1815
+ strategies: strategies.filter((value) => value !== null)
1816
+ };
1817
+ }
1750
1818
  /**
1751
1819
  * True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
1752
1820
  * to this EOA — the "new wallet" kind that is predeployed on the chains it
@@ -2042,6 +2110,33 @@ var ZyfaiAgent = class _ZyfaiAgent {
2042
2110
  const validChainId = isValidChainId(chainId);
2043
2111
  await this.ensureConnected(state, validChainId);
2044
2112
  if (depositCallback) {
2113
+ debugLog("zyfai:first-deposit", "starting sponsored deposit setup", {
2114
+ asset,
2115
+ chainId: validChainId,
2116
+ requestedStrategy: "aggressive"
2117
+ });
2118
+ const setupResult = await this.sdk.ensureFirstDepositSetup("aggressive");
2119
+ debugLog("zyfai:first-deposit", "setup call completed", {
2120
+ requestedStrategy: "aggressive",
2121
+ setupResult
2122
+ });
2123
+ if (isOwneyDebug()) {
2124
+ try {
2125
+ const profileAfterSetup = await this.sdk.getUserDetails(
2126
+ asset === "WETH" ? "WETH" : "USDC"
2127
+ );
2128
+ debugLog("zyfai:first-deposit", "profile immediately after setup", {
2129
+ asset,
2130
+ strategy: profileAfterSetup.strategy,
2131
+ chains: profileAfterSetup.chains,
2132
+ protocols: profileAfterSetup.protocols
2133
+ });
2134
+ } catch (debugError) {
2135
+ debugLog("zyfai:first-deposit", "post-setup profile read failed", {
2136
+ error: debugError instanceof Error ? debugError.message : String(debugError)
2137
+ });
2138
+ }
2139
+ }
2045
2140
  const smartWallet = await this.ensureWalletDeployed(
2046
2141
  this.getAddress(),
2047
2142
  validChainId
@@ -2059,7 +2154,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2059
2154
  return { txHash, smartWallet, amount };
2060
2155
  }
2061
2156
  await this.ensureWalletDeployed(this.getAddress(), validChainId);
2062
- const raw = await this.sdk.depositFunds(
2157
+ const raw = await this.sdk.sendDeposit(
2063
2158
  this.getAddress(),
2064
2159
  validChainId,
2065
2160
  amount,
@@ -2256,6 +2351,19 @@ var ZyfaiAgent = class _ZyfaiAgent {
2256
2351
  async ensureAutoSelectProtocols(state, chainId, asset) {
2257
2352
  await this.connectAuth(state, chainId);
2258
2353
  const current = await this.sdk.getUserDetails(asset);
2354
+ debugLog("zyfai:auto-select", `${asset}: profile before check`, {
2355
+ autoSelectProtocols: current.autoSelectProtocols,
2356
+ chains: current.chains,
2357
+ protocols: current.protocols,
2358
+ strategy: current.strategy
2359
+ });
2360
+ if ((current.chains?.length ?? 0) === 0) {
2361
+ debugLog(
2362
+ "zyfai:auto-select",
2363
+ `${asset}: skipping untouched profile until first deposit`
2364
+ );
2365
+ return false;
2366
+ }
2259
2367
  const update = buildAutoSelectUpdate(
2260
2368
  {
2261
2369
  autoSelectProtocols: current.autoSelectProtocols,
@@ -2266,6 +2374,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2266
2374
  );
2267
2375
  if (!update) return false;
2268
2376
  await this.sdk.updateUserProfile(update);
2377
+ debugLog("zyfai:auto-select", `${asset}: wrote profile update`, update);
2269
2378
  return true;
2270
2379
  }
2271
2380
  // --- IAgent: Discovery (no wallet required) ---
@@ -5493,6 +5602,19 @@ var OwneySDK = class {
5493
5602
  chain: dstChain,
5494
5603
  transport: swapReadTransport(quote.dst.chainId, this.zyfaiRpcUrls)
5495
5604
  });
5605
+ const walletPublic = createPublicClient2({
5606
+ chain: srcChain,
5607
+ transport: custom(provider)
5608
+ });
5609
+ const signOnSource = (payload) => signWithChainRetry(
5610
+ walletPublic,
5611
+ wallet,
5612
+ quote.src.chainId,
5613
+ () => wallet.signTypedData({
5614
+ account: state.walletAddress,
5615
+ ...payload
5616
+ })
5617
+ );
5496
5618
  return {
5497
5619
  api: this.swapApi(),
5498
5620
  // Native-aware, like readSourceBalance below. Native ETH is never a
@@ -5533,10 +5655,7 @@ var OwneySDK = class {
5533
5655
  }
5534
5656
  return hash;
5535
5657
  },
5536
- signTypedData: (typedData) => wallet.signTypedData({
5537
- account: state.walletAddress,
5538
- ...typedData
5539
- }),
5658
+ signTypedData: signOnSource,
5540
5659
  // Chain-bound like every other read here: the wallet provider's chain is
5541
5660
  // not ours to rely on mid-swap.
5542
5661
  readSourceBalance: async () => {
@@ -5593,10 +5712,7 @@ var OwneySDK = class {
5593
5712
  spender,
5594
5713
  value: amount,
5595
5714
  chainId: quote.src.chainId,
5596
- signTypedData: (payload) => wallet.signTypedData({
5597
- account: state.walletAddress,
5598
- ...payload
5599
- })
5715
+ signTypedData: signOnSource
5600
5716
  }
5601
5717
  ),
5602
5718
  /**
@@ -6719,6 +6835,27 @@ var OwneySDK = class {
6719
6835
  }
6720
6836
  await agent.setPoolSelection(params.selection);
6721
6837
  }
6838
+ /**
6839
+ * The pool selection saved on the user's account (ROUT-650), so the Pools
6840
+ * step can show what applies now rather than the defaults. `pairs` and
6841
+ * `assets` say which protocol/chain lists and strategies to read.
6842
+ */
6843
+ async getPoolSelection(params) {
6844
+ const state = this.requireState();
6845
+ const chainId = this.requireChainId();
6846
+ await this.ensureAgentsInitialized();
6847
+ const agent = this.getAgent(params.agentId ?? "zyfai");
6848
+ if (!agent.getPoolSelection) {
6849
+ throw new OwneyError(
6850
+ "POOL_SELECTION_UNSUPPORTED",
6851
+ `Agent ${agent.id} does not support pool customization`
6852
+ );
6853
+ }
6854
+ return agent.getPoolSelection(state, chainId, {
6855
+ pairs: params.pairs,
6856
+ assets: params.assets
6857
+ });
6858
+ }
6722
6859
  async getAccountApy({
6723
6860
  agentId,
6724
6861
  days,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.7.28-beta.5",
3
+ "version": "0.7.28-beta.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -23,7 +23,7 @@
23
23
  "test:watch": "vitest"
24
24
  },
25
25
  "dependencies": {
26
- "@zyfai/sdk": "0.2.57",
26
+ "@zyfai/sdk": "0.11.2",
27
27
  "siwe": "^3.0.0",
28
28
  "viem": "^2.48.1"
29
29
  },