@alchemy/cli 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth-6BBITIOZ.js +16 -0
- package/dist/{auth-JPRZE2MA.js → auth-IAM4AMBK.js} +2 -2
- package/dist/{chunk-L7VFXQSF.js → chunk-75ICFV5K.js} +1 -1
- package/dist/{chunk-76ZO4UJ4.js → chunk-AJOLFTCZ.js} +3 -3
- package/dist/{chunk-ROBA7SR7.js → chunk-GDLPBPG3.js} +1 -1
- package/dist/{chunk-EKS2THJU.js → chunk-L2WODD2D.js} +6 -6
- package/dist/{chunk-DGZYRBXR.js → chunk-MV7O3XBG.js} +1 -1
- package/dist/{chunk-46LMXT54.js → chunk-OVLQH6KL.js} +4 -4
- package/dist/{chunk-GNOTKJF4.js → chunk-P56HOTPV.js} +5 -5
- package/dist/{chunk-NGF46GZP.js → chunk-RGVM5SNE.js} +1 -1
- package/dist/{chunk-JWLZAO7S.js → chunk-SIIZGMK5.js} +133 -9
- package/dist/{chunk-5Y7UQ27V.js → chunk-TTWOBNJP.js} +4 -4
- package/dist/{errors-A53DVJDY.js → errors-T6XE2I2L.js} +1 -1
- package/dist/index.js +756 -215
- package/dist/{interactive-6R3VKAPQ.js → interactive-IFPSMRMX.js} +7 -7
- package/dist/{onboarding-YHYXW4F3.js → onboarding-ZLBWCNTB.js} +6 -6
- package/dist/{policy-prompt-7AUZOA7S.js → policy-prompt-4BV5AWVV.js} +5 -5
- package/dist/{resolve-N3SX252M.js → resolve-FQ66OWT7.js} +3 -3
- package/package.json +1 -1
- package/dist/auth-RINQSQDT.js +0 -16
package/dist/index.js
CHANGED
|
@@ -5,23 +5,23 @@ import {
|
|
|
5
5
|
errNotLoggedInForPolicyLookup,
|
|
6
6
|
errSponsorshipNeedsPolicy,
|
|
7
7
|
selectOrCreatePolicy
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-TTWOBNJP.js";
|
|
9
9
|
import {
|
|
10
10
|
registerAuth
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-L2WODD2D.js";
|
|
12
12
|
import {
|
|
13
13
|
openBrowser
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-RGVM5SNE.js";
|
|
15
15
|
import {
|
|
16
16
|
SETUP_CAPABILITY_LABELS,
|
|
17
17
|
SETUP_CAPABILITY_ORDER,
|
|
18
18
|
getSetupStatus,
|
|
19
19
|
isSetupComplete,
|
|
20
20
|
shouldRunOnboarding
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-P56HOTPV.js";
|
|
22
22
|
import {
|
|
23
23
|
isInteractiveAllowed
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-75ICFV5K.js";
|
|
25
25
|
import {
|
|
26
26
|
adminClientFromFlags,
|
|
27
27
|
clearSession,
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
fromAdminNetworkId,
|
|
31
31
|
gasManagerClientFromFlags,
|
|
32
32
|
getRPCNetworks,
|
|
33
|
+
getWalletSessionByChain,
|
|
33
34
|
hasAuthLoginToken,
|
|
34
35
|
isSessionValid,
|
|
35
36
|
isSolanaNetwork,
|
|
@@ -53,12 +54,12 @@ import {
|
|
|
53
54
|
saveSession,
|
|
54
55
|
toAdminNetworkId,
|
|
55
56
|
updateSession
|
|
56
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-SIIZGMK5.js";
|
|
57
58
|
import {
|
|
58
59
|
getAvailableUpdate,
|
|
59
60
|
getUpdateStatus,
|
|
60
61
|
printUpdateNotice
|
|
61
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-AJOLFTCZ.js";
|
|
62
63
|
import {
|
|
63
64
|
bold,
|
|
64
65
|
brand,
|
|
@@ -82,7 +83,7 @@ import {
|
|
|
82
83
|
weiToEth,
|
|
83
84
|
withSpinner,
|
|
84
85
|
yellow
|
|
85
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-MV7O3XBG.js";
|
|
86
87
|
import {
|
|
87
88
|
KEY_MAP,
|
|
88
89
|
configDir,
|
|
@@ -93,7 +94,7 @@ import {
|
|
|
93
94
|
save,
|
|
94
95
|
toMap,
|
|
95
96
|
validKeys
|
|
96
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-GDLPBPG3.js";
|
|
97
98
|
import {
|
|
98
99
|
CLIError,
|
|
99
100
|
EXIT_CODES,
|
|
@@ -129,7 +130,7 @@ import {
|
|
|
129
130
|
setFlags,
|
|
130
131
|
setNoColor,
|
|
131
132
|
verbose
|
|
132
|
-
} from "./chunk-
|
|
133
|
+
} from "./chunk-OVLQH6KL.js";
|
|
133
134
|
|
|
134
135
|
// src/index.ts
|
|
135
136
|
import { Command, Help } from "commander";
|
|
@@ -576,8 +577,8 @@ function registerConfig(program2) {
|
|
|
576
577
|
"Interactive policy selection requires an interactive terminal. Pass an ID: `alchemy config set evm-gas-policy-id <id>`."
|
|
577
578
|
);
|
|
578
579
|
}
|
|
579
|
-
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-
|
|
580
|
-
const { resolveNetwork: resolveNetwork2 } = await import("./resolve-
|
|
580
|
+
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-4BV5AWVV.js");
|
|
581
|
+
const { resolveNetwork: resolveNetwork2 } = await import("./resolve-FQ66OWT7.js");
|
|
581
582
|
const network = resolveNetwork2(program2);
|
|
582
583
|
await selectOrCreatePolicy2({
|
|
583
584
|
flavor: "sponsorship",
|
|
@@ -631,8 +632,8 @@ function registerConfig(program2) {
|
|
|
631
632
|
"Interactive policy selection requires an interactive terminal. Pass an ID: `alchemy config set solana-fee-policy-id <id>`."
|
|
632
633
|
);
|
|
633
634
|
}
|
|
634
|
-
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-
|
|
635
|
-
const { resolveSolanaNetwork: resolveSolanaNetwork2 } = await import("./resolve-
|
|
635
|
+
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-4BV5AWVV.js");
|
|
636
|
+
const { resolveSolanaNetwork: resolveSolanaNetwork2 } = await import("./resolve-FQ66OWT7.js");
|
|
636
637
|
const network = resolveSolanaNetwork2(program2);
|
|
637
638
|
await selectOrCreatePolicy2({
|
|
638
639
|
flavor: "solana",
|
|
@@ -690,7 +691,7 @@ function registerConfig(program2) {
|
|
|
690
691
|
printJSON(toMap(cfg));
|
|
691
692
|
return;
|
|
692
693
|
}
|
|
693
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
694
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-FQ66OWT7.js");
|
|
694
695
|
const validToken = resolveAuthToken2(cfg);
|
|
695
696
|
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");
|
|
696
697
|
const pairs = [
|
|
@@ -1369,7 +1370,19 @@ var walletSessionCreateResponseSchema = z.object({
|
|
|
1369
1370
|
approvalUrl: z.string().url(),
|
|
1370
1371
|
expiresAt: z.string().datetime().optional()
|
|
1371
1372
|
}).passthrough();
|
|
1373
|
+
var walletSessionRequestSessionCreateResponseSchema = z.object({
|
|
1374
|
+
walletSessionId: z.string().min(1),
|
|
1375
|
+
chainType: z.string().min(1),
|
|
1376
|
+
status: rawWalletSessionStateSchema.transform(normalizeWalletSessionState)
|
|
1377
|
+
}).passthrough();
|
|
1378
|
+
var walletSessionRequestCreateResponseSchema = z.object({
|
|
1379
|
+
sessionId: z.string().min(1),
|
|
1380
|
+
approvalUrl: z.string().url(),
|
|
1381
|
+
expiresAt: z.string().datetime().optional(),
|
|
1382
|
+
sessions: z.array(walletSessionRequestSessionCreateResponseSchema).min(1)
|
|
1383
|
+
}).passthrough();
|
|
1372
1384
|
var rawWalletSessionStatusResponseSchema = z.object({
|
|
1385
|
+
type: z.literal("session").optional(),
|
|
1373
1386
|
sessionId: z.string().min(1).optional(),
|
|
1374
1387
|
status: rawWalletSessionStateSchema,
|
|
1375
1388
|
expiresAt: z.string().datetime().optional(),
|
|
@@ -1385,6 +1398,15 @@ var rawWalletSessionStatusResponseSchema = z.object({
|
|
|
1385
1398
|
chainType: z.string().min(1).optional(),
|
|
1386
1399
|
capabilities: z.record(z.string(), z.boolean()).optional()
|
|
1387
1400
|
}).passthrough();
|
|
1401
|
+
var walletSessionRequestStatusResponseSchema = z.object({
|
|
1402
|
+
type: z.literal("sessionRequest"),
|
|
1403
|
+
sessionId: z.string().min(1),
|
|
1404
|
+
sessions: z.array(
|
|
1405
|
+
rawWalletSessionStatusResponseSchema.extend({
|
|
1406
|
+
walletSessionId: z.string().min(1)
|
|
1407
|
+
})
|
|
1408
|
+
).min(1)
|
|
1409
|
+
}).passthrough();
|
|
1388
1410
|
var walletSessionDisconnectResponseSchema = z.object({
|
|
1389
1411
|
sessionId: z.string().min(1).optional(),
|
|
1390
1412
|
status: rawWalletSessionStateSchema.optional().transform(
|
|
@@ -1411,12 +1433,27 @@ var rawEvmSigningChallengeResponseSchema = z.object({
|
|
|
1411
1433
|
challenge: z.string().min(1),
|
|
1412
1434
|
expiresAt: z.string().datetime(),
|
|
1413
1435
|
requestExpiry: z.string().min(1),
|
|
1414
|
-
method: z.enum([
|
|
1436
|
+
method: z.enum([
|
|
1437
|
+
"personal_sign",
|
|
1438
|
+
"eth_signTypedData_v4",
|
|
1439
|
+
"eth_sign7702Authorization"
|
|
1440
|
+
]),
|
|
1415
1441
|
walletId: z.string().min(1),
|
|
1416
1442
|
walletAddress: z.string().regex(/^0x[a-fA-F0-9]{40}$/),
|
|
1417
1443
|
providerKeyQuorumId: z.string().min(1).optional(),
|
|
1418
1444
|
providerSignerId: z.string().min(1).optional()
|
|
1419
1445
|
}).strict();
|
|
1446
|
+
var rawSolanaSigningChallengeResponseSchema = z.object({
|
|
1447
|
+
challengeId: z.string().uuid(),
|
|
1448
|
+
challenge: z.string().min(1),
|
|
1449
|
+
expiresAt: z.string().datetime(),
|
|
1450
|
+
requestExpiry: z.string().min(1),
|
|
1451
|
+
method: z.literal("signTransaction"),
|
|
1452
|
+
walletId: z.string().min(1),
|
|
1453
|
+
walletAddress: z.string().min(1),
|
|
1454
|
+
providerKeyQuorumId: z.string().min(1).optional(),
|
|
1455
|
+
providerSignerId: z.string().min(1).optional()
|
|
1456
|
+
}).strict();
|
|
1420
1457
|
var completeEvmChallengeInputSchema = z.object({
|
|
1421
1458
|
challengeId: z.string().uuid(),
|
|
1422
1459
|
signature: z.string().min(1)
|
|
@@ -1439,6 +1476,10 @@ var signAuthorizationCompleteResponseSchema = z.object({
|
|
|
1439
1476
|
y_parity: z.number().int()
|
|
1440
1477
|
}).strict()
|
|
1441
1478
|
}).strict();
|
|
1479
|
+
var solanaSignTransactionCompleteResponseSchema = z.object({
|
|
1480
|
+
signedTransaction: z.string().min(1),
|
|
1481
|
+
encoding: z.literal("base64")
|
|
1482
|
+
}).strict();
|
|
1442
1483
|
function baseURLOverride() {
|
|
1443
1484
|
const options = { allowedHostnames: [STAGING_ADMIN_API_HOST] };
|
|
1444
1485
|
return parseBaseURLOverride(WALLET_API_BASE_URL_ENV, options) ?? parseBaseURLOverride(ADMIN_API_BASE_URL_ENV, options);
|
|
@@ -1532,6 +1573,17 @@ function normalizeWalletSessionStatus(session) {
|
|
|
1532
1573
|
privySignerId: session.providerSignerId
|
|
1533
1574
|
};
|
|
1534
1575
|
}
|
|
1576
|
+
function normalizeWalletSessionRequestStatus(request2) {
|
|
1577
|
+
return {
|
|
1578
|
+
sessionId: request2.sessionId,
|
|
1579
|
+
sessions: request2.sessions.map(({ walletSessionId, ...session }) => {
|
|
1580
|
+
return normalizeWalletSessionStatus({
|
|
1581
|
+
...session,
|
|
1582
|
+
sessionId: walletSessionId
|
|
1583
|
+
});
|
|
1584
|
+
})
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1535
1587
|
function normalizeEvmSigningChallengeResponse(response) {
|
|
1536
1588
|
return {
|
|
1537
1589
|
...response,
|
|
@@ -1539,6 +1591,13 @@ function normalizeEvmSigningChallengeResponse(response) {
|
|
|
1539
1591
|
privySignerId: response.providerSignerId
|
|
1540
1592
|
};
|
|
1541
1593
|
}
|
|
1594
|
+
function normalizeSolanaSigningChallengeResponse(response) {
|
|
1595
|
+
return {
|
|
1596
|
+
...response,
|
|
1597
|
+
privyKeyQuorumId: response.providerKeyQuorumId,
|
|
1598
|
+
privySignerId: response.providerSignerId
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1542
1601
|
function toProviderSigningBindingInput(input) {
|
|
1543
1602
|
const { privyKeyQuorumId, privySignerId, ...rest } = input;
|
|
1544
1603
|
return {
|
|
@@ -1547,7 +1606,15 @@ function toProviderSigningBindingInput(input) {
|
|
|
1547
1606
|
...privySignerId ? { providerSignerId: privySignerId } : {}
|
|
1548
1607
|
};
|
|
1549
1608
|
}
|
|
1550
|
-
|
|
1609
|
+
function toProviderSolanaSigningBindingInput(input) {
|
|
1610
|
+
const { privyKeyQuorumId, privySignerId, ...rest } = input;
|
|
1611
|
+
return {
|
|
1612
|
+
...rest,
|
|
1613
|
+
...privyKeyQuorumId ? { providerKeyQuorumId: privyKeyQuorumId } : {},
|
|
1614
|
+
...privySignerId ? { providerSignerId: privySignerId } : {}
|
|
1615
|
+
};
|
|
1616
|
+
}
|
|
1617
|
+
async function createRemoteWalletSessionRequest(token, input) {
|
|
1551
1618
|
let data;
|
|
1552
1619
|
let requestInput = input;
|
|
1553
1620
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
@@ -1558,16 +1625,19 @@ async function createRemoteWalletSession(token, input) {
|
|
|
1558
1625
|
"/wallet/sessions",
|
|
1559
1626
|
requestInput
|
|
1560
1627
|
);
|
|
1561
|
-
return unwrapAdminData(
|
|
1628
|
+
return unwrapAdminData(walletSessionRequestCreateResponseSchema, data);
|
|
1562
1629
|
} catch (err) {
|
|
1563
|
-
const retryInput = getClientInstanceCompatibilityRetryInput(
|
|
1630
|
+
const retryInput = getClientInstanceCompatibilityRetryInput(
|
|
1631
|
+
requestInput,
|
|
1632
|
+
err
|
|
1633
|
+
);
|
|
1564
1634
|
if (retryInput === void 0) {
|
|
1565
1635
|
throw err;
|
|
1566
1636
|
}
|
|
1567
1637
|
requestInput = retryInput;
|
|
1568
1638
|
}
|
|
1569
1639
|
}
|
|
1570
|
-
throw new CLIError(ErrorCode.NETWORK_ERROR, "Unable to create wallet session.");
|
|
1640
|
+
throw new CLIError(ErrorCode.NETWORK_ERROR, "Unable to create wallet session request.");
|
|
1571
1641
|
}
|
|
1572
1642
|
function getClientInstanceCompatibilityRetryInput(input, err) {
|
|
1573
1643
|
if (input.environment.clientInstanceName !== void 0 && isUnsupportedClientInstanceMetadataError(err, "clientInstanceName")) {
|
|
@@ -1602,6 +1672,16 @@ async function getRemoteWalletSession(token, sessionId) {
|
|
|
1602
1672
|
unwrapAdminData(rawWalletSessionStatusResponseSchema, data)
|
|
1603
1673
|
);
|
|
1604
1674
|
}
|
|
1675
|
+
async function getRemoteWalletSessionRequest(token, sessionId) {
|
|
1676
|
+
const data = await request(
|
|
1677
|
+
token,
|
|
1678
|
+
"GET",
|
|
1679
|
+
`/wallet/sessions/${encodeURIComponent(sessionId)}`
|
|
1680
|
+
);
|
|
1681
|
+
return normalizeWalletSessionRequestStatus(
|
|
1682
|
+
unwrapAdminData(walletSessionRequestStatusResponseSchema, data)
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1605
1685
|
async function disconnectRemoteWalletSession(token, sessionId) {
|
|
1606
1686
|
try {
|
|
1607
1687
|
const data = await request(
|
|
@@ -1680,6 +1760,24 @@ var signAuthorizationChallengeInputSchema = evmSigningSessionBindingBaseSchema.e
|
|
|
1680
1760
|
executor: z.literal("self").optional()
|
|
1681
1761
|
}).strict()
|
|
1682
1762
|
}).strict().superRefine(ensureSessionSignerBinding);
|
|
1763
|
+
var solanaSigningSessionBindingBaseSchema = z.object({
|
|
1764
|
+
sessionId: z.string().uuid(),
|
|
1765
|
+
walletId: z.string().min(1),
|
|
1766
|
+
walletAddress: z.string().min(1),
|
|
1767
|
+
privyKeyQuorumId: z.string().min(1).optional(),
|
|
1768
|
+
privySignerId: z.string().min(1).optional()
|
|
1769
|
+
});
|
|
1770
|
+
var solanaSignTransactionChallengeInputSchema = solanaSigningSessionBindingBaseSchema.extend({
|
|
1771
|
+
transaction: z.string().min(1),
|
|
1772
|
+
encoding: z.literal("base64")
|
|
1773
|
+
}).strict().superRefine((input, ctx) => {
|
|
1774
|
+
if (!input.privyKeyQuorumId && !input.privySignerId) {
|
|
1775
|
+
ctx.addIssue({
|
|
1776
|
+
code: z.ZodIssueCode.custom,
|
|
1777
|
+
message: "Provide privyKeyQuorumId or privySignerId."
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
});
|
|
1683
1781
|
async function createRemoteSignTypedDataChallenge(token, input) {
|
|
1684
1782
|
const parsedInput = signTypedDataChallengeInputSchema.parse(input);
|
|
1685
1783
|
return createEvmSigningChallenge(
|
|
@@ -1718,6 +1816,25 @@ async function completeRemoteSignAuthorizationChallenge(token, input) {
|
|
|
1718
1816
|
adminApiResponseSchema(signAuthorizationCompleteResponseSchema).transform((resp) => resp.data)
|
|
1719
1817
|
);
|
|
1720
1818
|
}
|
|
1819
|
+
async function createRemoteSolanaSignTransactionChallenge(token, input) {
|
|
1820
|
+
const parsedInput = solanaSignTransactionChallengeInputSchema.parse(input);
|
|
1821
|
+
return createEvmSigningChallenge(
|
|
1822
|
+
token,
|
|
1823
|
+
"/wallet/solana/sign-transaction/challenge",
|
|
1824
|
+
toProviderSolanaSigningBindingInput(parsedInput),
|
|
1825
|
+
adminApiResponseSchema(rawSolanaSigningChallengeResponseSchema).transform(
|
|
1826
|
+
(resp) => normalizeSolanaSigningChallengeResponse(resp.data)
|
|
1827
|
+
)
|
|
1828
|
+
);
|
|
1829
|
+
}
|
|
1830
|
+
async function completeRemoteSolanaSignTransactionChallenge(token, input) {
|
|
1831
|
+
return completeEvmSigningChallenge(
|
|
1832
|
+
token,
|
|
1833
|
+
"/wallet/solana/sign-transaction/complete",
|
|
1834
|
+
input,
|
|
1835
|
+
adminApiResponseSchema(solanaSignTransactionCompleteResponseSchema).transform((resp) => resp.data)
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1721
1838
|
|
|
1722
1839
|
// src/commands/wallet.ts
|
|
1723
1840
|
import QRCode from "qrcode";
|
|
@@ -1728,6 +1845,9 @@ var DEFAULT_WALLET_CAPABILITIES = {
|
|
|
1728
1845
|
"evm.signTypedData": true,
|
|
1729
1846
|
"evm.signAuthorization": true
|
|
1730
1847
|
};
|
|
1848
|
+
var DEFAULT_SOLANA_SESSION_CAPABILITIES = {
|
|
1849
|
+
"solana.signTransaction": true
|
|
1850
|
+
};
|
|
1731
1851
|
function createEvmWallet() {
|
|
1732
1852
|
const privateKey = generatePrivateKey();
|
|
1733
1853
|
const account = privateKeyToAccount(privateKey);
|
|
@@ -1851,7 +1971,13 @@ async function withApprovalInterruptHandler(args) {
|
|
|
1851
1971
|
return await args.run(controller.signal);
|
|
1852
1972
|
} catch (err) {
|
|
1853
1973
|
if (isWalletConnectInterruptedError(err)) {
|
|
1854
|
-
await
|
|
1974
|
+
await Promise.all(
|
|
1975
|
+
args.sessionIds.map(
|
|
1976
|
+
(sessionId) => disconnectRemoteWalletSession(args.authToken, sessionId).catch(
|
|
1977
|
+
() => void 0
|
|
1978
|
+
)
|
|
1979
|
+
)
|
|
1980
|
+
);
|
|
1855
1981
|
clearSession();
|
|
1856
1982
|
}
|
|
1857
1983
|
throw err;
|
|
@@ -1862,23 +1988,9 @@ async function withApprovalInterruptHandler(args) {
|
|
|
1862
1988
|
}
|
|
1863
1989
|
}
|
|
1864
1990
|
}
|
|
1865
|
-
function
|
|
1866
|
-
const date = new Date(value);
|
|
1867
|
-
if (Number.isNaN(date.getTime())) {
|
|
1868
|
-
return false;
|
|
1869
|
-
}
|
|
1870
|
-
return date > /* @__PURE__ */ new Date();
|
|
1871
|
-
}
|
|
1872
|
-
function isActiveWalletSession(session, remoteStatus) {
|
|
1873
|
-
if (!session) return false;
|
|
1874
|
-
if (session.status !== "approved") return false;
|
|
1875
|
-
if (!isFutureIsoDate(session.expiresAt)) return false;
|
|
1876
|
-
if (remoteStatus && remoteStatus !== "approved") return false;
|
|
1877
|
-
return true;
|
|
1878
|
-
}
|
|
1879
|
-
function deriveWalletStatus(session, remoteStatus) {
|
|
1991
|
+
function deriveWalletStatus(session) {
|
|
1880
1992
|
if (!session) return "none";
|
|
1881
|
-
if (
|
|
1993
|
+
if (isSessionValid(session)) return "active";
|
|
1882
1994
|
if (session.status === "pending") return "none";
|
|
1883
1995
|
return "expired";
|
|
1884
1996
|
}
|
|
@@ -1988,7 +2100,7 @@ function resolveQrAddress(args) {
|
|
|
1988
2100
|
function missingQrWalletError(type, source) {
|
|
1989
2101
|
if (source === "session") {
|
|
1990
2102
|
return type === "solana" ? errInvalidArgs(
|
|
1991
|
-
"
|
|
2103
|
+
"No Solana session wallet is configured. Run `alchemy wallet connect --mode session --force`."
|
|
1992
2104
|
) : errNoActiveSession();
|
|
1993
2105
|
}
|
|
1994
2106
|
if (source === "local") {
|
|
@@ -1999,20 +2111,6 @@ function missingQrWalletError(type, source) {
|
|
|
1999
2111
|
function indentBlock(text, prefix = " ") {
|
|
2000
2112
|
return text.split("\n").map((line) => line ? `${prefix}${line}` : line).join("\n");
|
|
2001
2113
|
}
|
|
2002
|
-
function generateAndPersistWallet() {
|
|
2003
|
-
const wallet = createEvmWallet();
|
|
2004
|
-
const keyPath = persistWalletKey("wallet-key", wallet.privateKey, wallet.address);
|
|
2005
|
-
const cfg = load();
|
|
2006
|
-
save({ ...cfg, wallet_key_file: keyPath, wallet_address: wallet.address });
|
|
2007
|
-
return { address: wallet.address, keyFile: keyPath };
|
|
2008
|
-
}
|
|
2009
|
-
async function generateAndPersistSolanaWallet() {
|
|
2010
|
-
const wallet = await createSolanaWallet();
|
|
2011
|
-
const keyPath = persistWalletKey("solana-wallet-key", wallet.secretKey, wallet.address);
|
|
2012
|
-
const cfg = load();
|
|
2013
|
-
save({ ...cfg, solana_wallet_key_file: keyPath, solana_wallet_address: wallet.address });
|
|
2014
|
-
return { address: wallet.address, keyFile: keyPath };
|
|
2015
|
-
}
|
|
2016
2114
|
async function createAndPersistWallets() {
|
|
2017
2115
|
const evm = createEvmWallet();
|
|
2018
2116
|
const solana = await createSolanaWallet();
|
|
@@ -2077,14 +2175,12 @@ function getEffectiveLocalWalletState(program2, cfg) {
|
|
|
2077
2175
|
}
|
|
2078
2176
|
async function runLocalCreate(opts) {
|
|
2079
2177
|
const cfg = load();
|
|
2080
|
-
const
|
|
2081
|
-
const
|
|
2082
|
-
const evmConflict = wantsEvm && Boolean(cfg.wallet_key_file);
|
|
2083
|
-
const solanaConflict = wantsSolana && Boolean(cfg.solana_wallet_key_file);
|
|
2178
|
+
const evmConflict = Boolean(cfg.wallet_key_file);
|
|
2179
|
+
const solanaConflict = Boolean(cfg.solana_wallet_key_file);
|
|
2084
2180
|
if ((evmConflict || solanaConflict) && !opts.force) {
|
|
2085
2181
|
if (!isInteractiveAllowed(opts.program)) {
|
|
2086
2182
|
throw errInvalidArgs(
|
|
2087
|
-
"A local key is already configured
|
|
2183
|
+
"A local key is already configured. Re-run with --force to replace it."
|
|
2088
2184
|
);
|
|
2089
2185
|
}
|
|
2090
2186
|
const kinds = [evmConflict ? "EVM" : null, solanaConflict ? "Solana" : null].filter(Boolean).join(" and ");
|
|
@@ -2097,16 +2193,7 @@ async function runLocalCreate(opts) {
|
|
|
2097
2193
|
throw errInvalidArgs("Aborted. Existing local key preserved.");
|
|
2098
2194
|
}
|
|
2099
2195
|
}
|
|
2100
|
-
|
|
2101
|
-
const { evm, solana: solana2 } = await createAndPersistWallets();
|
|
2102
|
-
return { evm, solana: solana2 };
|
|
2103
|
-
}
|
|
2104
|
-
if (opts.chain === "evm") {
|
|
2105
|
-
const evm = generateAndPersistWallet();
|
|
2106
|
-
return { evm };
|
|
2107
|
-
}
|
|
2108
|
-
const solana = await generateAndPersistSolanaWallet();
|
|
2109
|
-
return { solana };
|
|
2196
|
+
return await createAndPersistWallets();
|
|
2110
2197
|
}
|
|
2111
2198
|
function runLocalImport(opts) {
|
|
2112
2199
|
const cfg = load();
|
|
@@ -2139,7 +2226,27 @@ async function runLocalImportInteractive(opts) {
|
|
|
2139
2226
|
return runLocalImport({ ...opts, force: true });
|
|
2140
2227
|
}
|
|
2141
2228
|
}
|
|
2229
|
+
function capabilitiesForChain(chain) {
|
|
2230
|
+
return chain === "evm" ? { ...DEFAULT_WALLET_CAPABILITIES } : { ...DEFAULT_SOLANA_SESSION_CAPABILITIES };
|
|
2231
|
+
}
|
|
2232
|
+
function capabilitiesForChains(chains) {
|
|
2233
|
+
return Object.fromEntries(
|
|
2234
|
+
chains.map((chain) => [chain, capabilitiesForChain(chain)])
|
|
2235
|
+
);
|
|
2236
|
+
}
|
|
2237
|
+
function getApprovedSessionWalletMetadata(chain, session) {
|
|
2238
|
+
const walletId = chain === "evm" ? session.walletId ?? session.evmWalletId : session.solanaWalletId ?? session.walletId;
|
|
2239
|
+
const walletAddress = chain === "evm" ? session.evmAddress ?? session.address : session.solanaAddress ?? session.address;
|
|
2240
|
+
if (!walletId || !walletAddress) {
|
|
2241
|
+
throw new CLIError(
|
|
2242
|
+
ErrorCode.INTERNAL_ERROR,
|
|
2243
|
+
"Approved wallet session response missing required metadata."
|
|
2244
|
+
);
|
|
2245
|
+
}
|
|
2246
|
+
return { walletId, walletAddress };
|
|
2247
|
+
}
|
|
2142
2248
|
async function runSessionConnect(opts) {
|
|
2249
|
+
const requestedChains = ["evm", "solana"];
|
|
2143
2250
|
const authToken = resolveAuthToken();
|
|
2144
2251
|
if (!authToken) throw errAuthRequired();
|
|
2145
2252
|
const existing = loadSession();
|
|
@@ -2177,32 +2284,51 @@ async function runSessionConnect(opts) {
|
|
|
2177
2284
|
...clientInstance.name === void 0 ? {} : { clientInstanceName: clientInstance.name }
|
|
2178
2285
|
};
|
|
2179
2286
|
updateSession({
|
|
2180
|
-
chainType: "
|
|
2181
|
-
capabilities:
|
|
2287
|
+
chainType: "both",
|
|
2288
|
+
capabilities: Object.assign(
|
|
2289
|
+
{},
|
|
2290
|
+
...requestedChains.map((chain) => capabilitiesForChain(chain))
|
|
2291
|
+
),
|
|
2182
2292
|
backendBaseUrl: getWalletApiBaseUrl(),
|
|
2183
2293
|
environment: sessionEnvironment
|
|
2184
2294
|
});
|
|
2185
|
-
const
|
|
2295
|
+
const remoteRequest = await createRemoteWalletSessionRequest(authToken, {
|
|
2186
2296
|
publicKeyJwk: session.publicKeyJwk,
|
|
2187
2297
|
requestSignerVersion: session.envelopeVersion,
|
|
2188
|
-
|
|
2189
|
-
capabilities:
|
|
2298
|
+
chains: requestedChains,
|
|
2299
|
+
capabilities: capabilitiesForChains(requestedChains),
|
|
2190
2300
|
environment: sessionEnvironment
|
|
2191
2301
|
}).catch((err) => {
|
|
2192
2302
|
clearSession();
|
|
2193
2303
|
throw err;
|
|
2194
2304
|
});
|
|
2305
|
+
const pendingSessionsByChain = Object.fromEntries(
|
|
2306
|
+
remoteRequest.sessions.map((remoteSession) => [
|
|
2307
|
+
remoteSession.chainType,
|
|
2308
|
+
{
|
|
2309
|
+
sessionId: remoteSession.walletSessionId,
|
|
2310
|
+
status: "pending",
|
|
2311
|
+
expiresAt: remoteRequest.expiresAt ?? session.expiresAt,
|
|
2312
|
+
chainType: remoteSession.chainType,
|
|
2313
|
+
capabilities: capabilitiesForChain(
|
|
2314
|
+
remoteSession.chainType
|
|
2315
|
+
)
|
|
2316
|
+
}
|
|
2317
|
+
])
|
|
2318
|
+
);
|
|
2195
2319
|
updateSession({
|
|
2196
|
-
|
|
2197
|
-
|
|
2320
|
+
connectionRequestId: remoteRequest.sessionId,
|
|
2321
|
+
sessionId: remoteRequest.sessions[0].walletSessionId,
|
|
2322
|
+
expiresAt: remoteRequest.expiresAt ?? session.expiresAt,
|
|
2323
|
+
sessionsByChain: pendingSessionsByChain
|
|
2198
2324
|
});
|
|
2199
2325
|
if (!isJSONMode()) {
|
|
2200
2326
|
const summaryPairs = [
|
|
2201
|
-
["
|
|
2327
|
+
["Connection Request ID", remoteRequest.sessionId],
|
|
2202
2328
|
["Status", "pending"],
|
|
2203
|
-
["Approval URL",
|
|
2329
|
+
["Approval URL", remoteRequest.approvalUrl],
|
|
2204
2330
|
["Created", session.createdAt],
|
|
2205
|
-
["Expires",
|
|
2331
|
+
["Expires", remoteRequest.expiresAt ?? session.expiresAt]
|
|
2206
2332
|
];
|
|
2207
2333
|
if (clientInstance.name !== void 0) {
|
|
2208
2334
|
summaryPairs.splice(1, 0, ["Instance", clientInstance.name]);
|
|
@@ -2217,7 +2343,14 @@ async function runSessionConnect(opts) {
|
|
|
2217
2343
|
});
|
|
2218
2344
|
if (answer === null) {
|
|
2219
2345
|
clearSession();
|
|
2220
|
-
await
|
|
2346
|
+
await Promise.all(
|
|
2347
|
+
remoteRequest.sessions.map(
|
|
2348
|
+
(remoteSession) => disconnectRemoteWalletSession(
|
|
2349
|
+
authToken,
|
|
2350
|
+
remoteSession.walletSessionId
|
|
2351
|
+
).catch(() => void 0)
|
|
2352
|
+
)
|
|
2353
|
+
);
|
|
2221
2354
|
throw new WalletConnectInterruptedError();
|
|
2222
2355
|
}
|
|
2223
2356
|
}
|
|
@@ -2225,25 +2358,41 @@ async function runSessionConnect(opts) {
|
|
|
2225
2358
|
console.log(` Opening browser for approval...`);
|
|
2226
2359
|
console.log(` ${dim("Waiting for dashboard approval to complete connection.")}`);
|
|
2227
2360
|
}
|
|
2228
|
-
openBrowser(
|
|
2229
|
-
const
|
|
2361
|
+
openBrowser(remoteRequest.approvalUrl);
|
|
2362
|
+
const approvedSessions = await withApprovalInterruptHandler({
|
|
2230
2363
|
authToken,
|
|
2231
|
-
|
|
2364
|
+
sessionIds: remoteRequest.sessions.map(
|
|
2365
|
+
(remoteSession) => remoteSession.walletSessionId
|
|
2366
|
+
),
|
|
2232
2367
|
run: async (signal) => {
|
|
2233
2368
|
const startedAt = Date.now();
|
|
2234
2369
|
while (Date.now() - startedAt < CONNECT_TIMEOUT_MS) {
|
|
2235
|
-
const
|
|
2236
|
-
|
|
2370
|
+
const currentSessions = await waitForInterruptible(
|
|
2371
|
+
remoteRequest.sessionId ? getRemoteWalletSessionRequest(
|
|
2372
|
+
authToken,
|
|
2373
|
+
remoteRequest.sessionId
|
|
2374
|
+
).then((request2) => request2.sessions) : Promise.all(
|
|
2375
|
+
remoteRequest.sessions.map(
|
|
2376
|
+
(remoteSession) => getRemoteWalletSession(authToken, remoteSession.walletSessionId)
|
|
2377
|
+
)
|
|
2378
|
+
),
|
|
2237
2379
|
signal
|
|
2238
2380
|
);
|
|
2239
|
-
if (
|
|
2240
|
-
|
|
2381
|
+
if (requestedChains.every(
|
|
2382
|
+
(chain) => currentSessions.some((current) => {
|
|
2383
|
+
return current.chainType === chain && current.status === "approved";
|
|
2384
|
+
})
|
|
2385
|
+
)) {
|
|
2386
|
+
return currentSessions;
|
|
2241
2387
|
}
|
|
2242
|
-
|
|
2388
|
+
const terminalSession = currentSessions.find((current) => {
|
|
2389
|
+
return current.status === "denied" || current.status === "revoked" || current.status === "expired";
|
|
2390
|
+
});
|
|
2391
|
+
if (terminalSession) {
|
|
2243
2392
|
clearSession();
|
|
2244
2393
|
throw new CLIError(
|
|
2245
2394
|
ErrorCode.INTERNAL_ERROR,
|
|
2246
|
-
`Wallet session ${
|
|
2395
|
+
`Wallet session ${terminalSession.status}.`,
|
|
2247
2396
|
"Run 'alchemy wallet connect' to start a new approval flow."
|
|
2248
2397
|
);
|
|
2249
2398
|
}
|
|
@@ -2252,58 +2401,123 @@ async function runSessionConnect(opts) {
|
|
|
2252
2401
|
return null;
|
|
2253
2402
|
}
|
|
2254
2403
|
});
|
|
2255
|
-
if (!
|
|
2404
|
+
if (!approvedSessions) {
|
|
2256
2405
|
throw new CLIError(
|
|
2257
2406
|
ErrorCode.NETWORK_ERROR,
|
|
2258
2407
|
"Timed out waiting for wallet approval.",
|
|
2259
2408
|
"Finish approval in the dashboard and rerun 'alchemy wallet connect --force' if needed."
|
|
2260
2409
|
);
|
|
2261
2410
|
}
|
|
2262
|
-
const
|
|
2263
|
-
|
|
2264
|
-
|
|
2411
|
+
const missingProviderAppId = approvedSessions.find((approvedSession) => {
|
|
2412
|
+
return !approvedSession.privyAppId;
|
|
2413
|
+
});
|
|
2414
|
+
if (missingProviderAppId) {
|
|
2265
2415
|
throw new CLIError(
|
|
2266
2416
|
ErrorCode.INTERNAL_ERROR,
|
|
2267
2417
|
"Approved wallet session response missing required metadata."
|
|
2268
2418
|
);
|
|
2269
2419
|
}
|
|
2420
|
+
const approvedSessionsByChain = Object.fromEntries(
|
|
2421
|
+
requestedChains.map((chain) => {
|
|
2422
|
+
const approvedSession = approvedSessions.find((current) => {
|
|
2423
|
+
return current.chainType === chain;
|
|
2424
|
+
});
|
|
2425
|
+
if (!approvedSession) {
|
|
2426
|
+
throw new CLIError(
|
|
2427
|
+
ErrorCode.INTERNAL_ERROR,
|
|
2428
|
+
"Approved wallet session response missing requested chain."
|
|
2429
|
+
);
|
|
2430
|
+
}
|
|
2431
|
+
const { walletId, walletAddress } = getApprovedSessionWalletMetadata(
|
|
2432
|
+
chain,
|
|
2433
|
+
approvedSession
|
|
2434
|
+
);
|
|
2435
|
+
return [
|
|
2436
|
+
chain,
|
|
2437
|
+
{
|
|
2438
|
+
sessionId: approvedSession.sessionId ?? remoteRequest.sessions.find((remoteSession) => remoteSession.chainType === chain)?.walletSessionId ?? session.sessionId,
|
|
2439
|
+
status: "approved",
|
|
2440
|
+
expiresAt: approvedSession.expiresAt ?? remoteRequest.expiresAt ?? session.expiresAt,
|
|
2441
|
+
chainType: chain,
|
|
2442
|
+
walletId,
|
|
2443
|
+
walletAddress,
|
|
2444
|
+
providerKeyQuorumId: approvedSession.privyKeyQuorumId,
|
|
2445
|
+
providerSignerId: approvedSession.privySignerId,
|
|
2446
|
+
capabilities: approvedSession.capabilities ?? capabilitiesForChain(chain)
|
|
2447
|
+
}
|
|
2448
|
+
];
|
|
2449
|
+
})
|
|
2450
|
+
);
|
|
2451
|
+
const firstApprovedSession = approvedSessions.find((approvedSession) => {
|
|
2452
|
+
return approvedSession.chainType === requestedChains[0];
|
|
2453
|
+
}) ?? approvedSessions[0];
|
|
2454
|
+
const evmSession = approvedSessionsByChain.evm;
|
|
2455
|
+
const solanaSession = approvedSessionsByChain.solana;
|
|
2270
2456
|
updateSession({
|
|
2271
|
-
|
|
2457
|
+
connectionRequestId: remoteRequest.sessionId,
|
|
2458
|
+
sessionId: firstApprovedSession.sessionId ?? remoteRequest.sessions[0].walletSessionId,
|
|
2272
2459
|
status: "approved",
|
|
2273
|
-
expiresAt:
|
|
2274
|
-
privyAppId:
|
|
2275
|
-
walletId,
|
|
2276
|
-
evmWalletId:
|
|
2277
|
-
evmAddress,
|
|
2278
|
-
solanaWalletId:
|
|
2279
|
-
solanaAddress:
|
|
2280
|
-
privyKeyQuorumId:
|
|
2281
|
-
privySignerId:
|
|
2282
|
-
chainType:
|
|
2283
|
-
capabilities:
|
|
2460
|
+
expiresAt: firstApprovedSession.expiresAt ?? remoteRequest.expiresAt ?? session.expiresAt,
|
|
2461
|
+
privyAppId: firstApprovedSession.privyAppId,
|
|
2462
|
+
walletId: evmSession?.walletId ?? solanaSession?.walletId,
|
|
2463
|
+
evmWalletId: evmSession?.walletId,
|
|
2464
|
+
evmAddress: evmSession?.walletAddress,
|
|
2465
|
+
solanaWalletId: solanaSession?.walletId,
|
|
2466
|
+
solanaAddress: solanaSession?.walletAddress,
|
|
2467
|
+
privyKeyQuorumId: evmSession?.providerKeyQuorumId ?? solanaSession?.providerKeyQuorumId,
|
|
2468
|
+
privySignerId: evmSession?.providerSignerId ?? solanaSession?.providerSignerId,
|
|
2469
|
+
chainType: "both",
|
|
2470
|
+
capabilities: Object.assign(
|
|
2471
|
+
{},
|
|
2472
|
+
...requestedChains.map((chain) => capabilitiesForChain(chain)),
|
|
2473
|
+
...approvedSessions.map((approvedSession) => approvedSession.capabilities ?? {})
|
|
2474
|
+
),
|
|
2475
|
+
sessionsByChain: approvedSessionsByChain,
|
|
2284
2476
|
backendBaseUrl: getWalletApiBaseUrl(),
|
|
2285
2477
|
environment: sessionEnvironment
|
|
2286
2478
|
});
|
|
2287
2479
|
if (isJSONMode()) {
|
|
2288
2480
|
printJSON({
|
|
2289
|
-
|
|
2481
|
+
connectionRequestId: remoteRequest.sessionId,
|
|
2482
|
+
sessionId: firstApprovedSession.sessionId ?? remoteRequest.sessions[0].walletSessionId,
|
|
2483
|
+
walletSessionId: firstApprovedSession.sessionId ?? remoteRequest.sessions[0].walletSessionId,
|
|
2290
2484
|
status: "approved",
|
|
2291
|
-
privyAppId:
|
|
2292
|
-
walletId,
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2485
|
+
privyAppId: firstApprovedSession.privyAppId,
|
|
2486
|
+
walletId: evmSession?.walletId ?? solanaSession?.walletId,
|
|
2487
|
+
...evmSession ? {
|
|
2488
|
+
evmAddress: evmSession.walletAddress,
|
|
2489
|
+
evmWalletId: evmSession.walletId
|
|
2490
|
+
} : {},
|
|
2491
|
+
...solanaSession ? {
|
|
2492
|
+
solanaAddress: solanaSession.walletAddress,
|
|
2493
|
+
solanaWalletId: solanaSession.walletId
|
|
2494
|
+
} : {},
|
|
2495
|
+
chainType: "both",
|
|
2496
|
+
capabilities: Object.assign(
|
|
2497
|
+
{},
|
|
2498
|
+
...requestedChains.map((chain) => capabilitiesForChain(chain))
|
|
2499
|
+
),
|
|
2500
|
+
expiresAt: firstApprovedSession.expiresAt ?? remoteRequest.expiresAt ?? session.expiresAt,
|
|
2501
|
+
sessionsByChain: approvedSessionsByChain
|
|
2298
2502
|
});
|
|
2299
2503
|
} else {
|
|
2300
|
-
|
|
2301
|
-
["
|
|
2302
|
-
["Status", green("approved")]
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2504
|
+
const pairs = [
|
|
2505
|
+
["Connection Request ID", remoteRequest.sessionId],
|
|
2506
|
+
["Status", green("approved")]
|
|
2507
|
+
];
|
|
2508
|
+
for (const chain of requestedChains) {
|
|
2509
|
+
const chainSession = approvedSessionsByChain[chain];
|
|
2510
|
+
if (!chainSession) continue;
|
|
2511
|
+
pairs.push(
|
|
2512
|
+
[`${chain.toUpperCase()} Wallet ID`, chainSession.walletId ?? ""],
|
|
2513
|
+
[`${chain.toUpperCase()} Address`, green(chainSession.walletAddress ?? "")]
|
|
2514
|
+
);
|
|
2515
|
+
}
|
|
2516
|
+
pairs.push([
|
|
2517
|
+
"Expires",
|
|
2518
|
+
firstApprovedSession.expiresAt ?? remoteRequest.expiresAt ?? session.expiresAt
|
|
2306
2519
|
]);
|
|
2520
|
+
printKeyValue(pairs);
|
|
2307
2521
|
console.log(` ${green("\u2713")} Wallet connected`);
|
|
2308
2522
|
}
|
|
2309
2523
|
}
|
|
@@ -2372,17 +2586,6 @@ async function runConnectFlow(program2, opts) {
|
|
|
2372
2586
|
}
|
|
2373
2587
|
mode2 = "local";
|
|
2374
2588
|
}
|
|
2375
|
-
let chain = "both";
|
|
2376
|
-
if (opts.chain !== void 0) {
|
|
2377
|
-
if (opts.chain !== "evm" && opts.chain !== "solana" && opts.chain !== "both") {
|
|
2378
|
-
throw errInvalidArgs("`--chain` must be 'evm', 'solana', or 'both'.");
|
|
2379
|
-
}
|
|
2380
|
-
chain = opts.chain;
|
|
2381
|
-
}
|
|
2382
|
-
if (importPath && chain !== "evm" && opts.chain !== void 0) {
|
|
2383
|
-
throw errInvalidArgs("`--import` implies `--chain evm`; omit `--chain` or set it to 'evm'.");
|
|
2384
|
-
}
|
|
2385
|
-
if (importPath) chain = "evm";
|
|
2386
2589
|
if (!mode2) {
|
|
2387
2590
|
if (!isInteractiveAllowed(program2)) {
|
|
2388
2591
|
throw errInvalidArgs(
|
|
@@ -2392,7 +2595,7 @@ async function runConnectFlow(program2, opts) {
|
|
|
2392
2595
|
const choice = await promptSelect({
|
|
2393
2596
|
message: "Choose a wallet to connect",
|
|
2394
2597
|
options: [
|
|
2395
|
-
{ value: "session", label: "Session wallet", hint: "Recommended \u2014 Alchemy
|
|
2598
|
+
{ value: "session", label: "Session wallet", hint: "Recommended \u2014 Alchemy-managed, more secure" },
|
|
2396
2599
|
{ value: "local", label: "Local wallet", hint: "Private key stored on this machine" }
|
|
2397
2600
|
],
|
|
2398
2601
|
initialValue: "session",
|
|
@@ -2402,7 +2605,11 @@ async function runConnectFlow(program2, opts) {
|
|
|
2402
2605
|
mode2 = choice;
|
|
2403
2606
|
}
|
|
2404
2607
|
if (mode2 === "session") {
|
|
2405
|
-
await runSessionConnect({
|
|
2608
|
+
await runSessionConnect({
|
|
2609
|
+
program: program2,
|
|
2610
|
+
force,
|
|
2611
|
+
instanceName: opts.instanceName
|
|
2612
|
+
});
|
|
2406
2613
|
printCrossModeHintAfterSessionConnect();
|
|
2407
2614
|
return;
|
|
2408
2615
|
}
|
|
@@ -2412,9 +2619,55 @@ async function runConnectFlow(program2, opts) {
|
|
|
2412
2619
|
printCrossModeHintAfterLocal("evm");
|
|
2413
2620
|
return;
|
|
2414
2621
|
}
|
|
2415
|
-
const result = await runLocalCreate({
|
|
2622
|
+
const result = await runLocalCreate({ force, program: program2 });
|
|
2416
2623
|
printPostLocalCreateSummary(result);
|
|
2417
|
-
printCrossModeHintAfterLocal(
|
|
2624
|
+
printCrossModeHintAfterLocal("both");
|
|
2625
|
+
}
|
|
2626
|
+
function uniqueSessionIds(session) {
|
|
2627
|
+
const ids = Object.values(session.sessionsByChain ?? {}).map((chainSession) => chainSession?.sessionId).filter((sessionId) => Boolean(sessionId));
|
|
2628
|
+
if (ids.length === 0) {
|
|
2629
|
+
ids.push(session.sessionId);
|
|
2630
|
+
}
|
|
2631
|
+
return Array.from(new Set(ids));
|
|
2632
|
+
}
|
|
2633
|
+
function selectRemoteSessionForStatus(session, remoteSessions) {
|
|
2634
|
+
return remoteSessions.find((remoteSession) => {
|
|
2635
|
+
return remoteSession.status !== "approved";
|
|
2636
|
+
}) ?? remoteSessions.find((remoteSession) => {
|
|
2637
|
+
return remoteSession.sessionId === session.sessionId;
|
|
2638
|
+
}) ?? remoteSessions[0];
|
|
2639
|
+
}
|
|
2640
|
+
function mergeRemoteCapabilities(session, remoteSessions) {
|
|
2641
|
+
return Object.assign(
|
|
2642
|
+
{},
|
|
2643
|
+
session.capabilities ?? {},
|
|
2644
|
+
...remoteSessions.map((remoteSession) => remoteSession.capabilities ?? {})
|
|
2645
|
+
);
|
|
2646
|
+
}
|
|
2647
|
+
async function getRemoteSessionsForStatus(authToken, session) {
|
|
2648
|
+
const sessionIds = uniqueSessionIds(session);
|
|
2649
|
+
if (session.connectionRequestId) {
|
|
2650
|
+
try {
|
|
2651
|
+
return await getRemoteWalletSessionRequest(
|
|
2652
|
+
authToken,
|
|
2653
|
+
session.connectionRequestId
|
|
2654
|
+
).then((request2) => request2.sessions);
|
|
2655
|
+
} catch {
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
const results = await Promise.allSettled(
|
|
2659
|
+
sessionIds.map((sessionId) => getRemoteWalletSession(authToken, sessionId))
|
|
2660
|
+
);
|
|
2661
|
+
const remoteSessions = results.flatMap((result) => {
|
|
2662
|
+
return result.status === "fulfilled" ? [result.value] : [];
|
|
2663
|
+
});
|
|
2664
|
+
if (remoteSessions.length === 0) {
|
|
2665
|
+
const firstRejection = results.find((result) => {
|
|
2666
|
+
return result.status === "rejected";
|
|
2667
|
+
});
|
|
2668
|
+
throw firstRejection?.reason ?? new Error("Unable to verify wallet session.");
|
|
2669
|
+
}
|
|
2670
|
+
return remoteSessions;
|
|
2418
2671
|
}
|
|
2419
2672
|
async function buildSessionSnapshot(program2, verify) {
|
|
2420
2673
|
let session = loadStoredSession?.() ?? loadSession();
|
|
@@ -2422,25 +2675,51 @@ async function buildSessionSnapshot(program2, verify) {
|
|
|
2422
2675
|
if (verify && session) {
|
|
2423
2676
|
const authToken = resolveAuthToken();
|
|
2424
2677
|
if (!authToken) throw errAuthRequired();
|
|
2425
|
-
const
|
|
2678
|
+
const remoteSessions = await getRemoteSessionsForStatus(authToken, session);
|
|
2679
|
+
const remote = selectRemoteSessionForStatus(session, remoteSessions);
|
|
2426
2680
|
remoteStatus = remote.status;
|
|
2427
|
-
const
|
|
2681
|
+
const nextSessionsByChain = { ...session.sessionsByChain ?? {} };
|
|
2682
|
+
for (const remoteSession of remoteSessions) {
|
|
2683
|
+
const chain = remoteSession.chainType === "solana" ? "solana" : "evm";
|
|
2684
|
+
const walletIdForChain = chain === "solana" ? remoteSession.solanaWalletId ?? remoteSession.walletId : remoteSession.evmWalletId ?? remoteSession.walletId;
|
|
2685
|
+
const walletAddressForChain = chain === "solana" ? remoteSession.solanaAddress ?? remoteSession.address : remoteSession.evmAddress ?? remoteSession.address;
|
|
2686
|
+
nextSessionsByChain[chain] = {
|
|
2687
|
+
...nextSessionsByChain[chain] ?? {},
|
|
2688
|
+
sessionId: remoteSession.sessionId ?? nextSessionsByChain[chain]?.sessionId ?? session.sessionId,
|
|
2689
|
+
status: normalizeRemoteStatusForStorage(remoteSession.status),
|
|
2690
|
+
expiresAt: remoteSession.expiresAt ?? nextSessionsByChain[chain]?.expiresAt ?? session.expiresAt,
|
|
2691
|
+
chainType: chain,
|
|
2692
|
+
...walletIdForChain ? { walletId: walletIdForChain } : {},
|
|
2693
|
+
...walletAddressForChain ? { walletAddress: walletAddressForChain } : {},
|
|
2694
|
+
...remoteSession.privyKeyQuorumId ? { providerKeyQuorumId: remoteSession.privyKeyQuorumId } : {},
|
|
2695
|
+
...remoteSession.privySignerId ? { providerSignerId: remoteSession.privySignerId } : {},
|
|
2696
|
+
...remoteSession.capabilities ? { capabilities: remoteSession.capabilities } : {}
|
|
2697
|
+
};
|
|
2698
|
+
}
|
|
2699
|
+
const remoteChain = remote.chainType === "solana" ? "solana" : "evm";
|
|
2700
|
+
const remoteWalletId = remoteChain === "solana" ? remote.solanaWalletId ?? remote.walletId : remote.evmWalletId ?? remote.walletId;
|
|
2701
|
+
const evmWalletId = remoteChain === "evm" ? remoteWalletId ?? session.evmWalletId : session.evmWalletId;
|
|
2702
|
+
const evmAddress = remoteChain === "evm" ? remote.evmAddress ?? remote.address ?? session.evmAddress : session.evmAddress;
|
|
2703
|
+
const solanaWalletId = remoteChain === "solana" ? remoteWalletId ?? session.solanaWalletId : session.solanaWalletId;
|
|
2704
|
+
const solanaAddress = remoteChain === "solana" ? remote.solanaAddress ?? remote.address ?? session.solanaAddress : session.solanaAddress;
|
|
2705
|
+
const chainType = nextSessionsByChain.evm && nextSessionsByChain.solana ? "both" : remote.chainType ?? session.chainType;
|
|
2428
2706
|
session = {
|
|
2429
2707
|
...session,
|
|
2430
2708
|
status: normalizeRemoteStatusForStorage(remote.status),
|
|
2431
2709
|
expiresAt: remote.expiresAt ?? session.expiresAt,
|
|
2432
2710
|
privyAppId: remote.privyAppId ?? session.privyAppId,
|
|
2433
|
-
walletId:
|
|
2434
|
-
evmWalletId
|
|
2435
|
-
evmAddress
|
|
2436
|
-
solanaWalletId
|
|
2437
|
-
solanaAddress
|
|
2438
|
-
chainType
|
|
2439
|
-
capabilities:
|
|
2711
|
+
walletId: evmWalletId ?? solanaWalletId ?? session.walletId,
|
|
2712
|
+
evmWalletId,
|
|
2713
|
+
evmAddress,
|
|
2714
|
+
solanaWalletId,
|
|
2715
|
+
solanaAddress,
|
|
2716
|
+
chainType,
|
|
2717
|
+
capabilities: mergeRemoteCapabilities(session, remoteSessions),
|
|
2718
|
+
sessionsByChain: nextSessionsByChain
|
|
2440
2719
|
};
|
|
2441
2720
|
saveSession(session);
|
|
2442
2721
|
}
|
|
2443
|
-
const status = deriveWalletStatus(session
|
|
2722
|
+
const status = deriveWalletStatus(session);
|
|
2444
2723
|
const walletAddress = resolveSessionAddress(session);
|
|
2445
2724
|
const environment = resolveSessionEnvironment(session);
|
|
2446
2725
|
const signerCapabilities = resolveEnabledCapabilities(session);
|
|
@@ -2456,14 +2735,16 @@ async function buildSessionSnapshot(program2, verify) {
|
|
|
2456
2735
|
walletId,
|
|
2457
2736
|
expiresAt,
|
|
2458
2737
|
sessionId: session?.sessionId ?? null,
|
|
2738
|
+
connectionRequestId: session?.connectionRequestId ?? null,
|
|
2459
2739
|
sessionState: session?.status ?? null,
|
|
2460
2740
|
chainType: session?.chainType ?? null,
|
|
2741
|
+
sessionsByChain: session?.sessionsByChain ?? null,
|
|
2461
2742
|
valid: session ? isSessionValid(session) : false
|
|
2462
2743
|
};
|
|
2463
2744
|
}
|
|
2464
2745
|
function registerWallets(program2) {
|
|
2465
2746
|
const cmd = program2.command("wallet").description("Manage wallets");
|
|
2466
|
-
cmd.command("connect").description("Connect a wallet for onchain actions (session or local)").option("--mode <mode>", "session | local").option("--
|
|
2747
|
+
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) => {
|
|
2467
2748
|
try {
|
|
2468
2749
|
await runConnectFlow(program2, opts);
|
|
2469
2750
|
} catch (err) {
|
|
@@ -2493,10 +2774,12 @@ function registerWallets(program2) {
|
|
|
2493
2774
|
expiresAt: snap.expiresAt,
|
|
2494
2775
|
environment: snap.environment,
|
|
2495
2776
|
signerCapabilities: snap.signerCapabilities,
|
|
2777
|
+
connectionRequestId: snap.connectionRequestId,
|
|
2496
2778
|
sessionId: snap.sessionId,
|
|
2497
2779
|
sessionState: snap.sessionState,
|
|
2498
2780
|
walletId: snap.walletId,
|
|
2499
2781
|
chainType: snap.chainType,
|
|
2782
|
+
sessionsByChain: snap.sessionsByChain,
|
|
2500
2783
|
verified: Boolean(opts.verify),
|
|
2501
2784
|
remoteStatus: snap.remoteStatus,
|
|
2502
2785
|
valid: snap.valid,
|
|
@@ -2507,10 +2790,12 @@ function registerWallets(program2) {
|
|
|
2507
2790
|
expiresAt: snap.expiresAt,
|
|
2508
2791
|
environment: snap.environment,
|
|
2509
2792
|
signerCapabilities: snap.signerCapabilities,
|
|
2793
|
+
connectionRequestId: snap.connectionRequestId,
|
|
2510
2794
|
sessionId: snap.sessionId,
|
|
2511
2795
|
sessionState: snap.sessionState,
|
|
2512
2796
|
walletId: snap.walletId,
|
|
2513
2797
|
chainType: snap.chainType,
|
|
2798
|
+
sessionsByChain: snap.sessionsByChain,
|
|
2514
2799
|
valid: snap.valid
|
|
2515
2800
|
},
|
|
2516
2801
|
localEvm: localState.evmAddress ? { address: localState.evmAddress, keyFile: localState.evmKeyFile } : null,
|
|
@@ -2528,7 +2813,11 @@ function registerWallets(program2) {
|
|
|
2528
2813
|
["Environment", snap.environment ?? dim("none")],
|
|
2529
2814
|
["Signer Capabilities", snap.signerCapabilities.length > 0 ? snap.signerCapabilities.join(", ") : dim("none")]
|
|
2530
2815
|
];
|
|
2531
|
-
if (snap.
|
|
2816
|
+
if (snap.connectionRequestId) {
|
|
2817
|
+
pairs.push(["Connection Request ID", snap.connectionRequestId]);
|
|
2818
|
+
} else if (snap.sessionId) {
|
|
2819
|
+
pairs.push(["Session ID", snap.sessionId]);
|
|
2820
|
+
}
|
|
2532
2821
|
if (snap.walletId) pairs.push(["Wallet ID", snap.walletId]);
|
|
2533
2822
|
if (opts.verify) {
|
|
2534
2823
|
pairs.push(["Backend Status", snap.remoteStatus ?? dim("not checked")]);
|
|
@@ -2683,7 +2972,7 @@ function registerWallets(program2) {
|
|
|
2683
2972
|
}
|
|
2684
2973
|
if (target === "local" && !hasLocalEvmKey()) {
|
|
2685
2974
|
throw errInvalidArgs(
|
|
2686
|
-
"No local EVM key configured. Run `alchemy wallet connect --mode local
|
|
2975
|
+
"No local EVM key configured. Run `alchemy wallet connect --mode local` first."
|
|
2687
2976
|
);
|
|
2688
2977
|
}
|
|
2689
2978
|
const cfg = load();
|
|
@@ -2717,11 +3006,23 @@ function registerWallets(program2) {
|
|
|
2717
3006
|
let revoked = false;
|
|
2718
3007
|
let alreadyDisconnected = false;
|
|
2719
3008
|
let remoteStatus = null;
|
|
3009
|
+
let backendRevokeFailed = false;
|
|
3010
|
+
const sessionIdsToDisconnect = uniqueSessionIds(session);
|
|
2720
3011
|
if (authToken) {
|
|
2721
|
-
const
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
3012
|
+
const results = await Promise.allSettled(
|
|
3013
|
+
sessionIdsToDisconnect.map(
|
|
3014
|
+
(sessionId) => disconnectRemoteWalletSession(authToken, sessionId)
|
|
3015
|
+
)
|
|
3016
|
+
);
|
|
3017
|
+
const successfulResults = results.flatMap((result) => {
|
|
3018
|
+
return result.status === "fulfilled" ? [result.value] : [];
|
|
3019
|
+
});
|
|
3020
|
+
backendRevokeFailed = results.some((result) => {
|
|
3021
|
+
return result.status === "rejected";
|
|
3022
|
+
});
|
|
3023
|
+
revoked = successfulResults.some((remote) => !remote.alreadyDisconnected);
|
|
3024
|
+
alreadyDisconnected = successfulResults.length > 0 && successfulResults.every((remote) => remote.alreadyDisconnected);
|
|
3025
|
+
remoteStatus = successfulResults[0]?.status ?? null;
|
|
2725
3026
|
}
|
|
2726
3027
|
const removed = clearSession();
|
|
2727
3028
|
const cfg = load();
|
|
@@ -2735,8 +3036,11 @@ function registerWallets(program2) {
|
|
|
2735
3036
|
revoked,
|
|
2736
3037
|
alreadyDisconnected,
|
|
2737
3038
|
remoteStatus,
|
|
2738
|
-
backendRevokeAttempted: Boolean(authToken)
|
|
3039
|
+
backendRevokeAttempted: Boolean(authToken),
|
|
3040
|
+
backendRevokeFailed
|
|
2739
3041
|
});
|
|
3042
|
+
} else if (removed && authToken && backendRevokeFailed) {
|
|
3043
|
+
console.log(` ${green("\u2713")} Wallet session disconnected (${dim("backend revoke partially failed")})`);
|
|
2740
3044
|
} else if (removed && authToken && alreadyDisconnected) {
|
|
2741
3045
|
console.log(` ${green("\u2713")} Wallet session disconnected (${dim("already revoked or expired")})`);
|
|
2742
3046
|
} else if (removed && authToken) {
|
|
@@ -3120,9 +3424,10 @@ import {
|
|
|
3120
3424
|
createKeyPairSignerFromBytes as createKeyPairSignerFromBytes2,
|
|
3121
3425
|
createKeyPairSignerFromPrivateKeyBytes as createKeyPairSignerFromPrivateKeyBytes2
|
|
3122
3426
|
} from "@solana/kit";
|
|
3123
|
-
import {
|
|
3427
|
+
import { sign as signWithPrivateKey } from "crypto";
|
|
3124
3428
|
var SOL_DECIMALS = 9;
|
|
3125
3429
|
var SPONSOR_FEE_PAYER_PLACEHOLDER = address("Amh6quo1FcmL16Qmzdugzjq3Lv1zXzTW7ktswyLDzits");
|
|
3430
|
+
var SYSTEM_PROGRAM_ADDRESS = address("11111111111111111111111111111111");
|
|
3126
3431
|
var SPL_TOKEN_PROGRAM_ADDRESS = address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
|
|
3127
3432
|
function parseSolanaKeyBytes(secret) {
|
|
3128
3433
|
const trimmed = secret.trim();
|
|
@@ -3153,11 +3458,28 @@ async function createSolanaSignerFromKeyBytes(keyBytes) {
|
|
|
3153
3458
|
throw errInvalidArgs("Invalid Solana key: expected 64-byte secret key or 32-byte private key.");
|
|
3154
3459
|
}
|
|
3155
3460
|
function buildSolTransferInstruction(from, to, lamports) {
|
|
3156
|
-
return
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3461
|
+
return {
|
|
3462
|
+
programAddress: SYSTEM_PROGRAM_ADDRESS,
|
|
3463
|
+
accounts: [
|
|
3464
|
+
{ address: from.address, role: AccountRole.WRITABLE_SIGNER },
|
|
3465
|
+
{ address: to, role: AccountRole.WRITABLE }
|
|
3466
|
+
],
|
|
3467
|
+
data: new Uint8Array([
|
|
3468
|
+
...encodeU32LE(2),
|
|
3469
|
+
...encodeU64LE(lamports)
|
|
3470
|
+
])
|
|
3471
|
+
};
|
|
3472
|
+
}
|
|
3473
|
+
function encodeU32LE(value) {
|
|
3474
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > 4294967295) {
|
|
3475
|
+
throw errInvalidArgs("Instruction discriminator must fit in an unsigned 32-bit integer.");
|
|
3476
|
+
}
|
|
3477
|
+
const bytes = new Uint8Array(4);
|
|
3478
|
+
bytes[0] = value & 255;
|
|
3479
|
+
bytes[1] = value >> 8 & 255;
|
|
3480
|
+
bytes[2] = value >> 16 & 255;
|
|
3481
|
+
bytes[3] = value >> 24 & 255;
|
|
3482
|
+
return bytes;
|
|
3161
3483
|
}
|
|
3162
3484
|
function encodeU64LE(value) {
|
|
3163
3485
|
if (value < 0n || value > 0xffffffffffffffffn) {
|
|
@@ -3238,6 +3560,38 @@ async function buildAndSendSolanaTransaction(opts) {
|
|
|
3238
3560
|
const signature = await client.call("sendTransaction", [wireTransaction, { encoding: "base64" }]);
|
|
3239
3561
|
return { signature, fromAddress: signer.address };
|
|
3240
3562
|
}
|
|
3563
|
+
async function buildAndSendSolanaTransactionWithSession(opts) {
|
|
3564
|
+
const { client, instructions, session, authToken, sponsored, gasPolicyId } = opts;
|
|
3565
|
+
const fromAddress = getSolanaSessionAddress(session);
|
|
3566
|
+
const blockhashResult = await client.call("getLatestBlockhash", [{ commitment: "finalized" }]);
|
|
3567
|
+
const { blockhash, lastValidBlockHeight } = blockhashResult.value;
|
|
3568
|
+
const feePayer = sponsored ? SPONSOR_FEE_PAYER_PLACEHOLDER : address(fromAddress);
|
|
3569
|
+
const txMessage = pipe(
|
|
3570
|
+
createTransactionMessage({ version: 0 }),
|
|
3571
|
+
(msg) => setTransactionMessageFeePayer(feePayer, msg),
|
|
3572
|
+
(msg) => setTransactionMessageLifetimeUsingBlockhash(
|
|
3573
|
+
{ blockhash, lastValidBlockHeight },
|
|
3574
|
+
msg
|
|
3575
|
+
),
|
|
3576
|
+
(msg) => appendTransactionMessageInstructions(instructions, msg)
|
|
3577
|
+
);
|
|
3578
|
+
const compiledTx = compileTransaction(txMessage);
|
|
3579
|
+
const transactionToSign = sponsored ? await sponsorSolanaTransaction({
|
|
3580
|
+
client,
|
|
3581
|
+
compiledTransactionBase64: getBase64EncodedWireTransaction(compiledTx),
|
|
3582
|
+
gasPolicyId
|
|
3583
|
+
}) : getBase64EncodedWireTransaction(compiledTx);
|
|
3584
|
+
const signedTransaction = await signSolanaTransactionWithSession({
|
|
3585
|
+
authToken,
|
|
3586
|
+
session,
|
|
3587
|
+
transactionBase64: transactionToSign
|
|
3588
|
+
});
|
|
3589
|
+
const signature = await client.call("sendTransaction", [
|
|
3590
|
+
signedTransaction,
|
|
3591
|
+
{ encoding: "base64" }
|
|
3592
|
+
]);
|
|
3593
|
+
return { signature, fromAddress };
|
|
3594
|
+
}
|
|
3241
3595
|
async function waitForSolanaConfirmation(client, signature, timeoutMs = 6e4, pollIntervalMs = 2e3) {
|
|
3242
3596
|
const start = Date.now();
|
|
3243
3597
|
while (Date.now() - start < timeoutMs) {
|
|
@@ -3254,6 +3608,76 @@ async function waitForSolanaConfirmation(client, signature, timeoutMs = 6e4, pol
|
|
|
3254
3608
|
}
|
|
3255
3609
|
return false;
|
|
3256
3610
|
}
|
|
3611
|
+
async function sponsorSolanaTransaction(args) {
|
|
3612
|
+
if (!args.gasPolicyId) {
|
|
3613
|
+
throw errInvalidArgs("Fee sponsorship requires a fee policy ID.");
|
|
3614
|
+
}
|
|
3615
|
+
const feePayerResponse = await args.client.call("alchemy_requestFeePayer", [{
|
|
3616
|
+
policyId: args.gasPolicyId,
|
|
3617
|
+
serializedTransaction: args.compiledTransactionBase64
|
|
3618
|
+
}]);
|
|
3619
|
+
return feePayerResponse.serializedTransaction;
|
|
3620
|
+
}
|
|
3621
|
+
async function signSolanaTransactionWithSession(args) {
|
|
3622
|
+
const binding = getSolanaSessionBinding(args.session);
|
|
3623
|
+
if (args.session.capabilities?.["solana.signTransaction"] === false) {
|
|
3624
|
+
throw errInvalidArgs(
|
|
3625
|
+
"Delegated wallet session does not allow 'solana.signTransaction'. Reconnect the wallet session to refresh capabilities."
|
|
3626
|
+
);
|
|
3627
|
+
}
|
|
3628
|
+
const challenge = await createRemoteSolanaSignTransactionChallenge(args.authToken, {
|
|
3629
|
+
...binding,
|
|
3630
|
+
transaction: args.transactionBase64,
|
|
3631
|
+
encoding: "base64"
|
|
3632
|
+
});
|
|
3633
|
+
const completion = await completeRemoteSolanaSignTransactionChallenge(args.authToken, {
|
|
3634
|
+
challengeId: challenge.challengeId,
|
|
3635
|
+
signature: signChallengePayload({
|
|
3636
|
+
challengePayload: challenge.challenge,
|
|
3637
|
+
privateKeyPem: args.session.privateKeyPem
|
|
3638
|
+
})
|
|
3639
|
+
});
|
|
3640
|
+
return completion.signedTransaction;
|
|
3641
|
+
}
|
|
3642
|
+
function getSolanaSessionBinding(session) {
|
|
3643
|
+
const walletId = session.solanaWalletId ?? session.walletId;
|
|
3644
|
+
const walletAddress = getSolanaSessionAddress(session);
|
|
3645
|
+
if (!walletId) {
|
|
3646
|
+
throw errInvalidArgs(
|
|
3647
|
+
"Delegated wallet session is missing Solana wallet ID metadata. Run 'alchemy wallet connect --mode session --force'."
|
|
3648
|
+
);
|
|
3649
|
+
}
|
|
3650
|
+
if (!session.privyKeyQuorumId && !session.privySignerId) {
|
|
3651
|
+
throw errInvalidArgs(
|
|
3652
|
+
"Delegated wallet session is missing signer binding metadata. Run 'alchemy wallet connect --mode session --force'."
|
|
3653
|
+
);
|
|
3654
|
+
}
|
|
3655
|
+
return {
|
|
3656
|
+
sessionId: session.sessionId,
|
|
3657
|
+
walletId,
|
|
3658
|
+
walletAddress,
|
|
3659
|
+
privyKeyQuorumId: session.privyKeyQuorumId,
|
|
3660
|
+
privySignerId: session.privySignerId
|
|
3661
|
+
};
|
|
3662
|
+
}
|
|
3663
|
+
function getSolanaSessionAddress(session) {
|
|
3664
|
+
if (!session.solanaAddress) {
|
|
3665
|
+
throw errInvalidArgs(
|
|
3666
|
+
"Delegated wallet session is missing Solana address metadata. Run 'alchemy wallet connect --mode session --force'."
|
|
3667
|
+
);
|
|
3668
|
+
}
|
|
3669
|
+
return session.solanaAddress;
|
|
3670
|
+
}
|
|
3671
|
+
function signChallengePayload(args) {
|
|
3672
|
+
return signWithPrivateKey(
|
|
3673
|
+
"sha256",
|
|
3674
|
+
Buffer.from(args.challengePayload, "utf8"),
|
|
3675
|
+
{
|
|
3676
|
+
key: args.privateKeyPem,
|
|
3677
|
+
dsaEncoding: "der"
|
|
3678
|
+
}
|
|
3679
|
+
).toString("base64url");
|
|
3680
|
+
}
|
|
3257
3681
|
|
|
3258
3682
|
// src/lib/solana-fees.ts
|
|
3259
3683
|
async function resolveSolanaFeeSponsorship(program2) {
|
|
@@ -3287,23 +3711,54 @@ function parseDecimals(value) {
|
|
|
3287
3711
|
}
|
|
3288
3712
|
return decimals;
|
|
3289
3713
|
}
|
|
3290
|
-
async function
|
|
3714
|
+
async function resolveSolanaDelegateSigner(program2, signerOpt) {
|
|
3291
3715
|
const signer = parseSignerOpt(signerOpt);
|
|
3292
3716
|
if (signer === "session") {
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3717
|
+
return resolveSessionSolanaDelegateSigner();
|
|
3718
|
+
}
|
|
3719
|
+
if (signer === void 0 && resolveActiveSigner(program2) === "session") {
|
|
3720
|
+
return resolveSessionSolanaDelegateSigner();
|
|
3296
3721
|
}
|
|
3297
3722
|
const solanaKey = resolveSolanaWalletKey(program2);
|
|
3298
3723
|
if (!solanaKey) {
|
|
3724
|
+
if (signer === void 0) {
|
|
3725
|
+
const sessionSigner = tryResolveSessionSolanaDelegateSigner();
|
|
3726
|
+
if (sessionSigner) {
|
|
3727
|
+
return sessionSigner;
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3299
3730
|
throw errSolanaWalletKeyRequired();
|
|
3300
3731
|
}
|
|
3301
3732
|
const keyBytes = parseSolanaKeyBytes(solanaKey);
|
|
3302
3733
|
return {
|
|
3734
|
+
type: "local",
|
|
3303
3735
|
keyBytes,
|
|
3304
3736
|
signer: await createSolanaSignerFromKeyBytes(keyBytes)
|
|
3305
3737
|
};
|
|
3306
3738
|
}
|
|
3739
|
+
function resolveSessionSolanaDelegateSigner() {
|
|
3740
|
+
const sessionSigner = tryResolveSessionSolanaDelegateSigner();
|
|
3741
|
+
if (!sessionSigner) {
|
|
3742
|
+
throw errInvalidArgs(
|
|
3743
|
+
"No active Solana wallet session. Run `alchemy wallet connect --mode session` first."
|
|
3744
|
+
);
|
|
3745
|
+
}
|
|
3746
|
+
return sessionSigner;
|
|
3747
|
+
}
|
|
3748
|
+
function tryResolveSessionSolanaDelegateSigner() {
|
|
3749
|
+
const authToken = resolveAuthToken();
|
|
3750
|
+
const session = resolveWalletSession();
|
|
3751
|
+
const solanaSession = session ? getWalletSessionByChain(session, "solana") : null;
|
|
3752
|
+
if (!authToken || !solanaSession?.solanaAddress) {
|
|
3753
|
+
return void 0;
|
|
3754
|
+
}
|
|
3755
|
+
return {
|
|
3756
|
+
type: "session",
|
|
3757
|
+
address: solanaSession.solanaAddress,
|
|
3758
|
+
session: solanaSession,
|
|
3759
|
+
authToken
|
|
3760
|
+
};
|
|
3761
|
+
}
|
|
3307
3762
|
function registerSolanaDelegate(program2) {
|
|
3308
3763
|
const cmd = program2.command("delegate").description("Delegate Solana token authority");
|
|
3309
3764
|
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");
|
|
@@ -3337,7 +3792,7 @@ async function performSolanaDelegateApprove(program2, opts) {
|
|
|
3337
3792
|
validateSolanaAddress(opts.delegate);
|
|
3338
3793
|
const decimals = parseDecimals(opts.decimals);
|
|
3339
3794
|
const rawAmount = parseAmount(opts.amount, decimals);
|
|
3340
|
-
const
|
|
3795
|
+
const signer = await resolveSolanaDelegateSigner(program2, opts.signer);
|
|
3341
3796
|
const network = resolveSolanaNetwork(program2);
|
|
3342
3797
|
const { sponsored, feePolicyId } = await resolveSolanaFeeSponsorship(program2);
|
|
3343
3798
|
const client = clientFromFlags(program2, { forceNetwork: network });
|
|
@@ -3345,20 +3800,32 @@ async function performSolanaDelegateApprove(program2, opts) {
|
|
|
3345
3800
|
tokenAccount: solAddress(opts.tokenAccount),
|
|
3346
3801
|
mint: solAddress(opts.mint),
|
|
3347
3802
|
delegate: solAddress(opts.delegate),
|
|
3348
|
-
owner: signer,
|
|
3803
|
+
owner: { address: solAddress(signer.type === "session" ? signer.address : signer.signer.address) },
|
|
3349
3804
|
amount: rawAmount,
|
|
3350
3805
|
decimals
|
|
3351
3806
|
});
|
|
3352
3807
|
const result = await withSpinner(
|
|
3353
3808
|
"Approving delegate...",
|
|
3354
3809
|
"Delegate approved",
|
|
3355
|
-
() =>
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3810
|
+
async () => {
|
|
3811
|
+
if (signer.type === "session") {
|
|
3812
|
+
return await buildAndSendSolanaTransactionWithSession({
|
|
3813
|
+
client,
|
|
3814
|
+
instructions: [instruction],
|
|
3815
|
+
session: signer.session,
|
|
3816
|
+
authToken: signer.authToken,
|
|
3817
|
+
sponsored,
|
|
3818
|
+
gasPolicyId: feePolicyId
|
|
3819
|
+
});
|
|
3820
|
+
}
|
|
3821
|
+
return await buildAndSendSolanaTransaction({
|
|
3822
|
+
client,
|
|
3823
|
+
instructions: [instruction],
|
|
3824
|
+
senderKeyBytes: signer.keyBytes,
|
|
3825
|
+
sponsored,
|
|
3826
|
+
gasPolicyId: feePolicyId
|
|
3827
|
+
});
|
|
3828
|
+
}
|
|
3362
3829
|
);
|
|
3363
3830
|
const confirmed = await withSpinner(
|
|
3364
3831
|
"Waiting for confirmation...",
|
|
@@ -3399,24 +3866,36 @@ async function performSolanaDelegateApprove(program2, opts) {
|
|
|
3399
3866
|
}
|
|
3400
3867
|
async function performSolanaDelegateRevoke(program2, opts) {
|
|
3401
3868
|
validateSolanaAddress(opts.tokenAccount);
|
|
3402
|
-
const
|
|
3869
|
+
const signer = await resolveSolanaDelegateSigner(program2, opts.signer);
|
|
3403
3870
|
const network = resolveSolanaNetwork(program2);
|
|
3404
3871
|
const { sponsored, feePolicyId } = await resolveSolanaFeeSponsorship(program2);
|
|
3405
3872
|
const client = clientFromFlags(program2, { forceNetwork: network });
|
|
3406
3873
|
const instruction = buildSplTokenRevokeInstruction({
|
|
3407
3874
|
tokenAccount: solAddress(opts.tokenAccount),
|
|
3408
|
-
owner: signer
|
|
3875
|
+
owner: { address: solAddress(signer.type === "session" ? signer.address : signer.signer.address) }
|
|
3409
3876
|
});
|
|
3410
3877
|
const result = await withSpinner(
|
|
3411
3878
|
"Revoking delegate...",
|
|
3412
3879
|
"Delegate revoked",
|
|
3413
|
-
() =>
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3880
|
+
async () => {
|
|
3881
|
+
if (signer.type === "session") {
|
|
3882
|
+
return await buildAndSendSolanaTransactionWithSession({
|
|
3883
|
+
client,
|
|
3884
|
+
instructions: [instruction],
|
|
3885
|
+
session: signer.session,
|
|
3886
|
+
authToken: signer.authToken,
|
|
3887
|
+
sponsored,
|
|
3888
|
+
gasPolicyId: feePolicyId
|
|
3889
|
+
});
|
|
3890
|
+
}
|
|
3891
|
+
return await buildAndSendSolanaTransaction({
|
|
3892
|
+
client,
|
|
3893
|
+
instructions: [instruction],
|
|
3894
|
+
senderKeyBytes: signer.keyBytes,
|
|
3895
|
+
sponsored,
|
|
3896
|
+
gasPolicyId: feePolicyId
|
|
3897
|
+
});
|
|
3898
|
+
}
|
|
3420
3899
|
);
|
|
3421
3900
|
const confirmed = await withSpinner(
|
|
3422
3901
|
"Waiting for confirmation...",
|
|
@@ -3660,35 +4139,41 @@ async function performSolanaSend(program2, toArg, amountArg, tokenAddress, opts
|
|
|
3660
4139
|
if (tokenAddress) {
|
|
3661
4140
|
throw errInvalidArgs("SPL token transfers are not yet supported. Omit --token for native SOL transfers.");
|
|
3662
4141
|
}
|
|
3663
|
-
|
|
3664
|
-
throw errInvalidArgs(
|
|
3665
|
-
"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`."
|
|
3666
|
-
);
|
|
3667
|
-
}
|
|
3668
|
-
const solanaKey = resolveSolanaWalletKey(program2);
|
|
3669
|
-
if (!solanaKey) {
|
|
3670
|
-
throw errSolanaWalletKeyRequired();
|
|
3671
|
-
}
|
|
3672
|
-
const keyBytes = parseSolanaKeyBytes(solanaKey);
|
|
4142
|
+
const signer = await resolveSolanaSigner(program2, opts.signer);
|
|
3673
4143
|
validateSolanaAddress(toArg);
|
|
3674
4144
|
const to = solAddress2(toArg);
|
|
3675
4145
|
const network = resolveSolanaNetwork(program2);
|
|
3676
4146
|
const symbol = nativeTokenSymbol(network);
|
|
3677
4147
|
const lamports = parseAmount(amountArg, SOL_DECIMALS);
|
|
3678
|
-
const
|
|
3679
|
-
|
|
4148
|
+
const instruction = buildSolTransferInstruction(
|
|
4149
|
+
{ address: solAddress2(signer.address) },
|
|
4150
|
+
to,
|
|
4151
|
+
lamports
|
|
4152
|
+
);
|
|
3680
4153
|
const { sponsored, feePolicyId } = await resolveSolanaFeeSponsorship(program2);
|
|
3681
4154
|
const client = clientFromFlags(program2, { forceNetwork: network });
|
|
3682
4155
|
const result = await withSpinner(
|
|
3683
4156
|
"Sending transaction\u2026",
|
|
3684
4157
|
"Transaction submitted",
|
|
3685
|
-
() =>
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
4158
|
+
async () => {
|
|
4159
|
+
if (signer.type === "session") {
|
|
4160
|
+
return await buildAndSendSolanaTransactionWithSession({
|
|
4161
|
+
client,
|
|
4162
|
+
instructions: [instruction],
|
|
4163
|
+
session: signer.session,
|
|
4164
|
+
authToken: signer.authToken,
|
|
4165
|
+
sponsored,
|
|
4166
|
+
gasPolicyId: feePolicyId
|
|
4167
|
+
});
|
|
4168
|
+
}
|
|
4169
|
+
return await buildAndSendSolanaTransaction({
|
|
4170
|
+
client,
|
|
4171
|
+
instructions: [instruction],
|
|
4172
|
+
senderKeyBytes: signer.keyBytes,
|
|
4173
|
+
sponsored,
|
|
4174
|
+
gasPolicyId: feePolicyId
|
|
4175
|
+
});
|
|
4176
|
+
}
|
|
3692
4177
|
);
|
|
3693
4178
|
const confirmed = await withSpinner(
|
|
3694
4179
|
"Waiting for confirmation\u2026",
|
|
@@ -3721,6 +4206,61 @@ async function performSolanaSend(program2, toArg, amountArg, tokenAddress, opts
|
|
|
3721
4206
|
printKeyValue(pairs);
|
|
3722
4207
|
}
|
|
3723
4208
|
}
|
|
4209
|
+
async function resolveSolanaSigner(program2, signer) {
|
|
4210
|
+
if (signer === "session") {
|
|
4211
|
+
return resolveSessionSolanaSigner();
|
|
4212
|
+
}
|
|
4213
|
+
if (signer === void 0 && resolveActiveSigner(program2) === "session") {
|
|
4214
|
+
return resolveSessionSolanaSigner();
|
|
4215
|
+
}
|
|
4216
|
+
const solanaKey = resolveSolanaWalletKey(program2);
|
|
4217
|
+
if (!solanaKey) {
|
|
4218
|
+
if (signer === void 0) {
|
|
4219
|
+
const authToken = resolveAuthToken();
|
|
4220
|
+
const session = resolveWalletSession();
|
|
4221
|
+
const solanaSession = session ? getWalletSessionByChain(session, "solana") : null;
|
|
4222
|
+
if (authToken && solanaSession?.solanaAddress) {
|
|
4223
|
+
return {
|
|
4224
|
+
type: "session",
|
|
4225
|
+
address: solanaSession.solanaAddress,
|
|
4226
|
+
session: solanaSession,
|
|
4227
|
+
authToken
|
|
4228
|
+
};
|
|
4229
|
+
}
|
|
4230
|
+
}
|
|
4231
|
+
throw errSolanaWalletKeyRequired();
|
|
4232
|
+
}
|
|
4233
|
+
const keyBytes = parseSolanaKeyBytes(solanaKey);
|
|
4234
|
+
const localSigner = await createSolanaSignerFromKeyBytes(keyBytes);
|
|
4235
|
+
return {
|
|
4236
|
+
type: "local",
|
|
4237
|
+
address: localSigner.address,
|
|
4238
|
+
keyBytes
|
|
4239
|
+
};
|
|
4240
|
+
}
|
|
4241
|
+
function resolveSessionSolanaSigner() {
|
|
4242
|
+
const sessionSigner = tryResolveSessionSolanaSigner();
|
|
4243
|
+
if (!sessionSigner) {
|
|
4244
|
+
throw errInvalidArgs(
|
|
4245
|
+
"No active Solana wallet session. Run `alchemy wallet connect --mode session` first."
|
|
4246
|
+
);
|
|
4247
|
+
}
|
|
4248
|
+
return sessionSigner;
|
|
4249
|
+
}
|
|
4250
|
+
function tryResolveSessionSolanaSigner() {
|
|
4251
|
+
const authToken = resolveAuthToken();
|
|
4252
|
+
const session = resolveWalletSession();
|
|
4253
|
+
const solanaSession = session ? getWalletSessionByChain(session, "solana") : null;
|
|
4254
|
+
if (!authToken || !solanaSession?.solanaAddress) {
|
|
4255
|
+
return void 0;
|
|
4256
|
+
}
|
|
4257
|
+
return {
|
|
4258
|
+
type: "session",
|
|
4259
|
+
address: solanaSession.solanaAddress,
|
|
4260
|
+
session: solanaSession,
|
|
4261
|
+
authToken
|
|
4262
|
+
};
|
|
4263
|
+
}
|
|
3724
4264
|
|
|
3725
4265
|
// src/lib/smart-wallet.ts
|
|
3726
4266
|
import { createSmartWalletClient } from "@alchemy/wallet-apis";
|
|
@@ -3780,7 +4320,7 @@ function networkToChain(network) {
|
|
|
3780
4320
|
}
|
|
3781
4321
|
|
|
3782
4322
|
// src/lib/delegated-signer.ts
|
|
3783
|
-
import { sign as
|
|
4323
|
+
import { sign as signWithPrivateKey2 } from "crypto";
|
|
3784
4324
|
import { isAddressEqual, recoverMessageAddress, recoverTypedDataAddress } from "viem";
|
|
3785
4325
|
import { toAccount } from "viem/accounts";
|
|
3786
4326
|
var messageCapabilities = {
|
|
@@ -3794,8 +4334,8 @@ function toHex(bytes) {
|
|
|
3794
4334
|
function normalizeSignedChallengeSignature(signature) {
|
|
3795
4335
|
return signature.toString("base64url");
|
|
3796
4336
|
}
|
|
3797
|
-
function
|
|
3798
|
-
const signature =
|
|
4337
|
+
function signChallengePayload2(args) {
|
|
4338
|
+
const signature = signWithPrivateKey2(
|
|
3799
4339
|
"sha256",
|
|
3800
4340
|
Buffer.from(args.challengePayload, "utf8"),
|
|
3801
4341
|
{
|
|
@@ -3978,7 +4518,7 @@ function createDelegatedAccount(args) {
|
|
|
3978
4518
|
message: remoteMessage.message,
|
|
3979
4519
|
encoding: remoteMessage.encoding
|
|
3980
4520
|
});
|
|
3981
|
-
const signature =
|
|
4521
|
+
const signature = signChallengePayload2({
|
|
3982
4522
|
challengePayload: challenge.challenge,
|
|
3983
4523
|
privateKeyPem: args.session.privateKeyPem
|
|
3984
4524
|
});
|
|
@@ -4013,7 +4553,7 @@ function createDelegatedAccount(args) {
|
|
|
4013
4553
|
...sessionBinding,
|
|
4014
4554
|
typedData: serializedTypedData
|
|
4015
4555
|
});
|
|
4016
|
-
const signature =
|
|
4556
|
+
const signature = signChallengePayload2({
|
|
4017
4557
|
challengePayload: challenge.challenge,
|
|
4018
4558
|
privateKeyPem: args.session.privateKeyPem
|
|
4019
4559
|
});
|
|
@@ -4042,7 +4582,7 @@ function createDelegatedAccount(args) {
|
|
|
4042
4582
|
...sessionBinding,
|
|
4043
4583
|
authorization
|
|
4044
4584
|
});
|
|
4045
|
-
const signature =
|
|
4585
|
+
const signature = signChallengePayload2({
|
|
4046
4586
|
challengePayload: challenge.challenge,
|
|
4047
4587
|
privateKeyPem: args.session.privateKeyPem
|
|
4048
4588
|
});
|
|
@@ -4163,12 +4703,13 @@ function buildWalletClient(program2, options = {}) {
|
|
|
4163
4703
|
}
|
|
4164
4704
|
throw errNoActiveSession();
|
|
4165
4705
|
}
|
|
4166
|
-
|
|
4167
|
-
if (
|
|
4706
|
+
const evmSession = getWalletSessionByChain(validSession, "evm");
|
|
4707
|
+
if (!evmSession) {
|
|
4168
4708
|
throw errInvalidArgs(
|
|
4169
|
-
|
|
4709
|
+
"Wallet session is missing EVM metadata. Run 'alchemy wallet connect --mode session --force'."
|
|
4170
4710
|
);
|
|
4171
4711
|
}
|
|
4712
|
+
assertSessionMetadata(evmSession);
|
|
4172
4713
|
const authToken = resolveAuthToken(cfg);
|
|
4173
4714
|
if (!authToken) {
|
|
4174
4715
|
throw errAuthRequired();
|
|
@@ -4176,9 +4717,9 @@ function buildWalletClient(program2, options = {}) {
|
|
|
4176
4717
|
return {
|
|
4177
4718
|
signer: createDelegatedAccount({
|
|
4178
4719
|
authToken,
|
|
4179
|
-
session:
|
|
4720
|
+
session: evmSession
|
|
4180
4721
|
}),
|
|
4181
|
-
address:
|
|
4722
|
+
address: evmSession.evmAddress
|
|
4182
4723
|
};
|
|
4183
4724
|
}
|
|
4184
4725
|
if (!localKey) throw errWalletKeyRequired();
|
|
@@ -4917,7 +5458,7 @@ function buildAgentPrompt(program2) {
|
|
|
4917
5458
|
method: "Local wallet + API key",
|
|
4918
5459
|
envVar: "ALCHEMY_WALLET_KEY",
|
|
4919
5460
|
flag: "--wallet-key-file <path> | --signer local",
|
|
4920
|
-
setup: "alchemy wallet connect --mode local
|
|
5461
|
+
setup: "alchemy wallet connect --mode local",
|
|
4921
5462
|
commandFamilies: [
|
|
4922
5463
|
"evm send",
|
|
4923
5464
|
"evm contract call",
|
|
@@ -6828,7 +7369,7 @@ Examples:
|
|
|
6828
7369
|
dryRun: opts.dryRun
|
|
6829
7370
|
});
|
|
6830
7371
|
} catch (err) {
|
|
6831
|
-
const { exitWithError: exitWithError2 } = await import("./errors-
|
|
7372
|
+
const { exitWithError: exitWithError2 } = await import("./errors-T6XE2I2L.js");
|
|
6832
7373
|
exitWithError2(err);
|
|
6833
7374
|
}
|
|
6834
7375
|
});
|
|
@@ -8584,7 +9125,7 @@ async function flushProcessOutput() {
|
|
|
8584
9125
|
}
|
|
8585
9126
|
program.name("alchemy").description(
|
|
8586
9127
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
8587
|
-
).version("0.
|
|
9128
|
+
).version("0.9.1", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
|
|
8588
9129
|
"-n, --network <network>",
|
|
8589
9130
|
"Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
|
|
8590
9131
|
).option("--x402", "Use x402 wallet-based gateway auth").option(
|
|
@@ -8771,11 +9312,11 @@ ${styledLine}`;
|
|
|
8771
9312
|
"wallet"
|
|
8772
9313
|
];
|
|
8773
9314
|
if (!skipAppPrompt.includes(cmdName) && isInteractiveAllowed(program) && !opts.apiKey && !process.env.ALCHEMY_API_KEY) {
|
|
8774
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
9315
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-FQ66OWT7.js");
|
|
8775
9316
|
const authToken = resolveAuthToken2(cfg);
|
|
8776
9317
|
const hasApiKey = Boolean(cfg.api_key?.trim() || cfg.app?.apiKey);
|
|
8777
9318
|
if (authToken && !hasApiKey) {
|
|
8778
|
-
const { selectAppAfterAuth } = await import("./auth-
|
|
9319
|
+
const { selectAppAfterAuth } = await import("./auth-6BBITIOZ.js");
|
|
8779
9320
|
console.log("");
|
|
8780
9321
|
console.log(` No app selected. Please select an app to continue.`);
|
|
8781
9322
|
await selectAppAfterAuth(authToken);
|
|
@@ -8810,7 +9351,7 @@ ${styledLine}`;
|
|
|
8810
9351
|
if (isInteractiveAllowed(program)) {
|
|
8811
9352
|
let latestForInteractiveStartup = null;
|
|
8812
9353
|
if (shouldRunOnboarding(program, cfg)) {
|
|
8813
|
-
const { runOnboarding } = await import("./onboarding-
|
|
9354
|
+
const { runOnboarding } = await import("./onboarding-ZLBWCNTB.js");
|
|
8814
9355
|
const latest = getAvailableUpdateOnce();
|
|
8815
9356
|
const completed = await runOnboarding(program, latest);
|
|
8816
9357
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -8824,7 +9365,7 @@ ${styledLine}`;
|
|
|
8824
9365
|
latestForInteractiveStartup
|
|
8825
9366
|
);
|
|
8826
9367
|
}
|
|
8827
|
-
const { startREPL } = await import("./interactive-
|
|
9368
|
+
const { startREPL } = await import("./interactive-IFPSMRMX.js");
|
|
8828
9369
|
program.exitOverride();
|
|
8829
9370
|
program.configureOutput({
|
|
8830
9371
|
writeErr: () => {
|