@alchemy/cli 0.7.3 → 0.7.4-alpha.37

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.js CHANGED
@@ -2,26 +2,27 @@
2
2
  if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
3
  import {
4
4
  registerAuth
5
- } from "./chunk-XSN4XA5Z.js";
5
+ } from "./chunk-2OUAYCVA.js";
6
6
  import {
7
7
  openBrowser
8
- } from "./chunk-C5HNQOLB.js";
8
+ } from "./chunk-WCZIVY4O.js";
9
9
  import {
10
10
  SETUP_CAPABILITY_LABELS,
11
11
  SETUP_CAPABILITY_ORDER,
12
12
  getSetupStatus,
13
13
  isSetupComplete,
14
14
  shouldRunOnboarding
15
- } from "./chunk-R4W44A6E.js";
15
+ } from "./chunk-UYZH6GSY.js";
16
16
  import {
17
17
  isInteractiveAllowed
18
- } from "./chunk-64A5W4M2.js";
18
+ } from "./chunk-AUGBYMHT.js";
19
19
  import {
20
20
  adminClientFromFlags,
21
21
  clearSession,
22
22
  clientFromFlags,
23
23
  createPendingSession,
24
24
  getRPCNetworks,
25
+ getWalletSessionByChain,
25
26
  isSessionValid,
26
27
  isSolanaNetwork,
27
28
  loadSession,
@@ -43,12 +44,12 @@ import {
43
44
  resolveX402Client,
44
45
  saveSession,
45
46
  updateSession
46
- } from "./chunk-K6V3R7SH.js";
47
+ } from "./chunk-5HYOZ773.js";
47
48
  import {
48
49
  getAvailableUpdate,
49
50
  getUpdateStatus,
50
51
  printUpdateNotice
51
- } from "./chunk-FD6YLNTB.js";
52
+ } from "./chunk-6UHKZ5EN.js";
52
53
  import {
53
54
  bold,
54
55
  brand,
@@ -72,7 +73,7 @@ import {
72
73
  weiToEth,
73
74
  withSpinner,
74
75
  yellow
75
- } from "./chunk-5IL2PMZ6.js";
76
+ } from "./chunk-HR2UZ6ZU.js";
76
77
  import {
77
78
  KEY_MAP,
78
79
  configDir,
@@ -83,7 +84,7 @@ import {
83
84
  save,
84
85
  toMap,
85
86
  validKeys
86
- } from "./chunk-JUCUKTP3.js";
87
+ } from "./chunk-PX2YJ7XC.js";
87
88
  import {
88
89
  CLIError,
89
90
  EXIT_CODES,
@@ -119,7 +120,7 @@ import {
119
120
  setFlags,
120
121
  setNoColor,
121
122
  verbose
122
- } from "./chunk-2BALTY22.js";
123
+ } from "./chunk-MYHXAACL.js";
123
124
 
124
125
  // src/index.ts
125
126
  import { Command, Help } from "commander";
@@ -626,7 +627,7 @@ function registerConfig(program2) {
626
627
  printJSON(toMap(cfg));
627
628
  return;
628
629
  }
629
- const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXT5ZCUK.js");
630
+ const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-PAQKIAX3.js");
630
631
  const validToken = resolveAuthToken2(cfg);
631
632
  const authStatus = cfg.auth_token ? validToken ? `${green("\u2713")} authenticated${cfg.auth_token_expires_at ? ` ${dim(`(expires ${cfg.auth_token_expires_at})`)}` : ""}` : `${yellow("\u25C6")} expired${cfg.auth_token_expires_at ? ` ${dim(`(${cfg.auth_token_expires_at})`)}` : ""}` : dim("(not set) \u2014 run 'alchemy auth' to log in");
632
633
  const pairs = [
@@ -1305,7 +1306,19 @@ var walletSessionCreateResponseSchema = z.object({
1305
1306
  approvalUrl: z.string().url(),
1306
1307
  expiresAt: z.string().datetime().optional()
1307
1308
  }).passthrough();
1309
+ var walletSessionRequestSessionCreateResponseSchema = z.object({
1310
+ walletSessionId: z.string().min(1),
1311
+ chainType: z.string().min(1),
1312
+ status: rawWalletSessionStateSchema.transform(normalizeWalletSessionState)
1313
+ }).passthrough();
1314
+ var walletSessionRequestCreateResponseSchema = z.object({
1315
+ sessionId: z.string().min(1),
1316
+ approvalUrl: z.string().url(),
1317
+ expiresAt: z.string().datetime().optional(),
1318
+ sessions: z.array(walletSessionRequestSessionCreateResponseSchema).min(1)
1319
+ }).passthrough();
1308
1320
  var rawWalletSessionStatusResponseSchema = z.object({
1321
+ type: z.literal("session").optional(),
1309
1322
  sessionId: z.string().min(1).optional(),
1310
1323
  status: rawWalletSessionStateSchema,
1311
1324
  expiresAt: z.string().datetime().optional(),
@@ -1321,6 +1334,15 @@ var rawWalletSessionStatusResponseSchema = z.object({
1321
1334
  chainType: z.string().min(1).optional(),
1322
1335
  capabilities: z.record(z.string(), z.boolean()).optional()
1323
1336
  }).passthrough();
1337
+ var walletSessionRequestStatusResponseSchema = z.object({
1338
+ type: z.literal("sessionRequest"),
1339
+ sessionId: z.string().min(1),
1340
+ sessions: z.array(
1341
+ rawWalletSessionStatusResponseSchema.extend({
1342
+ walletSessionId: z.string().min(1)
1343
+ })
1344
+ ).min(1)
1345
+ }).passthrough();
1324
1346
  var walletSessionDisconnectResponseSchema = z.object({
1325
1347
  sessionId: z.string().min(1).optional(),
1326
1348
  status: rawWalletSessionStateSchema.optional().transform(
@@ -1347,9 +1369,14 @@ var rawEvmSigningChallengeResponseSchema = z.object({
1347
1369
  challenge: z.string().min(1),
1348
1370
  expiresAt: z.string().datetime(),
1349
1371
  requestExpiry: z.string().min(1),
1350
- method: z.enum(["personal_sign", "eth_signTypedData_v4", "eth_sign7702Authorization"]),
1372
+ method: z.enum([
1373
+ "personal_sign",
1374
+ "eth_signTypedData_v4",
1375
+ "eth_sign7702Authorization",
1376
+ "signTransaction"
1377
+ ]),
1351
1378
  walletId: z.string().min(1),
1352
- walletAddress: z.string().regex(/^0x[a-fA-F0-9]{40}$/),
1379
+ walletAddress: z.string().min(1),
1353
1380
  providerKeyQuorumId: z.string().min(1).optional(),
1354
1381
  providerSignerId: z.string().min(1).optional()
1355
1382
  }).strict();
@@ -1375,6 +1402,10 @@ var signAuthorizationCompleteResponseSchema = z.object({
1375
1402
  y_parity: z.number().int()
1376
1403
  }).strict()
1377
1404
  }).strict();
1405
+ var solanaSignTransactionCompleteResponseSchema = z.object({
1406
+ signedTransaction: z.string().min(1),
1407
+ encoding: z.literal("base64")
1408
+ }).strict();
1378
1409
  function baseURLOverride() {
1379
1410
  const options = { allowedHostnames: [STAGING_ADMIN_API_HOST] };
1380
1411
  return parseBaseURLOverride(WALLET_API_BASE_URL_ENV, options) ?? parseBaseURLOverride(ADMIN_API_BASE_URL_ENV, options);
@@ -1468,6 +1499,17 @@ function normalizeWalletSessionStatus(session) {
1468
1499
  privySignerId: session.providerSignerId
1469
1500
  };
1470
1501
  }
1502
+ function normalizeWalletSessionRequestStatus(request2) {
1503
+ return {
1504
+ sessionId: request2.sessionId,
1505
+ sessions: request2.sessions.map(({ walletSessionId, ...session }) => {
1506
+ return normalizeWalletSessionStatus({
1507
+ ...session,
1508
+ sessionId: walletSessionId
1509
+ });
1510
+ })
1511
+ };
1512
+ }
1471
1513
  function normalizeEvmSigningChallengeResponse(response) {
1472
1514
  return {
1473
1515
  ...response,
@@ -1483,7 +1525,15 @@ function toProviderSigningBindingInput(input) {
1483
1525
  ...privySignerId ? { providerSignerId: privySignerId } : {}
1484
1526
  };
1485
1527
  }
1486
- async function createRemoteWalletSession(token, input) {
1528
+ function toProviderSolanaSigningBindingInput(input) {
1529
+ const { privyKeyQuorumId, privySignerId, ...rest } = input;
1530
+ return {
1531
+ ...rest,
1532
+ ...privyKeyQuorumId ? { providerKeyQuorumId: privyKeyQuorumId } : {},
1533
+ ...privySignerId ? { providerSignerId: privySignerId } : {}
1534
+ };
1535
+ }
1536
+ async function createRemoteWalletSessionRequest(token, input) {
1487
1537
  let data;
1488
1538
  let requestInput = input;
1489
1539
  for (let attempt = 0; attempt < 3; attempt += 1) {
@@ -1494,16 +1544,19 @@ async function createRemoteWalletSession(token, input) {
1494
1544
  "/wallet/sessions",
1495
1545
  requestInput
1496
1546
  );
1497
- return unwrapAdminData(walletSessionCreateResponseSchema, data);
1547
+ return unwrapAdminData(walletSessionRequestCreateResponseSchema, data);
1498
1548
  } catch (err) {
1499
- const retryInput = getClientInstanceCompatibilityRetryInput(requestInput, err);
1549
+ const retryInput = getClientInstanceCompatibilityRetryInput(
1550
+ requestInput,
1551
+ err
1552
+ );
1500
1553
  if (retryInput === void 0) {
1501
1554
  throw err;
1502
1555
  }
1503
1556
  requestInput = retryInput;
1504
1557
  }
1505
1558
  }
1506
- throw new CLIError(ErrorCode.NETWORK_ERROR, "Unable to create wallet session.");
1559
+ throw new CLIError(ErrorCode.NETWORK_ERROR, "Unable to create wallet session request.");
1507
1560
  }
1508
1561
  function getClientInstanceCompatibilityRetryInput(input, err) {
1509
1562
  if (input.environment.clientInstanceName !== void 0 && isUnsupportedClientInstanceMetadataError(err, "clientInstanceName")) {
@@ -1538,6 +1591,16 @@ async function getRemoteWalletSession(token, sessionId) {
1538
1591
  unwrapAdminData(rawWalletSessionStatusResponseSchema, data)
1539
1592
  );
1540
1593
  }
1594
+ async function getRemoteWalletSessionRequest(token, sessionId) {
1595
+ const data = await request(
1596
+ token,
1597
+ "GET",
1598
+ `/wallet/sessions/${encodeURIComponent(sessionId)}`
1599
+ );
1600
+ return normalizeWalletSessionRequestStatus(
1601
+ unwrapAdminData(walletSessionRequestStatusResponseSchema, data)
1602
+ );
1603
+ }
1541
1604
  async function disconnectRemoteWalletSession(token, sessionId) {
1542
1605
  try {
1543
1606
  const data = await request(
@@ -1616,6 +1679,24 @@ var signAuthorizationChallengeInputSchema = evmSigningSessionBindingBaseSchema.e
1616
1679
  executor: z.literal("self").optional()
1617
1680
  }).strict()
1618
1681
  }).strict().superRefine(ensureSessionSignerBinding);
1682
+ var solanaSigningSessionBindingBaseSchema = z.object({
1683
+ sessionId: z.string().uuid(),
1684
+ walletId: z.string().min(1),
1685
+ walletAddress: z.string().min(1),
1686
+ privyKeyQuorumId: z.string().min(1).optional(),
1687
+ privySignerId: z.string().min(1).optional()
1688
+ });
1689
+ var solanaSignTransactionChallengeInputSchema = solanaSigningSessionBindingBaseSchema.extend({
1690
+ transaction: z.string().min(1),
1691
+ encoding: z.literal("base64")
1692
+ }).strict().superRefine((input, ctx) => {
1693
+ if (!input.privyKeyQuorumId && !input.privySignerId) {
1694
+ ctx.addIssue({
1695
+ code: z.ZodIssueCode.custom,
1696
+ message: "Provide privyKeyQuorumId or privySignerId."
1697
+ });
1698
+ }
1699
+ });
1619
1700
  async function createRemoteSignTypedDataChallenge(token, input) {
1620
1701
  const parsedInput = signTypedDataChallengeInputSchema.parse(input);
1621
1702
  return createEvmSigningChallenge(
@@ -1654,6 +1735,25 @@ async function completeRemoteSignAuthorizationChallenge(token, input) {
1654
1735
  adminApiResponseSchema(signAuthorizationCompleteResponseSchema).transform((resp) => resp.data)
1655
1736
  );
1656
1737
  }
1738
+ async function createRemoteSolanaSignTransactionChallenge(token, input) {
1739
+ const parsedInput = solanaSignTransactionChallengeInputSchema.parse(input);
1740
+ return createEvmSigningChallenge(
1741
+ token,
1742
+ "/wallet/solana/sign-transaction/challenge",
1743
+ toProviderSolanaSigningBindingInput(parsedInput),
1744
+ adminApiResponseSchema(rawEvmSigningChallengeResponseSchema).transform(
1745
+ (resp) => normalizeEvmSigningChallengeResponse(resp.data)
1746
+ )
1747
+ );
1748
+ }
1749
+ async function completeRemoteSolanaSignTransactionChallenge(token, input) {
1750
+ return completeEvmSigningChallenge(
1751
+ token,
1752
+ "/wallet/solana/sign-transaction/complete",
1753
+ input,
1754
+ adminApiResponseSchema(solanaSignTransactionCompleteResponseSchema).transform((resp) => resp.data)
1755
+ );
1756
+ }
1657
1757
 
1658
1758
  // src/commands/wallet.ts
1659
1759
  import QRCode from "qrcode";
@@ -1664,6 +1764,9 @@ var DEFAULT_WALLET_CAPABILITIES = {
1664
1764
  "evm.signTypedData": true,
1665
1765
  "evm.signAuthorization": true
1666
1766
  };
1767
+ var DEFAULT_SOLANA_SESSION_CAPABILITIES = {
1768
+ "solana.signTransaction": true
1769
+ };
1667
1770
  function createEvmWallet() {
1668
1771
  const privateKey = generatePrivateKey();
1669
1772
  const account = privateKeyToAccount(privateKey);
@@ -1787,7 +1890,13 @@ async function withApprovalInterruptHandler(args) {
1787
1890
  return await args.run(controller.signal);
1788
1891
  } catch (err) {
1789
1892
  if (isWalletConnectInterruptedError(err)) {
1790
- await disconnectRemoteWalletSession(args.authToken, args.sessionId).catch(() => void 0);
1893
+ await Promise.all(
1894
+ args.sessionIds.map(
1895
+ (sessionId) => disconnectRemoteWalletSession(args.authToken, sessionId).catch(
1896
+ () => void 0
1897
+ )
1898
+ )
1899
+ );
1791
1900
  clearSession();
1792
1901
  }
1793
1902
  throw err;
@@ -1798,23 +1907,9 @@ async function withApprovalInterruptHandler(args) {
1798
1907
  }
1799
1908
  }
1800
1909
  }
1801
- function isFutureIsoDate(value) {
1802
- const date = new Date(value);
1803
- if (Number.isNaN(date.getTime())) {
1804
- return false;
1805
- }
1806
- return date > /* @__PURE__ */ new Date();
1807
- }
1808
- function isActiveWalletSession(session, remoteStatus) {
1809
- if (!session) return false;
1810
- if (session.status !== "approved") return false;
1811
- if (!isFutureIsoDate(session.expiresAt)) return false;
1812
- if (remoteStatus && remoteStatus !== "approved") return false;
1813
- return true;
1814
- }
1815
- function deriveWalletStatus(session, remoteStatus) {
1910
+ function deriveWalletStatus(session) {
1816
1911
  if (!session) return "none";
1817
- if (isActiveWalletSession(session, remoteStatus)) return "active";
1912
+ if (isSessionValid(session)) return "active";
1818
1913
  if (session.status === "pending") return "none";
1819
1914
  return "expired";
1820
1915
  }
@@ -1924,7 +2019,7 @@ function resolveQrAddress(args) {
1924
2019
  function missingQrWalletError(type, source) {
1925
2020
  if (source === "session") {
1926
2021
  return type === "solana" ? errInvalidArgs(
1927
- "The session wallet does not yet support Solana QR selection. Use `alchemy wallet use local` or configure a local Solana wallet with `alchemy wallet connect --mode local --chain solana`."
2022
+ "No Solana session wallet is configured. Run `alchemy wallet connect --mode session --force`."
1928
2023
  ) : errNoActiveSession();
1929
2024
  }
1930
2025
  if (source === "local") {
@@ -1935,20 +2030,6 @@ function missingQrWalletError(type, source) {
1935
2030
  function indentBlock(text, prefix = " ") {
1936
2031
  return text.split("\n").map((line) => line ? `${prefix}${line}` : line).join("\n");
1937
2032
  }
1938
- function generateAndPersistWallet() {
1939
- const wallet = createEvmWallet();
1940
- const keyPath = persistWalletKey("wallet-key", wallet.privateKey, wallet.address);
1941
- const cfg = load();
1942
- save({ ...cfg, wallet_key_file: keyPath, wallet_address: wallet.address });
1943
- return { address: wallet.address, keyFile: keyPath };
1944
- }
1945
- async function generateAndPersistSolanaWallet() {
1946
- const wallet = await createSolanaWallet();
1947
- const keyPath = persistWalletKey("solana-wallet-key", wallet.secretKey, wallet.address);
1948
- const cfg = load();
1949
- save({ ...cfg, solana_wallet_key_file: keyPath, solana_wallet_address: wallet.address });
1950
- return { address: wallet.address, keyFile: keyPath };
1951
- }
1952
2033
  async function createAndPersistWallets() {
1953
2034
  const evm = createEvmWallet();
1954
2035
  const solana = await createSolanaWallet();
@@ -2013,14 +2094,12 @@ function getEffectiveLocalWalletState(program2, cfg) {
2013
2094
  }
2014
2095
  async function runLocalCreate(opts) {
2015
2096
  const cfg = load();
2016
- const wantsEvm = opts.chain === "evm" || opts.chain === "both";
2017
- const wantsSolana = opts.chain === "solana" || opts.chain === "both";
2018
- const evmConflict = wantsEvm && Boolean(cfg.wallet_key_file);
2019
- const solanaConflict = wantsSolana && Boolean(cfg.solana_wallet_key_file);
2097
+ const evmConflict = Boolean(cfg.wallet_key_file);
2098
+ const solanaConflict = Boolean(cfg.solana_wallet_key_file);
2020
2099
  if ((evmConflict || solanaConflict) && !opts.force) {
2021
2100
  if (!isInteractiveAllowed(opts.program)) {
2022
2101
  throw errInvalidArgs(
2023
- "A local key is already configured for the selected chain. Re-run with --force to replace it."
2102
+ "A local key is already configured. Re-run with --force to replace it."
2024
2103
  );
2025
2104
  }
2026
2105
  const kinds = [evmConflict ? "EVM" : null, solanaConflict ? "Solana" : null].filter(Boolean).join(" and ");
@@ -2033,16 +2112,7 @@ async function runLocalCreate(opts) {
2033
2112
  throw errInvalidArgs("Aborted. Existing local key preserved.");
2034
2113
  }
2035
2114
  }
2036
- if (opts.chain === "both") {
2037
- const { evm, solana: solana2 } = await createAndPersistWallets();
2038
- return { evm, solana: solana2 };
2039
- }
2040
- if (opts.chain === "evm") {
2041
- const evm = generateAndPersistWallet();
2042
- return { evm };
2043
- }
2044
- const solana = await generateAndPersistSolanaWallet();
2045
- return { solana };
2115
+ return await createAndPersistWallets();
2046
2116
  }
2047
2117
  function runLocalImport(opts) {
2048
2118
  const cfg = load();
@@ -2075,7 +2145,27 @@ async function runLocalImportInteractive(opts) {
2075
2145
  return runLocalImport({ ...opts, force: true });
2076
2146
  }
2077
2147
  }
2148
+ function capabilitiesForChain(chain) {
2149
+ return chain === "evm" ? { ...DEFAULT_WALLET_CAPABILITIES } : { ...DEFAULT_SOLANA_SESSION_CAPABILITIES };
2150
+ }
2151
+ function capabilitiesForChains(chains) {
2152
+ return Object.fromEntries(
2153
+ chains.map((chain) => [chain, capabilitiesForChain(chain)])
2154
+ );
2155
+ }
2156
+ function getApprovedSessionWalletMetadata(chain, session) {
2157
+ const walletId = chain === "evm" ? session.walletId ?? session.evmWalletId : session.solanaWalletId ?? session.walletId;
2158
+ const walletAddress = chain === "evm" ? session.evmAddress ?? session.address : session.solanaAddress ?? session.address;
2159
+ if (!walletId || !walletAddress) {
2160
+ throw new CLIError(
2161
+ ErrorCode.INTERNAL_ERROR,
2162
+ "Approved wallet session response missing required metadata."
2163
+ );
2164
+ }
2165
+ return { walletId, walletAddress };
2166
+ }
2078
2167
  async function runSessionConnect(opts) {
2168
+ const requestedChains = ["evm", "solana"];
2079
2169
  const authToken = resolveAuthToken();
2080
2170
  if (!authToken) throw errAuthRequired();
2081
2171
  const existing = loadSession();
@@ -2113,32 +2203,51 @@ async function runSessionConnect(opts) {
2113
2203
  ...clientInstance.name === void 0 ? {} : { clientInstanceName: clientInstance.name }
2114
2204
  };
2115
2205
  updateSession({
2116
- chainType: "evm",
2117
- capabilities: { ...DEFAULT_WALLET_CAPABILITIES },
2206
+ chainType: "both",
2207
+ capabilities: Object.assign(
2208
+ {},
2209
+ ...requestedChains.map((chain) => capabilitiesForChain(chain))
2210
+ ),
2118
2211
  backendBaseUrl: getWalletApiBaseUrl(),
2119
2212
  environment: sessionEnvironment
2120
2213
  });
2121
- const remoteSession = await createRemoteWalletSession(authToken, {
2214
+ const remoteRequest = await createRemoteWalletSessionRequest(authToken, {
2122
2215
  publicKeyJwk: session.publicKeyJwk,
2123
2216
  requestSignerVersion: session.envelopeVersion,
2124
- chainType: "evm",
2125
- capabilities: { ...DEFAULT_WALLET_CAPABILITIES },
2217
+ chains: requestedChains,
2218
+ capabilities: capabilitiesForChains(requestedChains),
2126
2219
  environment: sessionEnvironment
2127
2220
  }).catch((err) => {
2128
2221
  clearSession();
2129
2222
  throw err;
2130
2223
  });
2224
+ const pendingSessionsByChain = Object.fromEntries(
2225
+ remoteRequest.sessions.map((remoteSession) => [
2226
+ remoteSession.chainType,
2227
+ {
2228
+ sessionId: remoteSession.walletSessionId,
2229
+ status: "pending",
2230
+ expiresAt: remoteRequest.expiresAt ?? session.expiresAt,
2231
+ chainType: remoteSession.chainType,
2232
+ capabilities: capabilitiesForChain(
2233
+ remoteSession.chainType
2234
+ )
2235
+ }
2236
+ ])
2237
+ );
2131
2238
  updateSession({
2132
- sessionId: remoteSession.sessionId,
2133
- expiresAt: remoteSession.expiresAt ?? session.expiresAt
2239
+ connectionRequestId: remoteRequest.sessionId,
2240
+ sessionId: remoteRequest.sessions[0].walletSessionId,
2241
+ expiresAt: remoteRequest.expiresAt ?? session.expiresAt,
2242
+ sessionsByChain: pendingSessionsByChain
2134
2243
  });
2135
2244
  if (!isJSONMode()) {
2136
2245
  const summaryPairs = [
2137
- ["Session ID", remoteSession.sessionId],
2246
+ ["Connection Request ID", remoteRequest.sessionId],
2138
2247
  ["Status", "pending"],
2139
- ["Approval URL", remoteSession.approvalUrl],
2248
+ ["Approval URL", remoteRequest.approvalUrl],
2140
2249
  ["Created", session.createdAt],
2141
- ["Expires", remoteSession.expiresAt ?? session.expiresAt]
2250
+ ["Expires", remoteRequest.expiresAt ?? session.expiresAt]
2142
2251
  ];
2143
2252
  if (clientInstance.name !== void 0) {
2144
2253
  summaryPairs.splice(1, 0, ["Instance", clientInstance.name]);
@@ -2153,7 +2262,14 @@ async function runSessionConnect(opts) {
2153
2262
  });
2154
2263
  if (answer === null) {
2155
2264
  clearSession();
2156
- await disconnectRemoteWalletSession(authToken, remoteSession.sessionId).catch(() => void 0);
2265
+ await Promise.all(
2266
+ remoteRequest.sessions.map(
2267
+ (remoteSession) => disconnectRemoteWalletSession(
2268
+ authToken,
2269
+ remoteSession.walletSessionId
2270
+ ).catch(() => void 0)
2271
+ )
2272
+ );
2157
2273
  throw new WalletConnectInterruptedError();
2158
2274
  }
2159
2275
  }
@@ -2161,25 +2277,41 @@ async function runSessionConnect(opts) {
2161
2277
  console.log(` Opening browser for approval...`);
2162
2278
  console.log(` ${dim("Waiting for dashboard approval to complete connection.")}`);
2163
2279
  }
2164
- openBrowser(remoteSession.approvalUrl);
2165
- const approvedSession = await withApprovalInterruptHandler({
2280
+ openBrowser(remoteRequest.approvalUrl);
2281
+ const approvedSessions = await withApprovalInterruptHandler({
2166
2282
  authToken,
2167
- sessionId: remoteSession.sessionId,
2283
+ sessionIds: remoteRequest.sessions.map(
2284
+ (remoteSession) => remoteSession.walletSessionId
2285
+ ),
2168
2286
  run: async (signal) => {
2169
2287
  const startedAt = Date.now();
2170
2288
  while (Date.now() - startedAt < CONNECT_TIMEOUT_MS) {
2171
- const current = await waitForInterruptible(
2172
- getRemoteWalletSession(authToken, remoteSession.sessionId),
2289
+ const currentSessions = await waitForInterruptible(
2290
+ remoteRequest.sessionId ? getRemoteWalletSessionRequest(
2291
+ authToken,
2292
+ remoteRequest.sessionId
2293
+ ).then((request2) => request2.sessions) : Promise.all(
2294
+ remoteRequest.sessions.map(
2295
+ (remoteSession) => getRemoteWalletSession(authToken, remoteSession.walletSessionId)
2296
+ )
2297
+ ),
2173
2298
  signal
2174
2299
  );
2175
- if (current.status === "approved") {
2176
- return current;
2300
+ if (requestedChains.every(
2301
+ (chain) => currentSessions.some((current) => {
2302
+ return current.chainType === chain && current.status === "approved";
2303
+ })
2304
+ )) {
2305
+ return currentSessions;
2177
2306
  }
2178
- if (current.status === "denied" || current.status === "revoked" || current.status === "expired") {
2307
+ const terminalSession = currentSessions.find((current) => {
2308
+ return current.status === "denied" || current.status === "revoked" || current.status === "expired";
2309
+ });
2310
+ if (terminalSession) {
2179
2311
  clearSession();
2180
2312
  throw new CLIError(
2181
2313
  ErrorCode.INTERNAL_ERROR,
2182
- `Wallet session ${current.status}.`,
2314
+ `Wallet session ${terminalSession.status}.`,
2183
2315
  "Run 'alchemy wallet connect' to start a new approval flow."
2184
2316
  );
2185
2317
  }
@@ -2188,58 +2320,123 @@ async function runSessionConnect(opts) {
2188
2320
  return null;
2189
2321
  }
2190
2322
  });
2191
- if (!approvedSession) {
2323
+ if (!approvedSessions) {
2192
2324
  throw new CLIError(
2193
2325
  ErrorCode.NETWORK_ERROR,
2194
2326
  "Timed out waiting for wallet approval.",
2195
2327
  "Finish approval in the dashboard and rerun 'alchemy wallet connect --force' if needed."
2196
2328
  );
2197
2329
  }
2198
- const walletId = approvedSession.walletId ?? approvedSession.evmWalletId;
2199
- const evmAddress = approvedSession.evmAddress ?? approvedSession.address;
2200
- if (!approvedSession.privyAppId || !walletId || !evmAddress) {
2330
+ const missingProviderAppId = approvedSessions.find((approvedSession) => {
2331
+ return !approvedSession.privyAppId;
2332
+ });
2333
+ if (missingProviderAppId) {
2201
2334
  throw new CLIError(
2202
2335
  ErrorCode.INTERNAL_ERROR,
2203
2336
  "Approved wallet session response missing required metadata."
2204
2337
  );
2205
2338
  }
2339
+ const approvedSessionsByChain = Object.fromEntries(
2340
+ requestedChains.map((chain) => {
2341
+ const approvedSession = approvedSessions.find((current) => {
2342
+ return current.chainType === chain;
2343
+ });
2344
+ if (!approvedSession) {
2345
+ throw new CLIError(
2346
+ ErrorCode.INTERNAL_ERROR,
2347
+ "Approved wallet session response missing requested chain."
2348
+ );
2349
+ }
2350
+ const { walletId, walletAddress } = getApprovedSessionWalletMetadata(
2351
+ chain,
2352
+ approvedSession
2353
+ );
2354
+ return [
2355
+ chain,
2356
+ {
2357
+ sessionId: approvedSession.sessionId ?? remoteRequest.sessions.find((remoteSession) => remoteSession.chainType === chain)?.walletSessionId ?? session.sessionId,
2358
+ status: "approved",
2359
+ expiresAt: approvedSession.expiresAt ?? remoteRequest.expiresAt ?? session.expiresAt,
2360
+ chainType: chain,
2361
+ walletId,
2362
+ walletAddress,
2363
+ providerKeyQuorumId: approvedSession.privyKeyQuorumId,
2364
+ providerSignerId: approvedSession.privySignerId,
2365
+ capabilities: approvedSession.capabilities ?? capabilitiesForChain(chain)
2366
+ }
2367
+ ];
2368
+ })
2369
+ );
2370
+ const firstApprovedSession = approvedSessions.find((approvedSession) => {
2371
+ return approvedSession.chainType === requestedChains[0];
2372
+ }) ?? approvedSessions[0];
2373
+ const evmSession = approvedSessionsByChain.evm;
2374
+ const solanaSession = approvedSessionsByChain.solana;
2206
2375
  updateSession({
2207
- sessionId: approvedSession.sessionId ?? remoteSession.sessionId,
2376
+ connectionRequestId: remoteRequest.sessionId,
2377
+ sessionId: firstApprovedSession.sessionId ?? remoteRequest.sessions[0].walletSessionId,
2208
2378
  status: "approved",
2209
- expiresAt: approvedSession.expiresAt ?? remoteSession.expiresAt ?? session.expiresAt,
2210
- privyAppId: approvedSession.privyAppId,
2211
- walletId,
2212
- evmWalletId: approvedSession.evmWalletId ?? walletId,
2213
- evmAddress,
2214
- solanaWalletId: approvedSession.solanaWalletId,
2215
- solanaAddress: approvedSession.solanaAddress,
2216
- privyKeyQuorumId: approvedSession.privyKeyQuorumId,
2217
- privySignerId: approvedSession.privySignerId,
2218
- chainType: approvedSession.chainType ?? "evm",
2219
- capabilities: approvedSession.capabilities ?? { ...DEFAULT_WALLET_CAPABILITIES },
2379
+ expiresAt: firstApprovedSession.expiresAt ?? remoteRequest.expiresAt ?? session.expiresAt,
2380
+ privyAppId: firstApprovedSession.privyAppId,
2381
+ walletId: evmSession?.walletId ?? solanaSession?.walletId,
2382
+ evmWalletId: evmSession?.walletId,
2383
+ evmAddress: evmSession?.walletAddress,
2384
+ solanaWalletId: solanaSession?.walletId,
2385
+ solanaAddress: solanaSession?.walletAddress,
2386
+ privyKeyQuorumId: evmSession?.providerKeyQuorumId ?? solanaSession?.providerKeyQuorumId,
2387
+ privySignerId: evmSession?.providerSignerId ?? solanaSession?.providerSignerId,
2388
+ chainType: "both",
2389
+ capabilities: Object.assign(
2390
+ {},
2391
+ ...requestedChains.map((chain) => capabilitiesForChain(chain)),
2392
+ ...approvedSessions.map((approvedSession) => approvedSession.capabilities ?? {})
2393
+ ),
2394
+ sessionsByChain: approvedSessionsByChain,
2220
2395
  backendBaseUrl: getWalletApiBaseUrl(),
2221
2396
  environment: sessionEnvironment
2222
2397
  });
2223
2398
  if (isJSONMode()) {
2224
2399
  printJSON({
2225
- sessionId: approvedSession.sessionId ?? remoteSession.sessionId,
2400
+ connectionRequestId: remoteRequest.sessionId,
2401
+ sessionId: firstApprovedSession.sessionId ?? remoteRequest.sessions[0].walletSessionId,
2402
+ walletSessionId: firstApprovedSession.sessionId ?? remoteRequest.sessions[0].walletSessionId,
2226
2403
  status: "approved",
2227
- privyAppId: approvedSession.privyAppId,
2228
- walletId,
2229
- evmAddress,
2230
- evmWalletId: approvedSession.evmWalletId ?? walletId,
2231
- chainType: approvedSession.chainType ?? "evm",
2232
- capabilities: approvedSession.capabilities ?? { ...DEFAULT_WALLET_CAPABILITIES },
2233
- expiresAt: approvedSession.expiresAt ?? remoteSession.expiresAt ?? session.expiresAt
2404
+ privyAppId: firstApprovedSession.privyAppId,
2405
+ walletId: evmSession?.walletId ?? solanaSession?.walletId,
2406
+ ...evmSession ? {
2407
+ evmAddress: evmSession.walletAddress,
2408
+ evmWalletId: evmSession.walletId
2409
+ } : {},
2410
+ ...solanaSession ? {
2411
+ solanaAddress: solanaSession.walletAddress,
2412
+ solanaWalletId: solanaSession.walletId
2413
+ } : {},
2414
+ chainType: "both",
2415
+ capabilities: Object.assign(
2416
+ {},
2417
+ ...requestedChains.map((chain) => capabilitiesForChain(chain))
2418
+ ),
2419
+ expiresAt: firstApprovedSession.expiresAt ?? remoteRequest.expiresAt ?? session.expiresAt,
2420
+ sessionsByChain: approvedSessionsByChain
2234
2421
  });
2235
2422
  } else {
2236
- printKeyValue([
2237
- ["Session ID", approvedSession.sessionId ?? remoteSession.sessionId],
2238
- ["Status", green("approved")],
2239
- ["Wallet ID", walletId],
2240
- ["EVM Address", green(evmAddress)],
2241
- ["Expires", approvedSession.expiresAt ?? remoteSession.expiresAt ?? session.expiresAt]
2423
+ const pairs = [
2424
+ ["Connection Request ID", remoteRequest.sessionId],
2425
+ ["Status", green("approved")]
2426
+ ];
2427
+ for (const chain of requestedChains) {
2428
+ const chainSession = approvedSessionsByChain[chain];
2429
+ if (!chainSession) continue;
2430
+ pairs.push(
2431
+ [`${chain.toUpperCase()} Wallet ID`, chainSession.walletId ?? ""],
2432
+ [`${chain.toUpperCase()} Address`, green(chainSession.walletAddress ?? "")]
2433
+ );
2434
+ }
2435
+ pairs.push([
2436
+ "Expires",
2437
+ firstApprovedSession.expiresAt ?? remoteRequest.expiresAt ?? session.expiresAt
2242
2438
  ]);
2439
+ printKeyValue(pairs);
2243
2440
  console.log(` ${green("\u2713")} Wallet connected`);
2244
2441
  }
2245
2442
  }
@@ -2308,17 +2505,6 @@ async function runConnectFlow(program2, opts) {
2308
2505
  }
2309
2506
  mode2 = "local";
2310
2507
  }
2311
- let chain = "both";
2312
- if (opts.chain !== void 0) {
2313
- if (opts.chain !== "evm" && opts.chain !== "solana" && opts.chain !== "both") {
2314
- throw errInvalidArgs("`--chain` must be 'evm', 'solana', or 'both'.");
2315
- }
2316
- chain = opts.chain;
2317
- }
2318
- if (importPath && chain !== "evm" && opts.chain !== void 0) {
2319
- throw errInvalidArgs("`--import` implies `--chain evm`; omit `--chain` or set it to 'evm'.");
2320
- }
2321
- if (importPath) chain = "evm";
2322
2508
  if (!mode2) {
2323
2509
  if (!isInteractiveAllowed(program2)) {
2324
2510
  throw errInvalidArgs(
@@ -2328,7 +2514,7 @@ async function runConnectFlow(program2, opts) {
2328
2514
  const choice = await promptSelect({
2329
2515
  message: "Choose a wallet to connect",
2330
2516
  options: [
2331
- { value: "session", label: "Session wallet", hint: "Recommended \u2014 Alchemy/Privy-managed, more secure" },
2517
+ { value: "session", label: "Session wallet", hint: "Recommended \u2014 Alchemy-managed, more secure" },
2332
2518
  { value: "local", label: "Local wallet", hint: "Private key stored on this machine" }
2333
2519
  ],
2334
2520
  initialValue: "session",
@@ -2338,7 +2524,11 @@ async function runConnectFlow(program2, opts) {
2338
2524
  mode2 = choice;
2339
2525
  }
2340
2526
  if (mode2 === "session") {
2341
- await runSessionConnect({ program: program2, force, instanceName: opts.instanceName });
2527
+ await runSessionConnect({
2528
+ program: program2,
2529
+ force,
2530
+ instanceName: opts.instanceName
2531
+ });
2342
2532
  printCrossModeHintAfterSessionConnect();
2343
2533
  return;
2344
2534
  }
@@ -2348,9 +2538,30 @@ async function runConnectFlow(program2, opts) {
2348
2538
  printCrossModeHintAfterLocal("evm");
2349
2539
  return;
2350
2540
  }
2351
- const result = await runLocalCreate({ chain, force, program: program2 });
2541
+ const result = await runLocalCreate({ force, program: program2 });
2352
2542
  printPostLocalCreateSummary(result);
2353
- printCrossModeHintAfterLocal(chain);
2543
+ printCrossModeHintAfterLocal("both");
2544
+ }
2545
+ function uniqueSessionIds(session) {
2546
+ const ids = Object.values(session.sessionsByChain ?? {}).map((chainSession) => chainSession?.sessionId).filter((sessionId) => Boolean(sessionId));
2547
+ if (ids.length === 0) {
2548
+ ids.push(session.sessionId);
2549
+ }
2550
+ return Array.from(new Set(ids));
2551
+ }
2552
+ function selectRemoteSessionForStatus(session, remoteSessions) {
2553
+ return remoteSessions.find((remoteSession) => {
2554
+ return remoteSession.status !== "approved";
2555
+ }) ?? remoteSessions.find((remoteSession) => {
2556
+ return remoteSession.sessionId === session.sessionId;
2557
+ }) ?? remoteSessions[0];
2558
+ }
2559
+ function mergeRemoteCapabilities(session, remoteSessions) {
2560
+ return Object.assign(
2561
+ {},
2562
+ session.capabilities ?? {},
2563
+ ...remoteSessions.map((remoteSession) => remoteSession.capabilities ?? {})
2564
+ );
2354
2565
  }
2355
2566
  async function buildSessionSnapshot(program2, verify) {
2356
2567
  let session = loadStoredSession?.() ?? loadSession();
@@ -2358,25 +2569,55 @@ async function buildSessionSnapshot(program2, verify) {
2358
2569
  if (verify && session) {
2359
2570
  const authToken = resolveAuthToken();
2360
2571
  if (!authToken) throw errAuthRequired();
2361
- const remote = await getRemoteWalletSession(authToken, session.sessionId);
2572
+ const remoteSessions = session.connectionRequestId ? await getRemoteWalletSessionRequest(authToken, session.connectionRequestId).then((request2) => request2.sessions) : await Promise.all(
2573
+ uniqueSessionIds(session).map(
2574
+ (sessionId) => getRemoteWalletSession(authToken, sessionId)
2575
+ )
2576
+ );
2577
+ const remote = selectRemoteSessionForStatus(session, remoteSessions);
2362
2578
  remoteStatus = remote.status;
2363
- const walletId2 = remote.walletId ?? remote.evmWalletId;
2579
+ const nextSessionsByChain = { ...session.sessionsByChain ?? {} };
2580
+ for (const remoteSession of remoteSessions) {
2581
+ const chain = remoteSession.chainType === "solana" ? "solana" : "evm";
2582
+ const walletIdForChain = chain === "solana" ? remoteSession.solanaWalletId ?? remoteSession.walletId : remoteSession.evmWalletId ?? remoteSession.walletId;
2583
+ const walletAddressForChain = chain === "solana" ? remoteSession.solanaAddress ?? remoteSession.address : remoteSession.evmAddress ?? remoteSession.address;
2584
+ nextSessionsByChain[chain] = {
2585
+ ...nextSessionsByChain[chain] ?? {},
2586
+ sessionId: remoteSession.sessionId ?? nextSessionsByChain[chain]?.sessionId ?? session.sessionId,
2587
+ status: normalizeRemoteStatusForStorage(remoteSession.status),
2588
+ expiresAt: remoteSession.expiresAt ?? nextSessionsByChain[chain]?.expiresAt ?? session.expiresAt,
2589
+ chainType: chain,
2590
+ ...walletIdForChain ? { walletId: walletIdForChain } : {},
2591
+ ...walletAddressForChain ? { walletAddress: walletAddressForChain } : {},
2592
+ ...remoteSession.privyKeyQuorumId ? { providerKeyQuorumId: remoteSession.privyKeyQuorumId } : {},
2593
+ ...remoteSession.privySignerId ? { providerSignerId: remoteSession.privySignerId } : {},
2594
+ ...remoteSession.capabilities ? { capabilities: remoteSession.capabilities } : {}
2595
+ };
2596
+ }
2597
+ const remoteChain = remote.chainType === "solana" ? "solana" : "evm";
2598
+ const remoteWalletId = remoteChain === "solana" ? remote.solanaWalletId ?? remote.walletId : remote.evmWalletId ?? remote.walletId;
2599
+ const evmWalletId = remoteChain === "evm" ? remoteWalletId ?? session.evmWalletId : session.evmWalletId;
2600
+ const evmAddress = remoteChain === "evm" ? remote.evmAddress ?? remote.address ?? session.evmAddress : session.evmAddress;
2601
+ const solanaWalletId = remoteChain === "solana" ? remoteWalletId ?? session.solanaWalletId : session.solanaWalletId;
2602
+ const solanaAddress = remoteChain === "solana" ? remote.solanaAddress ?? remote.address ?? session.solanaAddress : session.solanaAddress;
2603
+ const chainType = nextSessionsByChain.evm && nextSessionsByChain.solana ? "both" : remote.chainType ?? session.chainType;
2364
2604
  session = {
2365
2605
  ...session,
2366
2606
  status: normalizeRemoteStatusForStorage(remote.status),
2367
2607
  expiresAt: remote.expiresAt ?? session.expiresAt,
2368
2608
  privyAppId: remote.privyAppId ?? session.privyAppId,
2369
- walletId: walletId2 ?? session.walletId,
2370
- evmWalletId: remote.evmWalletId ?? walletId2 ?? session.evmWalletId,
2371
- evmAddress: remote.evmAddress ?? remote.address ?? session.evmAddress,
2372
- solanaWalletId: remote.solanaWalletId ?? session.solanaWalletId,
2373
- solanaAddress: remote.solanaAddress ?? session.solanaAddress,
2374
- chainType: remote.chainType ?? session.chainType,
2375
- capabilities: remote.capabilities ?? session.capabilities
2609
+ walletId: evmWalletId ?? solanaWalletId ?? session.walletId,
2610
+ evmWalletId,
2611
+ evmAddress,
2612
+ solanaWalletId,
2613
+ solanaAddress,
2614
+ chainType,
2615
+ capabilities: mergeRemoteCapabilities(session, remoteSessions),
2616
+ sessionsByChain: nextSessionsByChain
2376
2617
  };
2377
2618
  saveSession(session);
2378
2619
  }
2379
- const status = deriveWalletStatus(session, remoteStatus ?? void 0);
2620
+ const status = deriveWalletStatus(session);
2380
2621
  const walletAddress = resolveSessionAddress(session);
2381
2622
  const environment = resolveSessionEnvironment(session);
2382
2623
  const signerCapabilities = resolveEnabledCapabilities(session);
@@ -2392,14 +2633,16 @@ async function buildSessionSnapshot(program2, verify) {
2392
2633
  walletId,
2393
2634
  expiresAt,
2394
2635
  sessionId: session?.sessionId ?? null,
2636
+ connectionRequestId: session?.connectionRequestId ?? null,
2395
2637
  sessionState: session?.status ?? null,
2396
2638
  chainType: session?.chainType ?? null,
2639
+ sessionsByChain: session?.sessionsByChain ?? null,
2397
2640
  valid: session ? isSessionValid(session) : false
2398
2641
  };
2399
2642
  }
2400
2643
  function registerWallets(program2) {
2401
2644
  const cmd = program2.command("wallet").description("Manage wallets");
2402
- cmd.command("connect").description("Connect a wallet for onchain actions (session or local)").option("--mode <mode>", "session | local").option("--chain <chain>", "For --mode local: evm | solana | both (default: both)").option("--import <path>", "For --mode local: import EVM key from file (implies --chain evm)").option("--instance-name <name>", "For --mode session: name this CLI instance").option("--force", "Replace the existing signer").action(async (opts) => {
2645
+ cmd.command("connect").description("Connect a wallet for onchain actions (session or local)").option("--mode <mode>", "session | local").option("--import <path>", "For --mode local: import an EVM key from file instead of creating both wallets").option("--instance-name <name>", "For --mode session: name this CLI instance").option("--force", "Replace the existing signer").action(async (opts) => {
2403
2646
  try {
2404
2647
  await runConnectFlow(program2, opts);
2405
2648
  } catch (err) {
@@ -2429,10 +2672,12 @@ function registerWallets(program2) {
2429
2672
  expiresAt: snap.expiresAt,
2430
2673
  environment: snap.environment,
2431
2674
  signerCapabilities: snap.signerCapabilities,
2675
+ connectionRequestId: snap.connectionRequestId,
2432
2676
  sessionId: snap.sessionId,
2433
2677
  sessionState: snap.sessionState,
2434
2678
  walletId: snap.walletId,
2435
2679
  chainType: snap.chainType,
2680
+ sessionsByChain: snap.sessionsByChain,
2436
2681
  verified: Boolean(opts.verify),
2437
2682
  remoteStatus: snap.remoteStatus,
2438
2683
  valid: snap.valid,
@@ -2443,10 +2688,12 @@ function registerWallets(program2) {
2443
2688
  expiresAt: snap.expiresAt,
2444
2689
  environment: snap.environment,
2445
2690
  signerCapabilities: snap.signerCapabilities,
2691
+ connectionRequestId: snap.connectionRequestId,
2446
2692
  sessionId: snap.sessionId,
2447
2693
  sessionState: snap.sessionState,
2448
2694
  walletId: snap.walletId,
2449
2695
  chainType: snap.chainType,
2696
+ sessionsByChain: snap.sessionsByChain,
2450
2697
  valid: snap.valid
2451
2698
  },
2452
2699
  localEvm: localState.evmAddress ? { address: localState.evmAddress, keyFile: localState.evmKeyFile } : null,
@@ -2464,7 +2711,11 @@ function registerWallets(program2) {
2464
2711
  ["Environment", snap.environment ?? dim("none")],
2465
2712
  ["Signer Capabilities", snap.signerCapabilities.length > 0 ? snap.signerCapabilities.join(", ") : dim("none")]
2466
2713
  ];
2467
- if (snap.sessionId) pairs.push(["Session ID", snap.sessionId]);
2714
+ if (snap.connectionRequestId) {
2715
+ pairs.push(["Connection Request ID", snap.connectionRequestId]);
2716
+ } else if (snap.sessionId) {
2717
+ pairs.push(["Session ID", snap.sessionId]);
2718
+ }
2468
2719
  if (snap.walletId) pairs.push(["Wallet ID", snap.walletId]);
2469
2720
  if (opts.verify) {
2470
2721
  pairs.push(["Backend Status", snap.remoteStatus ?? dim("not checked")]);
@@ -2619,7 +2870,7 @@ function registerWallets(program2) {
2619
2870
  }
2620
2871
  if (target === "local" && !hasLocalEvmKey()) {
2621
2872
  throw errInvalidArgs(
2622
- "No local EVM key configured. Run `alchemy wallet connect --mode local --chain evm` first."
2873
+ "No local EVM key configured. Run `alchemy wallet connect --mode local` first."
2623
2874
  );
2624
2875
  }
2625
2876
  const cfg = load();
@@ -2634,8 +2885,11 @@ function registerWallets(program2) {
2634
2885
  exitWithError(err);
2635
2886
  }
2636
2887
  });
2637
- cmd.command("disconnect").description("Revoke the current wallet session").action(async () => {
2888
+ cmd.command("disconnect").description("Revoke the current wallet session").option("--chain <chain>", "evm | solana").action(async (opts) => {
2638
2889
  try {
2890
+ if (opts.chain !== void 0 && opts.chain !== "evm" && opts.chain !== "solana") {
2891
+ throw errInvalidArgs("`--chain` must be 'evm' or 'solana'.");
2892
+ }
2639
2893
  const session = loadStoredSession?.() ?? loadSession();
2640
2894
  if (!session) {
2641
2895
  if (isJSONMode()) {
@@ -2653,15 +2907,40 @@ function registerWallets(program2) {
2653
2907
  let revoked = false;
2654
2908
  let alreadyDisconnected = false;
2655
2909
  let remoteStatus = null;
2910
+ const sessionsToDisconnect = opts.chain ? [
2911
+ getWalletSessionByChain(
2912
+ session,
2913
+ opts.chain
2914
+ )
2915
+ ].filter(
2916
+ (value) => value !== null
2917
+ ) : Object.values(session.sessionsByChain ?? {}).filter(
2918
+ (value) => value !== void 0
2919
+ ).map(
2920
+ (chainSession) => getWalletSessionByChain(session, chainSession.chainType)
2921
+ ).filter(
2922
+ (value) => value !== null
2923
+ );
2924
+ const disconnectTargets = sessionsToDisconnect.length > 0 ? sessionsToDisconnect : [session];
2656
2925
  if (authToken) {
2657
- const remote = await disconnectRemoteWalletSession(authToken, session.sessionId);
2658
- revoked = !remote.alreadyDisconnected;
2659
- alreadyDisconnected = remote.alreadyDisconnected;
2660
- remoteStatus = remote.status;
2661
- }
2662
- const removed = clearSession();
2926
+ const results = await Promise.all(
2927
+ disconnectTargets.map(
2928
+ (target) => disconnectRemoteWalletSession(authToken, target.sessionId)
2929
+ )
2930
+ );
2931
+ revoked = results.some((remote) => !remote.alreadyDisconnected);
2932
+ alreadyDisconnected = results.every((remote) => remote.alreadyDisconnected);
2933
+ remoteStatus = results[0]?.status ?? null;
2934
+ }
2935
+ const removed = opts.chain === void 0 ? clearSession() : updateSession({
2936
+ sessionsByChain: {
2937
+ ...session.sessionsByChain ?? {},
2938
+ [opts.chain]: void 0
2939
+ },
2940
+ ...opts.chain === "evm" ? { evmWalletId: void 0, evmAddress: void 0 } : { solanaWalletId: void 0, solanaAddress: void 0 }
2941
+ }) != null;
2663
2942
  const cfg = load();
2664
- if (cfg.active_signer === "session") {
2943
+ if (cfg.active_signer === "session" && opts.chain !== "solana") {
2665
2944
  const { active_signer: _omit, ...rest } = cfg;
2666
2945
  save(rest);
2667
2946
  }
@@ -3056,9 +3335,10 @@ import {
3056
3335
  createKeyPairSignerFromBytes as createKeyPairSignerFromBytes2,
3057
3336
  createKeyPairSignerFromPrivateKeyBytes as createKeyPairSignerFromPrivateKeyBytes2
3058
3337
  } from "@solana/kit";
3059
- import { getTransferSolInstruction } from "@solana-program/system";
3338
+ import { sign as signWithPrivateKey } from "crypto";
3060
3339
  var SOL_DECIMALS = 9;
3061
3340
  var SPONSOR_FEE_PAYER_PLACEHOLDER = address("Amh6quo1FcmL16Qmzdugzjq3Lv1zXzTW7ktswyLDzits");
3341
+ var SYSTEM_PROGRAM_ADDRESS = address("11111111111111111111111111111111");
3062
3342
  var SPL_TOKEN_PROGRAM_ADDRESS = address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
3063
3343
  function parseSolanaKeyBytes(secret) {
3064
3344
  const trimmed = secret.trim();
@@ -3089,11 +3369,28 @@ async function createSolanaSignerFromKeyBytes(keyBytes) {
3089
3369
  throw errInvalidArgs("Invalid Solana key: expected 64-byte secret key or 32-byte private key.");
3090
3370
  }
3091
3371
  function buildSolTransferInstruction(from, to, lamports) {
3092
- return getTransferSolInstruction({
3093
- source: from,
3094
- destination: to,
3095
- amount: lamports
3096
- });
3372
+ return {
3373
+ programAddress: SYSTEM_PROGRAM_ADDRESS,
3374
+ accounts: [
3375
+ { address: from.address, role: AccountRole.WRITABLE_SIGNER },
3376
+ { address: to, role: AccountRole.WRITABLE }
3377
+ ],
3378
+ data: new Uint8Array([
3379
+ ...encodeU32LE(2),
3380
+ ...encodeU64LE(lamports)
3381
+ ])
3382
+ };
3383
+ }
3384
+ function encodeU32LE(value) {
3385
+ if (!Number.isSafeInteger(value) || value < 0 || value > 4294967295) {
3386
+ throw errInvalidArgs("Instruction discriminator must fit in an unsigned 32-bit integer.");
3387
+ }
3388
+ const bytes = new Uint8Array(4);
3389
+ bytes[0] = value & 255;
3390
+ bytes[1] = value >> 8 & 255;
3391
+ bytes[2] = value >> 16 & 255;
3392
+ bytes[3] = value >> 24 & 255;
3393
+ return bytes;
3097
3394
  }
3098
3395
  function encodeU64LE(value) {
3099
3396
  if (value < 0n || value > 0xffffffffffffffffn) {
@@ -3174,6 +3471,38 @@ async function buildAndSendSolanaTransaction(opts) {
3174
3471
  const signature = await client.call("sendTransaction", [wireTransaction, { encoding: "base64" }]);
3175
3472
  return { signature, fromAddress: signer.address };
3176
3473
  }
3474
+ async function buildAndSendSolanaTransactionWithSession(opts) {
3475
+ const { client, instructions, session, authToken, sponsored, gasPolicyId } = opts;
3476
+ const fromAddress = getSolanaSessionAddress(session);
3477
+ const blockhashResult = await client.call("getLatestBlockhash", [{ commitment: "finalized" }]);
3478
+ const { blockhash, lastValidBlockHeight } = blockhashResult.value;
3479
+ const feePayer = sponsored ? SPONSOR_FEE_PAYER_PLACEHOLDER : address(fromAddress);
3480
+ const txMessage = pipe(
3481
+ createTransactionMessage({ version: 0 }),
3482
+ (msg) => setTransactionMessageFeePayer(feePayer, msg),
3483
+ (msg) => setTransactionMessageLifetimeUsingBlockhash(
3484
+ { blockhash, lastValidBlockHeight },
3485
+ msg
3486
+ ),
3487
+ (msg) => appendTransactionMessageInstructions(instructions, msg)
3488
+ );
3489
+ const compiledTx = compileTransaction(txMessage);
3490
+ const transactionToSign = sponsored ? await sponsorSolanaTransaction({
3491
+ client,
3492
+ compiledTransactionBase64: getBase64EncodedWireTransaction(compiledTx),
3493
+ gasPolicyId
3494
+ }) : getBase64EncodedWireTransaction(compiledTx);
3495
+ const signedTransaction = await signSolanaTransactionWithSession({
3496
+ authToken,
3497
+ session,
3498
+ transactionBase64: transactionToSign
3499
+ });
3500
+ const signature = await client.call("sendTransaction", [
3501
+ signedTransaction,
3502
+ { encoding: "base64" }
3503
+ ]);
3504
+ return { signature, fromAddress };
3505
+ }
3177
3506
  async function waitForSolanaConfirmation(client, signature, timeoutMs = 6e4, pollIntervalMs = 2e3) {
3178
3507
  const start = Date.now();
3179
3508
  while (Date.now() - start < timeoutMs) {
@@ -3190,6 +3519,76 @@ async function waitForSolanaConfirmation(client, signature, timeoutMs = 6e4, pol
3190
3519
  }
3191
3520
  return false;
3192
3521
  }
3522
+ async function sponsorSolanaTransaction(args) {
3523
+ if (!args.gasPolicyId) {
3524
+ throw errInvalidArgs("Fee sponsorship requires a fee policy ID.");
3525
+ }
3526
+ const feePayerResponse = await args.client.call("alchemy_requestFeePayer", [{
3527
+ policyId: args.gasPolicyId,
3528
+ serializedTransaction: args.compiledTransactionBase64
3529
+ }]);
3530
+ return feePayerResponse.serializedTransaction;
3531
+ }
3532
+ async function signSolanaTransactionWithSession(args) {
3533
+ const binding = getSolanaSessionBinding(args.session);
3534
+ if (args.session.capabilities?.["solana.signTransaction"] === false) {
3535
+ throw errInvalidArgs(
3536
+ "Delegated wallet session does not allow 'solana.signTransaction'. Reconnect the wallet session to refresh capabilities."
3537
+ );
3538
+ }
3539
+ const challenge = await createRemoteSolanaSignTransactionChallenge(args.authToken, {
3540
+ ...binding,
3541
+ transaction: args.transactionBase64,
3542
+ encoding: "base64"
3543
+ });
3544
+ const completion = await completeRemoteSolanaSignTransactionChallenge(args.authToken, {
3545
+ challengeId: challenge.challengeId,
3546
+ signature: signChallengePayload({
3547
+ challengePayload: challenge.challenge,
3548
+ privateKeyPem: args.session.privateKeyPem
3549
+ })
3550
+ });
3551
+ return completion.signedTransaction;
3552
+ }
3553
+ function getSolanaSessionBinding(session) {
3554
+ const walletId = session.solanaWalletId ?? session.walletId;
3555
+ const walletAddress = getSolanaSessionAddress(session);
3556
+ if (!walletId) {
3557
+ throw errInvalidArgs(
3558
+ "Delegated wallet session is missing Solana wallet ID metadata. Run 'alchemy wallet connect --mode session --force'."
3559
+ );
3560
+ }
3561
+ if (!session.privyKeyQuorumId && !session.privySignerId) {
3562
+ throw errInvalidArgs(
3563
+ "Delegated wallet session is missing signer binding metadata. Run 'alchemy wallet connect --mode session --force'."
3564
+ );
3565
+ }
3566
+ return {
3567
+ sessionId: session.sessionId,
3568
+ walletId,
3569
+ walletAddress,
3570
+ privyKeyQuorumId: session.privyKeyQuorumId,
3571
+ privySignerId: session.privySignerId
3572
+ };
3573
+ }
3574
+ function getSolanaSessionAddress(session) {
3575
+ if (!session.solanaAddress) {
3576
+ throw errInvalidArgs(
3577
+ "Delegated wallet session is missing Solana address metadata. Run 'alchemy wallet connect --mode session --force'."
3578
+ );
3579
+ }
3580
+ return session.solanaAddress;
3581
+ }
3582
+ function signChallengePayload(args) {
3583
+ return signWithPrivateKey(
3584
+ "sha256",
3585
+ Buffer.from(args.challengePayload, "utf8"),
3586
+ {
3587
+ key: args.privateKeyPem,
3588
+ dsaEncoding: "der"
3589
+ }
3590
+ ).toString("base64url");
3591
+ }
3193
3592
 
3194
3593
  // src/lib/solana-fees.ts
3195
3594
  function resolveSolanaFeeSponsorship(program2) {
@@ -3211,23 +3610,54 @@ function parseDecimals(value) {
3211
3610
  }
3212
3611
  return decimals;
3213
3612
  }
3214
- async function resolveLocalSolanaDelegateSigner(program2, signerOpt) {
3613
+ async function resolveSolanaDelegateSigner(program2, signerOpt) {
3215
3614
  const signer = parseSignerOpt(signerOpt);
3216
3615
  if (signer === "session") {
3217
- throw errInvalidArgs(
3218
- "The session wallet does not yet support Solana. Use `--signer local` or configure a local Solana wallet with `alchemy wallet connect --mode local --chain solana`."
3219
- );
3616
+ return resolveSessionSolanaDelegateSigner();
3617
+ }
3618
+ if (signer === void 0 && resolveActiveSigner(program2) === "session") {
3619
+ return resolveSessionSolanaDelegateSigner();
3220
3620
  }
3221
3621
  const solanaKey = resolveSolanaWalletKey(program2);
3222
3622
  if (!solanaKey) {
3623
+ if (signer === void 0) {
3624
+ const sessionSigner = tryResolveSessionSolanaDelegateSigner();
3625
+ if (sessionSigner) {
3626
+ return sessionSigner;
3627
+ }
3628
+ }
3223
3629
  throw errSolanaWalletKeyRequired();
3224
3630
  }
3225
3631
  const keyBytes = parseSolanaKeyBytes(solanaKey);
3226
3632
  return {
3633
+ type: "local",
3227
3634
  keyBytes,
3228
3635
  signer: await createSolanaSignerFromKeyBytes(keyBytes)
3229
3636
  };
3230
3637
  }
3638
+ function resolveSessionSolanaDelegateSigner() {
3639
+ const sessionSigner = tryResolveSessionSolanaDelegateSigner();
3640
+ if (!sessionSigner) {
3641
+ throw errInvalidArgs(
3642
+ "No active Solana wallet session. Run `alchemy wallet connect --mode session` first."
3643
+ );
3644
+ }
3645
+ return sessionSigner;
3646
+ }
3647
+ function tryResolveSessionSolanaDelegateSigner() {
3648
+ const authToken = resolveAuthToken();
3649
+ const session = resolveWalletSession();
3650
+ const solanaSession = session ? getWalletSessionByChain(session, "solana") : null;
3651
+ if (!authToken || !solanaSession?.solanaAddress) {
3652
+ return void 0;
3653
+ }
3654
+ return {
3655
+ type: "session",
3656
+ address: solanaSession.solanaAddress,
3657
+ session: solanaSession,
3658
+ authToken
3659
+ };
3660
+ }
3231
3661
  function registerSolanaDelegate(program2) {
3232
3662
  const cmd = program2.command("delegate").description("Delegate Solana token authority");
3233
3663
  const approveCmd = cmd.command("approve").description("Approve a delegate for an SPL token account").requiredOption("--token-account <address>", "SPL token account to delegate from").requiredOption("--mint <address>", "SPL token mint").requiredOption("--delegate <address>", "Delegate address").requiredOption("--amount <number>", "Amount to delegate in decimal token units").requiredOption("--decimals <n>", "Mint decimals").option("--fee-sponsored", "Enable Solana fee sponsorship").option("--fee-policy-id <id>", "Solana fee policy ID for sponsorship");
@@ -3261,7 +3691,7 @@ async function performSolanaDelegateApprove(program2, opts) {
3261
3691
  validateSolanaAddress(opts.delegate);
3262
3692
  const decimals = parseDecimals(opts.decimals);
3263
3693
  const rawAmount = parseAmount(opts.amount, decimals);
3264
- const { keyBytes, signer } = await resolveLocalSolanaDelegateSigner(program2, opts.signer);
3694
+ const signer = await resolveSolanaDelegateSigner(program2, opts.signer);
3265
3695
  const network = resolveSolanaNetwork(program2);
3266
3696
  const { sponsored, feePolicyId } = resolveSolanaFeeSponsorship(program2);
3267
3697
  const client = clientFromFlags(program2, { forceNetwork: network });
@@ -3269,20 +3699,32 @@ async function performSolanaDelegateApprove(program2, opts) {
3269
3699
  tokenAccount: solAddress(opts.tokenAccount),
3270
3700
  mint: solAddress(opts.mint),
3271
3701
  delegate: solAddress(opts.delegate),
3272
- owner: signer,
3702
+ owner: { address: solAddress(signer.type === "session" ? signer.address : signer.signer.address) },
3273
3703
  amount: rawAmount,
3274
3704
  decimals
3275
3705
  });
3276
3706
  const result = await withSpinner(
3277
3707
  "Approving delegate...",
3278
3708
  "Delegate approved",
3279
- () => buildAndSendSolanaTransaction({
3280
- client,
3281
- instructions: [instruction],
3282
- senderKeyBytes: keyBytes,
3283
- sponsored,
3284
- gasPolicyId: feePolicyId
3285
- })
3709
+ async () => {
3710
+ if (signer.type === "session") {
3711
+ return await buildAndSendSolanaTransactionWithSession({
3712
+ client,
3713
+ instructions: [instruction],
3714
+ session: signer.session,
3715
+ authToken: signer.authToken,
3716
+ sponsored,
3717
+ gasPolicyId: feePolicyId
3718
+ });
3719
+ }
3720
+ return await buildAndSendSolanaTransaction({
3721
+ client,
3722
+ instructions: [instruction],
3723
+ senderKeyBytes: signer.keyBytes,
3724
+ sponsored,
3725
+ gasPolicyId: feePolicyId
3726
+ });
3727
+ }
3286
3728
  );
3287
3729
  const confirmed = await withSpinner(
3288
3730
  "Waiting for confirmation...",
@@ -3323,24 +3765,36 @@ async function performSolanaDelegateApprove(program2, opts) {
3323
3765
  }
3324
3766
  async function performSolanaDelegateRevoke(program2, opts) {
3325
3767
  validateSolanaAddress(opts.tokenAccount);
3326
- const { keyBytes, signer } = await resolveLocalSolanaDelegateSigner(program2, opts.signer);
3768
+ const signer = await resolveSolanaDelegateSigner(program2, opts.signer);
3327
3769
  const network = resolveSolanaNetwork(program2);
3328
3770
  const { sponsored, feePolicyId } = resolveSolanaFeeSponsorship(program2);
3329
3771
  const client = clientFromFlags(program2, { forceNetwork: network });
3330
3772
  const instruction = buildSplTokenRevokeInstruction({
3331
3773
  tokenAccount: solAddress(opts.tokenAccount),
3332
- owner: signer
3774
+ owner: { address: solAddress(signer.type === "session" ? signer.address : signer.signer.address) }
3333
3775
  });
3334
3776
  const result = await withSpinner(
3335
3777
  "Revoking delegate...",
3336
3778
  "Delegate revoked",
3337
- () => buildAndSendSolanaTransaction({
3338
- client,
3339
- instructions: [instruction],
3340
- senderKeyBytes: keyBytes,
3341
- sponsored,
3342
- gasPolicyId: feePolicyId
3343
- })
3779
+ async () => {
3780
+ if (signer.type === "session") {
3781
+ return await buildAndSendSolanaTransactionWithSession({
3782
+ client,
3783
+ instructions: [instruction],
3784
+ session: signer.session,
3785
+ authToken: signer.authToken,
3786
+ sponsored,
3787
+ gasPolicyId: feePolicyId
3788
+ });
3789
+ }
3790
+ return await buildAndSendSolanaTransaction({
3791
+ client,
3792
+ instructions: [instruction],
3793
+ senderKeyBytes: signer.keyBytes,
3794
+ sponsored,
3795
+ gasPolicyId: feePolicyId
3796
+ });
3797
+ }
3344
3798
  );
3345
3799
  const confirmed = await withSpinner(
3346
3800
  "Waiting for confirmation...",
@@ -3584,35 +4038,41 @@ async function performSolanaSend(program2, toArg, amountArg, tokenAddress, opts
3584
4038
  if (tokenAddress) {
3585
4039
  throw errInvalidArgs("SPL token transfers are not yet supported. Omit --token for native SOL transfers.");
3586
4040
  }
3587
- if (opts.signer === "session") {
3588
- throw errInvalidArgs(
3589
- "The session wallet does not yet support Solana. Use `--signer local` or configure a local Solana wallet with `alchemy wallet connect --mode local --chain solana`."
3590
- );
3591
- }
3592
- const solanaKey = resolveSolanaWalletKey(program2);
3593
- if (!solanaKey) {
3594
- throw errSolanaWalletKeyRequired();
3595
- }
3596
- const keyBytes = parseSolanaKeyBytes(solanaKey);
4041
+ const signer = await resolveSolanaSigner(program2, opts.signer);
3597
4042
  validateSolanaAddress(toArg);
3598
4043
  const to = solAddress2(toArg);
3599
4044
  const network = resolveSolanaNetwork(program2);
3600
4045
  const symbol = nativeTokenSymbol(network);
3601
4046
  const lamports = parseAmount(amountArg, SOL_DECIMALS);
3602
- const signer = await createSolanaSignerFromKeyBytes(keyBytes);
3603
- const instruction = buildSolTransferInstruction(signer, to, lamports);
4047
+ const instruction = buildSolTransferInstruction(
4048
+ { address: solAddress2(signer.address) },
4049
+ to,
4050
+ lamports
4051
+ );
3604
4052
  const { sponsored, feePolicyId } = resolveSolanaFeeSponsorship(program2);
3605
4053
  const client = clientFromFlags(program2, { forceNetwork: network });
3606
4054
  const result = await withSpinner(
3607
4055
  "Sending transaction\u2026",
3608
4056
  "Transaction submitted",
3609
- () => buildAndSendSolanaTransaction({
3610
- client,
3611
- instructions: [instruction],
3612
- senderKeyBytes: keyBytes,
3613
- sponsored,
3614
- gasPolicyId: feePolicyId
3615
- })
4057
+ async () => {
4058
+ if (signer.type === "session") {
4059
+ return await buildAndSendSolanaTransactionWithSession({
4060
+ client,
4061
+ instructions: [instruction],
4062
+ session: signer.session,
4063
+ authToken: signer.authToken,
4064
+ sponsored,
4065
+ gasPolicyId: feePolicyId
4066
+ });
4067
+ }
4068
+ return await buildAndSendSolanaTransaction({
4069
+ client,
4070
+ instructions: [instruction],
4071
+ senderKeyBytes: signer.keyBytes,
4072
+ sponsored,
4073
+ gasPolicyId: feePolicyId
4074
+ });
4075
+ }
3616
4076
  );
3617
4077
  const confirmed = await withSpinner(
3618
4078
  "Waiting for confirmation\u2026",
@@ -3645,6 +4105,70 @@ async function performSolanaSend(program2, toArg, amountArg, tokenAddress, opts
3645
4105
  printKeyValue(pairs);
3646
4106
  }
3647
4107
  }
4108
+ async function resolveSolanaSigner(program2, signer) {
4109
+ if (signer === "session") {
4110
+ const authToken = resolveAuthToken();
4111
+ const session = resolveWalletSession();
4112
+ const solanaSession = session ? getWalletSessionByChain(session, "solana") : null;
4113
+ if (!authToken) {
4114
+ throw errInvalidArgs("Session Solana signing requires CLI authentication.");
4115
+ }
4116
+ if (!solanaSession?.solanaAddress) {
4117
+ throw errInvalidArgs(
4118
+ "No active Solana wallet session. Run `alchemy wallet connect --mode session` first."
4119
+ );
4120
+ }
4121
+ return {
4122
+ type: "session",
4123
+ address: solanaSession.solanaAddress,
4124
+ session: solanaSession,
4125
+ authToken
4126
+ };
4127
+ }
4128
+ if (signer === void 0 && resolveActiveSigner(program2) === "session") {
4129
+ const authToken = resolveAuthToken();
4130
+ const session = resolveWalletSession();
4131
+ const solanaSession = session ? getWalletSessionByChain(session, "solana") : null;
4132
+ if (!authToken) {
4133
+ throw errInvalidArgs("Session Solana signing requires CLI authentication.");
4134
+ }
4135
+ if (!solanaSession?.solanaAddress) {
4136
+ throw errInvalidArgs(
4137
+ "No active Solana wallet session. Run `alchemy wallet connect --mode session` first."
4138
+ );
4139
+ }
4140
+ return {
4141
+ type: "session",
4142
+ address: solanaSession.solanaAddress,
4143
+ session: solanaSession,
4144
+ authToken
4145
+ };
4146
+ }
4147
+ const solanaKey = resolveSolanaWalletKey(program2);
4148
+ if (!solanaKey) {
4149
+ if (signer === void 0) {
4150
+ const authToken = resolveAuthToken();
4151
+ const session = resolveWalletSession();
4152
+ const solanaSession = session ? getWalletSessionByChain(session, "solana") : null;
4153
+ if (authToken && solanaSession?.solanaAddress) {
4154
+ return {
4155
+ type: "session",
4156
+ address: solanaSession.solanaAddress,
4157
+ session: solanaSession,
4158
+ authToken
4159
+ };
4160
+ }
4161
+ }
4162
+ throw errSolanaWalletKeyRequired();
4163
+ }
4164
+ const keyBytes = parseSolanaKeyBytes(solanaKey);
4165
+ const localSigner = await createSolanaSignerFromKeyBytes(keyBytes);
4166
+ return {
4167
+ type: "local",
4168
+ address: localSigner.address,
4169
+ keyBytes
4170
+ };
4171
+ }
3648
4172
 
3649
4173
  // src/lib/smart-wallet.ts
3650
4174
  import { createSmartWalletClient } from "@alchemy/wallet-apis";
@@ -3704,7 +4228,7 @@ function networkToChain(network) {
3704
4228
  }
3705
4229
 
3706
4230
  // src/lib/delegated-signer.ts
3707
- import { sign as signWithPrivateKey } from "crypto";
4231
+ import { sign as signWithPrivateKey2 } from "crypto";
3708
4232
  import { isAddressEqual, recoverMessageAddress, recoverTypedDataAddress } from "viem";
3709
4233
  import { toAccount } from "viem/accounts";
3710
4234
  var messageCapabilities = {
@@ -3718,8 +4242,8 @@ function toHex(bytes) {
3718
4242
  function normalizeSignedChallengeSignature(signature) {
3719
4243
  return signature.toString("base64url");
3720
4244
  }
3721
- function signChallengePayload(args) {
3722
- const signature = signWithPrivateKey(
4245
+ function signChallengePayload2(args) {
4246
+ const signature = signWithPrivateKey2(
3723
4247
  "sha256",
3724
4248
  Buffer.from(args.challengePayload, "utf8"),
3725
4249
  {
@@ -3902,7 +4426,7 @@ function createDelegatedAccount(args) {
3902
4426
  message: remoteMessage.message,
3903
4427
  encoding: remoteMessage.encoding
3904
4428
  });
3905
- const signature = signChallengePayload({
4429
+ const signature = signChallengePayload2({
3906
4430
  challengePayload: challenge.challenge,
3907
4431
  privateKeyPem: args.session.privateKeyPem
3908
4432
  });
@@ -3937,7 +4461,7 @@ function createDelegatedAccount(args) {
3937
4461
  ...sessionBinding,
3938
4462
  typedData: serializedTypedData
3939
4463
  });
3940
- const signature = signChallengePayload({
4464
+ const signature = signChallengePayload2({
3941
4465
  challengePayload: challenge.challenge,
3942
4466
  privateKeyPem: args.session.privateKeyPem
3943
4467
  });
@@ -3966,7 +4490,7 @@ function createDelegatedAccount(args) {
3966
4490
  ...sessionBinding,
3967
4491
  authorization
3968
4492
  });
3969
- const signature = signChallengePayload({
4493
+ const signature = signChallengePayload2({
3970
4494
  challengePayload: challenge.challenge,
3971
4495
  privateKeyPem: args.session.privateKeyPem
3972
4496
  });
@@ -4065,12 +4589,13 @@ function buildWalletClient(program2, options = {}) {
4065
4589
  }
4066
4590
  throw errNoActiveSession();
4067
4591
  }
4068
- assertSessionMetadata(validSession);
4069
- if (validSession.chainType && validSession.chainType !== "evm") {
4592
+ const evmSession = getWalletSessionByChain(validSession, "evm");
4593
+ if (!evmSession) {
4070
4594
  throw errInvalidArgs(
4071
- `Wallet session is configured for '${validSession.chainType}', not EVM. Run 'alchemy wallet connect --force'.`
4595
+ "Wallet session is missing EVM metadata. Run 'alchemy wallet connect --mode session --force'."
4072
4596
  );
4073
4597
  }
4598
+ assertSessionMetadata(evmSession);
4074
4599
  const authToken = resolveAuthToken(cfg);
4075
4600
  if (!authToken) {
4076
4601
  throw errAuthRequired();
@@ -4078,9 +4603,9 @@ function buildWalletClient(program2, options = {}) {
4078
4603
  return {
4079
4604
  signer: createDelegatedAccount({
4080
4605
  authToken,
4081
- session: validSession
4606
+ session: evmSession
4082
4607
  }),
4083
- address: validSession.evmAddress
4608
+ address: evmSession.evmAddress
4084
4609
  };
4085
4610
  }
4086
4611
  if (!localKey) throw errWalletKeyRequired();
@@ -4819,7 +5344,7 @@ function buildAgentPrompt(program2) {
4819
5344
  method: "Local wallet + API key",
4820
5345
  envVar: "ALCHEMY_WALLET_KEY",
4821
5346
  flag: "--wallet-key-file <path> | --signer local",
4822
- setup: "alchemy wallet connect --mode local --chain evm",
5347
+ setup: "alchemy wallet connect --mode local",
4823
5348
  commandFamilies: [
4824
5349
  "evm send",
4825
5350
  "evm contract call",
@@ -6722,7 +7247,7 @@ Examples:
6722
7247
  dryRun: opts.dryRun
6723
7248
  });
6724
7249
  } catch (err) {
6725
- const { exitWithError: exitWithError2 } = await import("./errors-E2P6WHTX.js");
7250
+ const { exitWithError: exitWithError2 } = await import("./errors-UL3W4ECQ.js");
6726
7251
  exitWithError2(err);
6727
7252
  }
6728
7253
  });
@@ -8298,7 +8823,7 @@ async function flushProcessOutput() {
8298
8823
  }
8299
8824
  program.name("alchemy").description(
8300
8825
  "The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
8301
- ).version("0.7.3", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
8826
+ ).version("0.7.4-alpha.37", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
8302
8827
  "-n, --network <network>",
8303
8828
  "Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
8304
8829
  ).option("--x402", "Use x402 wallet-based gateway auth").option(
@@ -8485,11 +9010,11 @@ ${styledLine}`;
8485
9010
  "wallet"
8486
9011
  ];
8487
9012
  if (!skipAppPrompt.includes(cmdName) && isInteractiveAllowed(program) && !opts.apiKey && !process.env.ALCHEMY_API_KEY) {
8488
- const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXT5ZCUK.js");
9013
+ const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-PAQKIAX3.js");
8489
9014
  const authToken = resolveAuthToken2(cfg);
8490
9015
  const hasApiKey = Boolean(cfg.api_key?.trim() || cfg.app?.apiKey);
8491
9016
  if (authToken && !hasApiKey) {
8492
- const { selectAppAfterAuth } = await import("./auth-F2IXC6CM.js");
9017
+ const { selectAppAfterAuth } = await import("./auth-R5QHPFMA.js");
8493
9018
  console.log("");
8494
9019
  console.log(` No app selected. Please select an app to continue.`);
8495
9020
  await selectAppAfterAuth(authToken);
@@ -8524,7 +9049,7 @@ ${styledLine}`;
8524
9049
  if (isInteractiveAllowed(program)) {
8525
9050
  let latestForInteractiveStartup = null;
8526
9051
  if (shouldRunOnboarding(program, cfg)) {
8527
- const { runOnboarding } = await import("./onboarding-TTUVIXM4.js");
9052
+ const { runOnboarding } = await import("./onboarding-Q5PBXH3M.js");
8528
9053
  const latest = getAvailableUpdateOnce();
8529
9054
  const completed = await runOnboarding(program, latest);
8530
9055
  updateShownDuringInteractiveStartup = Boolean(latest);
@@ -8538,7 +9063,7 @@ ${styledLine}`;
8538
9063
  latestForInteractiveStartup
8539
9064
  );
8540
9065
  }
8541
- const { startREPL } = await import("./interactive-BNIJYEOV.js");
9066
+ const { startREPL } = await import("./interactive-Z2YHE6ME.js");
8542
9067
  program.exitOverride();
8543
9068
  program.configureOutput({
8544
9069
  writeErr: () => {