@alchemy/cli 0.7.4-alpha.37 → 0.8.0
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-D6CT363I.js → auth-JPRZE2MA.js} +2 -2
- package/dist/auth-RINQSQDT.js +16 -0
- package/dist/{chunk-MYHXAACL.js → chunk-46LMXT54.js} +12 -4
- package/dist/chunk-5Y7UQ27V.js +186 -0
- package/dist/{chunk-6UHKZ5EN.js → chunk-76ZO4UJ4.js} +3 -3
- package/dist/{chunk-HR2UZ6ZU.js → chunk-DGZYRBXR.js} +1 -1
- package/dist/{chunk-2OUAYCVA.js → chunk-EKS2THJU.js} +6 -6
- package/dist/{chunk-UYZH6GSY.js → chunk-GNOTKJF4.js} +5 -5
- package/dist/{chunk-5HYOZ773.js → chunk-JWLZAO7S.js} +188 -130
- package/dist/{chunk-AUGBYMHT.js → chunk-L7VFXQSF.js} +1 -1
- package/dist/{chunk-WCZIVY4O.js → chunk-NGF46GZP.js} +1 -1
- package/dist/{chunk-PX2YJ7XC.js → chunk-ROBA7SR7.js} +1 -1
- package/dist/{errors-UL3W4ECQ.js → errors-A53DVJDY.js} +3 -1
- package/dist/index.js +525 -763
- package/dist/{interactive-Z2YHE6ME.js → interactive-6R3VKAPQ.js} +7 -7
- package/dist/{onboarding-Q5PBXH3M.js → onboarding-YHYXW4F3.js} +6 -6
- package/dist/policy-prompt-7AUZOA7S.js +18 -0
- package/dist/{resolve-PAQKIAX3.js → resolve-N3SX252M.js} +7 -3
- package/package.json +1 -1
- package/dist/auth-R5QHPFMA.js +0 -16
package/dist/index.js
CHANGED
|
@@ -1,28 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
|
+
import {
|
|
4
|
+
createPolicyInteractive,
|
|
5
|
+
errNotLoggedInForPolicyLookup,
|
|
6
|
+
errSponsorshipNeedsPolicy,
|
|
7
|
+
selectOrCreatePolicy
|
|
8
|
+
} from "./chunk-5Y7UQ27V.js";
|
|
3
9
|
import {
|
|
4
10
|
registerAuth
|
|
5
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-EKS2THJU.js";
|
|
6
12
|
import {
|
|
7
13
|
openBrowser
|
|
8
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-NGF46GZP.js";
|
|
9
15
|
import {
|
|
10
16
|
SETUP_CAPABILITY_LABELS,
|
|
11
17
|
SETUP_CAPABILITY_ORDER,
|
|
12
18
|
getSetupStatus,
|
|
13
19
|
isSetupComplete,
|
|
14
20
|
shouldRunOnboarding
|
|
15
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GNOTKJF4.js";
|
|
16
22
|
import {
|
|
17
23
|
isInteractiveAllowed
|
|
18
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-L7VFXQSF.js";
|
|
19
25
|
import {
|
|
20
26
|
adminClientFromFlags,
|
|
21
27
|
clearSession,
|
|
22
28
|
clientFromFlags,
|
|
23
29
|
createPendingSession,
|
|
30
|
+
fromAdminNetworkId,
|
|
31
|
+
gasManagerClientFromFlags,
|
|
24
32
|
getRPCNetworks,
|
|
25
|
-
|
|
33
|
+
hasAuthLoginToken,
|
|
26
34
|
isSessionValid,
|
|
27
35
|
isSolanaNetwork,
|
|
28
36
|
loadSession,
|
|
@@ -43,13 +51,14 @@ import {
|
|
|
43
51
|
resolveWalletSession,
|
|
44
52
|
resolveX402Client,
|
|
45
53
|
saveSession,
|
|
54
|
+
toAdminNetworkId,
|
|
46
55
|
updateSession
|
|
47
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-JWLZAO7S.js";
|
|
48
57
|
import {
|
|
49
58
|
getAvailableUpdate,
|
|
50
59
|
getUpdateStatus,
|
|
51
60
|
printUpdateNotice
|
|
52
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-76ZO4UJ4.js";
|
|
53
62
|
import {
|
|
54
63
|
bold,
|
|
55
64
|
brand,
|
|
@@ -73,7 +82,7 @@ import {
|
|
|
73
82
|
weiToEth,
|
|
74
83
|
withSpinner,
|
|
75
84
|
yellow
|
|
76
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-DGZYRBXR.js";
|
|
77
86
|
import {
|
|
78
87
|
KEY_MAP,
|
|
79
88
|
configDir,
|
|
@@ -84,7 +93,7 @@ import {
|
|
|
84
93
|
save,
|
|
85
94
|
toMap,
|
|
86
95
|
validKeys
|
|
87
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-ROBA7SR7.js";
|
|
88
97
|
import {
|
|
89
98
|
CLIError,
|
|
90
99
|
EXIT_CODES,
|
|
@@ -120,7 +129,7 @@ import {
|
|
|
120
129
|
setFlags,
|
|
121
130
|
setNoColor,
|
|
122
131
|
verbose
|
|
123
|
-
} from "./chunk-
|
|
132
|
+
} from "./chunk-46LMXT54.js";
|
|
124
133
|
|
|
125
134
|
// src/index.ts
|
|
126
135
|
import { Command, Help } from "commander";
|
|
@@ -553,12 +562,39 @@ function registerConfig(program2) {
|
|
|
553
562
|
exitWithError(err);
|
|
554
563
|
}
|
|
555
564
|
});
|
|
556
|
-
setCmd.command("evm-gas-policy-id
|
|
565
|
+
setCmd.command("evm-gas-policy-id [id]").description("Set the EVM gas policy ID for sponsored transactions (omit ID for interactive)").action(async (id) => {
|
|
557
566
|
try {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
567
|
+
if (id) {
|
|
568
|
+
const cfg = load();
|
|
569
|
+
save({ ...cfg, evm_gas_policy_id: id });
|
|
570
|
+
printHuman(`${green("\u2713")} Set evm-gas-policy-id
|
|
561
571
|
`, { key: "evm-gas-policy-id", status: "set" });
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
if (!isInteractiveAllowed(program2)) {
|
|
575
|
+
throw errInvalidArgs(
|
|
576
|
+
"Interactive policy selection requires an interactive terminal. Pass an ID: `alchemy config set evm-gas-policy-id <id>`."
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-7AUZOA7S.js");
|
|
580
|
+
const { resolveNetwork: resolveNetwork2 } = await import("./resolve-N3SX252M.js");
|
|
581
|
+
const network = resolveNetwork2(program2);
|
|
582
|
+
await selectOrCreatePolicy2({
|
|
583
|
+
flavor: "sponsorship",
|
|
584
|
+
network,
|
|
585
|
+
program: program2,
|
|
586
|
+
skipPersistPrompt: true
|
|
587
|
+
}).then((policyId) => {
|
|
588
|
+
if (!policyId) return;
|
|
589
|
+
const cfg = load();
|
|
590
|
+
save({ ...cfg, evm_gas_policy_id: policyId });
|
|
591
|
+
printHuman(`${green("\u2713")} Set evm-gas-policy-id
|
|
592
|
+
`, {
|
|
593
|
+
key: "evm-gas-policy-id",
|
|
594
|
+
value: policyId,
|
|
595
|
+
status: "set"
|
|
596
|
+
});
|
|
597
|
+
});
|
|
562
598
|
} catch (err) {
|
|
563
599
|
exitWithError(err);
|
|
564
600
|
}
|
|
@@ -581,12 +617,39 @@ function registerConfig(program2) {
|
|
|
581
617
|
exitWithError(err);
|
|
582
618
|
}
|
|
583
619
|
});
|
|
584
|
-
setCmd.command("solana-fee-policy-id
|
|
620
|
+
setCmd.command("solana-fee-policy-id [id]").description("Set the Solana fee policy ID for sponsored transactions (omit ID for interactive)").action(async (id) => {
|
|
585
621
|
try {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
622
|
+
if (id) {
|
|
623
|
+
const cfg = load();
|
|
624
|
+
save({ ...cfg, solana_fee_policy_id: id });
|
|
625
|
+
printHuman(`${green("\u2713")} Set solana-fee-policy-id
|
|
589
626
|
`, { key: "solana-fee-policy-id", status: "set" });
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
if (!isInteractiveAllowed(program2)) {
|
|
630
|
+
throw errInvalidArgs(
|
|
631
|
+
"Interactive policy selection requires an interactive terminal. Pass an ID: `alchemy config set solana-fee-policy-id <id>`."
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-7AUZOA7S.js");
|
|
635
|
+
const { resolveSolanaNetwork: resolveSolanaNetwork2 } = await import("./resolve-N3SX252M.js");
|
|
636
|
+
const network = resolveSolanaNetwork2(program2);
|
|
637
|
+
await selectOrCreatePolicy2({
|
|
638
|
+
flavor: "solana",
|
|
639
|
+
network,
|
|
640
|
+
program: program2,
|
|
641
|
+
skipPersistPrompt: true
|
|
642
|
+
}).then((policyId) => {
|
|
643
|
+
if (!policyId) return;
|
|
644
|
+
const cfg = load();
|
|
645
|
+
save({ ...cfg, solana_fee_policy_id: policyId });
|
|
646
|
+
printHuman(`${green("\u2713")} Set solana-fee-policy-id
|
|
647
|
+
`, {
|
|
648
|
+
key: "solana-fee-policy-id",
|
|
649
|
+
value: policyId,
|
|
650
|
+
status: "set"
|
|
651
|
+
});
|
|
652
|
+
});
|
|
590
653
|
} catch (err) {
|
|
591
654
|
exitWithError(err);
|
|
592
655
|
}
|
|
@@ -627,7 +690,7 @@ function registerConfig(program2) {
|
|
|
627
690
|
printJSON(toMap(cfg));
|
|
628
691
|
return;
|
|
629
692
|
}
|
|
630
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
693
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-N3SX252M.js");
|
|
631
694
|
const validToken = resolveAuthToken2(cfg);
|
|
632
695
|
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");
|
|
633
696
|
const pairs = [
|
|
@@ -1306,19 +1369,7 @@ var walletSessionCreateResponseSchema = z.object({
|
|
|
1306
1369
|
approvalUrl: z.string().url(),
|
|
1307
1370
|
expiresAt: z.string().datetime().optional()
|
|
1308
1371
|
}).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();
|
|
1320
1372
|
var rawWalletSessionStatusResponseSchema = z.object({
|
|
1321
|
-
type: z.literal("session").optional(),
|
|
1322
1373
|
sessionId: z.string().min(1).optional(),
|
|
1323
1374
|
status: rawWalletSessionStateSchema,
|
|
1324
1375
|
expiresAt: z.string().datetime().optional(),
|
|
@@ -1334,15 +1385,6 @@ var rawWalletSessionStatusResponseSchema = z.object({
|
|
|
1334
1385
|
chainType: z.string().min(1).optional(),
|
|
1335
1386
|
capabilities: z.record(z.string(), z.boolean()).optional()
|
|
1336
1387
|
}).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();
|
|
1346
1388
|
var walletSessionDisconnectResponseSchema = z.object({
|
|
1347
1389
|
sessionId: z.string().min(1).optional(),
|
|
1348
1390
|
status: rawWalletSessionStateSchema.optional().transform(
|
|
@@ -1369,14 +1411,9 @@ var rawEvmSigningChallengeResponseSchema = z.object({
|
|
|
1369
1411
|
challenge: z.string().min(1),
|
|
1370
1412
|
expiresAt: z.string().datetime(),
|
|
1371
1413
|
requestExpiry: z.string().min(1),
|
|
1372
|
-
method: z.enum([
|
|
1373
|
-
"personal_sign",
|
|
1374
|
-
"eth_signTypedData_v4",
|
|
1375
|
-
"eth_sign7702Authorization",
|
|
1376
|
-
"signTransaction"
|
|
1377
|
-
]),
|
|
1414
|
+
method: z.enum(["personal_sign", "eth_signTypedData_v4", "eth_sign7702Authorization"]),
|
|
1378
1415
|
walletId: z.string().min(1),
|
|
1379
|
-
walletAddress: z.string().
|
|
1416
|
+
walletAddress: z.string().regex(/^0x[a-fA-F0-9]{40}$/),
|
|
1380
1417
|
providerKeyQuorumId: z.string().min(1).optional(),
|
|
1381
1418
|
providerSignerId: z.string().min(1).optional()
|
|
1382
1419
|
}).strict();
|
|
@@ -1402,10 +1439,6 @@ var signAuthorizationCompleteResponseSchema = z.object({
|
|
|
1402
1439
|
y_parity: z.number().int()
|
|
1403
1440
|
}).strict()
|
|
1404
1441
|
}).strict();
|
|
1405
|
-
var solanaSignTransactionCompleteResponseSchema = z.object({
|
|
1406
|
-
signedTransaction: z.string().min(1),
|
|
1407
|
-
encoding: z.literal("base64")
|
|
1408
|
-
}).strict();
|
|
1409
1442
|
function baseURLOverride() {
|
|
1410
1443
|
const options = { allowedHostnames: [STAGING_ADMIN_API_HOST] };
|
|
1411
1444
|
return parseBaseURLOverride(WALLET_API_BASE_URL_ENV, options) ?? parseBaseURLOverride(ADMIN_API_BASE_URL_ENV, options);
|
|
@@ -1499,17 +1532,6 @@ function normalizeWalletSessionStatus(session) {
|
|
|
1499
1532
|
privySignerId: session.providerSignerId
|
|
1500
1533
|
};
|
|
1501
1534
|
}
|
|
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
|
-
}
|
|
1513
1535
|
function normalizeEvmSigningChallengeResponse(response) {
|
|
1514
1536
|
return {
|
|
1515
1537
|
...response,
|
|
@@ -1525,15 +1547,7 @@ function toProviderSigningBindingInput(input) {
|
|
|
1525
1547
|
...privySignerId ? { providerSignerId: privySignerId } : {}
|
|
1526
1548
|
};
|
|
1527
1549
|
}
|
|
1528
|
-
function
|
|
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) {
|
|
1550
|
+
async function createRemoteWalletSession(token, input) {
|
|
1537
1551
|
let data;
|
|
1538
1552
|
let requestInput = input;
|
|
1539
1553
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
@@ -1544,19 +1558,16 @@ async function createRemoteWalletSessionRequest(token, input) {
|
|
|
1544
1558
|
"/wallet/sessions",
|
|
1545
1559
|
requestInput
|
|
1546
1560
|
);
|
|
1547
|
-
return unwrapAdminData(
|
|
1561
|
+
return unwrapAdminData(walletSessionCreateResponseSchema, data);
|
|
1548
1562
|
} catch (err) {
|
|
1549
|
-
const retryInput = getClientInstanceCompatibilityRetryInput(
|
|
1550
|
-
requestInput,
|
|
1551
|
-
err
|
|
1552
|
-
);
|
|
1563
|
+
const retryInput = getClientInstanceCompatibilityRetryInput(requestInput, err);
|
|
1553
1564
|
if (retryInput === void 0) {
|
|
1554
1565
|
throw err;
|
|
1555
1566
|
}
|
|
1556
1567
|
requestInput = retryInput;
|
|
1557
1568
|
}
|
|
1558
1569
|
}
|
|
1559
|
-
throw new CLIError(ErrorCode.NETWORK_ERROR, "Unable to create wallet session
|
|
1570
|
+
throw new CLIError(ErrorCode.NETWORK_ERROR, "Unable to create wallet session.");
|
|
1560
1571
|
}
|
|
1561
1572
|
function getClientInstanceCompatibilityRetryInput(input, err) {
|
|
1562
1573
|
if (input.environment.clientInstanceName !== void 0 && isUnsupportedClientInstanceMetadataError(err, "clientInstanceName")) {
|
|
@@ -1591,16 +1602,6 @@ async function getRemoteWalletSession(token, sessionId) {
|
|
|
1591
1602
|
unwrapAdminData(rawWalletSessionStatusResponseSchema, data)
|
|
1592
1603
|
);
|
|
1593
1604
|
}
|
|
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
|
-
}
|
|
1604
1605
|
async function disconnectRemoteWalletSession(token, sessionId) {
|
|
1605
1606
|
try {
|
|
1606
1607
|
const data = await request(
|
|
@@ -1679,24 +1680,6 @@ var signAuthorizationChallengeInputSchema = evmSigningSessionBindingBaseSchema.e
|
|
|
1679
1680
|
executor: z.literal("self").optional()
|
|
1680
1681
|
}).strict()
|
|
1681
1682
|
}).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
|
-
});
|
|
1700
1683
|
async function createRemoteSignTypedDataChallenge(token, input) {
|
|
1701
1684
|
const parsedInput = signTypedDataChallengeInputSchema.parse(input);
|
|
1702
1685
|
return createEvmSigningChallenge(
|
|
@@ -1735,25 +1718,6 @@ async function completeRemoteSignAuthorizationChallenge(token, input) {
|
|
|
1735
1718
|
adminApiResponseSchema(signAuthorizationCompleteResponseSchema).transform((resp) => resp.data)
|
|
1736
1719
|
);
|
|
1737
1720
|
}
|
|
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
|
-
}
|
|
1757
1721
|
|
|
1758
1722
|
// src/commands/wallet.ts
|
|
1759
1723
|
import QRCode from "qrcode";
|
|
@@ -1764,9 +1728,6 @@ var DEFAULT_WALLET_CAPABILITIES = {
|
|
|
1764
1728
|
"evm.signTypedData": true,
|
|
1765
1729
|
"evm.signAuthorization": true
|
|
1766
1730
|
};
|
|
1767
|
-
var DEFAULT_SOLANA_SESSION_CAPABILITIES = {
|
|
1768
|
-
"solana.signTransaction": true
|
|
1769
|
-
};
|
|
1770
1731
|
function createEvmWallet() {
|
|
1771
1732
|
const privateKey = generatePrivateKey();
|
|
1772
1733
|
const account = privateKeyToAccount(privateKey);
|
|
@@ -1890,13 +1851,7 @@ async function withApprovalInterruptHandler(args) {
|
|
|
1890
1851
|
return await args.run(controller.signal);
|
|
1891
1852
|
} catch (err) {
|
|
1892
1853
|
if (isWalletConnectInterruptedError(err)) {
|
|
1893
|
-
await
|
|
1894
|
-
args.sessionIds.map(
|
|
1895
|
-
(sessionId) => disconnectRemoteWalletSession(args.authToken, sessionId).catch(
|
|
1896
|
-
() => void 0
|
|
1897
|
-
)
|
|
1898
|
-
)
|
|
1899
|
-
);
|
|
1854
|
+
await disconnectRemoteWalletSession(args.authToken, args.sessionId).catch(() => void 0);
|
|
1900
1855
|
clearSession();
|
|
1901
1856
|
}
|
|
1902
1857
|
throw err;
|
|
@@ -1907,9 +1862,23 @@ async function withApprovalInterruptHandler(args) {
|
|
|
1907
1862
|
}
|
|
1908
1863
|
}
|
|
1909
1864
|
}
|
|
1910
|
-
function
|
|
1865
|
+
function isFutureIsoDate(value) {
|
|
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) {
|
|
1911
1880
|
if (!session) return "none";
|
|
1912
|
-
if (
|
|
1881
|
+
if (isActiveWalletSession(session, remoteStatus)) return "active";
|
|
1913
1882
|
if (session.status === "pending") return "none";
|
|
1914
1883
|
return "expired";
|
|
1915
1884
|
}
|
|
@@ -2019,7 +1988,7 @@ function resolveQrAddress(args) {
|
|
|
2019
1988
|
function missingQrWalletError(type, source) {
|
|
2020
1989
|
if (source === "session") {
|
|
2021
1990
|
return type === "solana" ? errInvalidArgs(
|
|
2022
|
-
"
|
|
1991
|
+
"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`."
|
|
2023
1992
|
) : errNoActiveSession();
|
|
2024
1993
|
}
|
|
2025
1994
|
if (source === "local") {
|
|
@@ -2030,6 +1999,20 @@ function missingQrWalletError(type, source) {
|
|
|
2030
1999
|
function indentBlock(text, prefix = " ") {
|
|
2031
2000
|
return text.split("\n").map((line) => line ? `${prefix}${line}` : line).join("\n");
|
|
2032
2001
|
}
|
|
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
|
+
}
|
|
2033
2016
|
async function createAndPersistWallets() {
|
|
2034
2017
|
const evm = createEvmWallet();
|
|
2035
2018
|
const solana = await createSolanaWallet();
|
|
@@ -2094,12 +2077,14 @@ function getEffectiveLocalWalletState(program2, cfg) {
|
|
|
2094
2077
|
}
|
|
2095
2078
|
async function runLocalCreate(opts) {
|
|
2096
2079
|
const cfg = load();
|
|
2097
|
-
const
|
|
2098
|
-
const
|
|
2080
|
+
const wantsEvm = opts.chain === "evm" || opts.chain === "both";
|
|
2081
|
+
const wantsSolana = opts.chain === "solana" || opts.chain === "both";
|
|
2082
|
+
const evmConflict = wantsEvm && Boolean(cfg.wallet_key_file);
|
|
2083
|
+
const solanaConflict = wantsSolana && Boolean(cfg.solana_wallet_key_file);
|
|
2099
2084
|
if ((evmConflict || solanaConflict) && !opts.force) {
|
|
2100
2085
|
if (!isInteractiveAllowed(opts.program)) {
|
|
2101
2086
|
throw errInvalidArgs(
|
|
2102
|
-
"A local key is already configured. Re-run with --force to replace it."
|
|
2087
|
+
"A local key is already configured for the selected chain. Re-run with --force to replace it."
|
|
2103
2088
|
);
|
|
2104
2089
|
}
|
|
2105
2090
|
const kinds = [evmConflict ? "EVM" : null, solanaConflict ? "Solana" : null].filter(Boolean).join(" and ");
|
|
@@ -2112,7 +2097,16 @@ async function runLocalCreate(opts) {
|
|
|
2112
2097
|
throw errInvalidArgs("Aborted. Existing local key preserved.");
|
|
2113
2098
|
}
|
|
2114
2099
|
}
|
|
2115
|
-
|
|
2100
|
+
if (opts.chain === "both") {
|
|
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 };
|
|
2116
2110
|
}
|
|
2117
2111
|
function runLocalImport(opts) {
|
|
2118
2112
|
const cfg = load();
|
|
@@ -2145,27 +2139,7 @@ async function runLocalImportInteractive(opts) {
|
|
|
2145
2139
|
return runLocalImport({ ...opts, force: true });
|
|
2146
2140
|
}
|
|
2147
2141
|
}
|
|
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
|
-
}
|
|
2167
2142
|
async function runSessionConnect(opts) {
|
|
2168
|
-
const requestedChains = ["evm", "solana"];
|
|
2169
2143
|
const authToken = resolveAuthToken();
|
|
2170
2144
|
if (!authToken) throw errAuthRequired();
|
|
2171
2145
|
const existing = loadSession();
|
|
@@ -2203,51 +2177,32 @@ async function runSessionConnect(opts) {
|
|
|
2203
2177
|
...clientInstance.name === void 0 ? {} : { clientInstanceName: clientInstance.name }
|
|
2204
2178
|
};
|
|
2205
2179
|
updateSession({
|
|
2206
|
-
chainType: "
|
|
2207
|
-
capabilities:
|
|
2208
|
-
{},
|
|
2209
|
-
...requestedChains.map((chain) => capabilitiesForChain(chain))
|
|
2210
|
-
),
|
|
2180
|
+
chainType: "evm",
|
|
2181
|
+
capabilities: { ...DEFAULT_WALLET_CAPABILITIES },
|
|
2211
2182
|
backendBaseUrl: getWalletApiBaseUrl(),
|
|
2212
2183
|
environment: sessionEnvironment
|
|
2213
2184
|
});
|
|
2214
|
-
const
|
|
2185
|
+
const remoteSession = await createRemoteWalletSession(authToken, {
|
|
2215
2186
|
publicKeyJwk: session.publicKeyJwk,
|
|
2216
2187
|
requestSignerVersion: session.envelopeVersion,
|
|
2217
|
-
|
|
2218
|
-
capabilities:
|
|
2188
|
+
chainType: "evm",
|
|
2189
|
+
capabilities: { ...DEFAULT_WALLET_CAPABILITIES },
|
|
2219
2190
|
environment: sessionEnvironment
|
|
2220
2191
|
}).catch((err) => {
|
|
2221
2192
|
clearSession();
|
|
2222
2193
|
throw err;
|
|
2223
2194
|
});
|
|
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
|
-
);
|
|
2238
2195
|
updateSession({
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
expiresAt: remoteRequest.expiresAt ?? session.expiresAt,
|
|
2242
|
-
sessionsByChain: pendingSessionsByChain
|
|
2196
|
+
sessionId: remoteSession.sessionId,
|
|
2197
|
+
expiresAt: remoteSession.expiresAt ?? session.expiresAt
|
|
2243
2198
|
});
|
|
2244
2199
|
if (!isJSONMode()) {
|
|
2245
2200
|
const summaryPairs = [
|
|
2246
|
-
["
|
|
2201
|
+
["Session ID", remoteSession.sessionId],
|
|
2247
2202
|
["Status", "pending"],
|
|
2248
|
-
["Approval URL",
|
|
2203
|
+
["Approval URL", remoteSession.approvalUrl],
|
|
2249
2204
|
["Created", session.createdAt],
|
|
2250
|
-
["Expires",
|
|
2205
|
+
["Expires", remoteSession.expiresAt ?? session.expiresAt]
|
|
2251
2206
|
];
|
|
2252
2207
|
if (clientInstance.name !== void 0) {
|
|
2253
2208
|
summaryPairs.splice(1, 0, ["Instance", clientInstance.name]);
|
|
@@ -2262,14 +2217,7 @@ async function runSessionConnect(opts) {
|
|
|
2262
2217
|
});
|
|
2263
2218
|
if (answer === null) {
|
|
2264
2219
|
clearSession();
|
|
2265
|
-
await
|
|
2266
|
-
remoteRequest.sessions.map(
|
|
2267
|
-
(remoteSession) => disconnectRemoteWalletSession(
|
|
2268
|
-
authToken,
|
|
2269
|
-
remoteSession.walletSessionId
|
|
2270
|
-
).catch(() => void 0)
|
|
2271
|
-
)
|
|
2272
|
-
);
|
|
2220
|
+
await disconnectRemoteWalletSession(authToken, remoteSession.sessionId).catch(() => void 0);
|
|
2273
2221
|
throw new WalletConnectInterruptedError();
|
|
2274
2222
|
}
|
|
2275
2223
|
}
|
|
@@ -2277,41 +2225,25 @@ async function runSessionConnect(opts) {
|
|
|
2277
2225
|
console.log(` Opening browser for approval...`);
|
|
2278
2226
|
console.log(` ${dim("Waiting for dashboard approval to complete connection.")}`);
|
|
2279
2227
|
}
|
|
2280
|
-
openBrowser(
|
|
2281
|
-
const
|
|
2228
|
+
openBrowser(remoteSession.approvalUrl);
|
|
2229
|
+
const approvedSession = await withApprovalInterruptHandler({
|
|
2282
2230
|
authToken,
|
|
2283
|
-
|
|
2284
|
-
(remoteSession) => remoteSession.walletSessionId
|
|
2285
|
-
),
|
|
2231
|
+
sessionId: remoteSession.sessionId,
|
|
2286
2232
|
run: async (signal) => {
|
|
2287
2233
|
const startedAt = Date.now();
|
|
2288
2234
|
while (Date.now() - startedAt < CONNECT_TIMEOUT_MS) {
|
|
2289
|
-
const
|
|
2290
|
-
|
|
2291
|
-
authToken,
|
|
2292
|
-
remoteRequest.sessionId
|
|
2293
|
-
).then((request2) => request2.sessions) : Promise.all(
|
|
2294
|
-
remoteRequest.sessions.map(
|
|
2295
|
-
(remoteSession) => getRemoteWalletSession(authToken, remoteSession.walletSessionId)
|
|
2296
|
-
)
|
|
2297
|
-
),
|
|
2235
|
+
const current = await waitForInterruptible(
|
|
2236
|
+
getRemoteWalletSession(authToken, remoteSession.sessionId),
|
|
2298
2237
|
signal
|
|
2299
2238
|
);
|
|
2300
|
-
if (
|
|
2301
|
-
|
|
2302
|
-
return current.chainType === chain && current.status === "approved";
|
|
2303
|
-
})
|
|
2304
|
-
)) {
|
|
2305
|
-
return currentSessions;
|
|
2239
|
+
if (current.status === "approved") {
|
|
2240
|
+
return current;
|
|
2306
2241
|
}
|
|
2307
|
-
|
|
2308
|
-
return current.status === "denied" || current.status === "revoked" || current.status === "expired";
|
|
2309
|
-
});
|
|
2310
|
-
if (terminalSession) {
|
|
2242
|
+
if (current.status === "denied" || current.status === "revoked" || current.status === "expired") {
|
|
2311
2243
|
clearSession();
|
|
2312
2244
|
throw new CLIError(
|
|
2313
2245
|
ErrorCode.INTERNAL_ERROR,
|
|
2314
|
-
`Wallet session ${
|
|
2246
|
+
`Wallet session ${current.status}.`,
|
|
2315
2247
|
"Run 'alchemy wallet connect' to start a new approval flow."
|
|
2316
2248
|
);
|
|
2317
2249
|
}
|
|
@@ -2320,123 +2252,58 @@ async function runSessionConnect(opts) {
|
|
|
2320
2252
|
return null;
|
|
2321
2253
|
}
|
|
2322
2254
|
});
|
|
2323
|
-
if (!
|
|
2255
|
+
if (!approvedSession) {
|
|
2324
2256
|
throw new CLIError(
|
|
2325
2257
|
ErrorCode.NETWORK_ERROR,
|
|
2326
2258
|
"Timed out waiting for wallet approval.",
|
|
2327
2259
|
"Finish approval in the dashboard and rerun 'alchemy wallet connect --force' if needed."
|
|
2328
2260
|
);
|
|
2329
2261
|
}
|
|
2330
|
-
const
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
if (missingProviderAppId) {
|
|
2262
|
+
const walletId = approvedSession.walletId ?? approvedSession.evmWalletId;
|
|
2263
|
+
const evmAddress = approvedSession.evmAddress ?? approvedSession.address;
|
|
2264
|
+
if (!approvedSession.privyAppId || !walletId || !evmAddress) {
|
|
2334
2265
|
throw new CLIError(
|
|
2335
2266
|
ErrorCode.INTERNAL_ERROR,
|
|
2336
2267
|
"Approved wallet session response missing required metadata."
|
|
2337
2268
|
);
|
|
2338
2269
|
}
|
|
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;
|
|
2375
2270
|
updateSession({
|
|
2376
|
-
|
|
2377
|
-
sessionId: firstApprovedSession.sessionId ?? remoteRequest.sessions[0].walletSessionId,
|
|
2271
|
+
sessionId: approvedSession.sessionId ?? remoteSession.sessionId,
|
|
2378
2272
|
status: "approved",
|
|
2379
|
-
expiresAt:
|
|
2380
|
-
privyAppId:
|
|
2381
|
-
walletId
|
|
2382
|
-
evmWalletId:
|
|
2383
|
-
evmAddress
|
|
2384
|
-
solanaWalletId:
|
|
2385
|
-
solanaAddress:
|
|
2386
|
-
privyKeyQuorumId:
|
|
2387
|
-
privySignerId:
|
|
2388
|
-
chainType: "
|
|
2389
|
-
capabilities:
|
|
2390
|
-
{},
|
|
2391
|
-
...requestedChains.map((chain) => capabilitiesForChain(chain)),
|
|
2392
|
-
...approvedSessions.map((approvedSession) => approvedSession.capabilities ?? {})
|
|
2393
|
-
),
|
|
2394
|
-
sessionsByChain: approvedSessionsByChain,
|
|
2273
|
+
expiresAt: approvedSession.expiresAt ?? remoteSession.expiresAt ?? session.expiresAt,
|
|
2274
|
+
privyAppId: approvedSession.privyAppId,
|
|
2275
|
+
walletId,
|
|
2276
|
+
evmWalletId: approvedSession.evmWalletId ?? walletId,
|
|
2277
|
+
evmAddress,
|
|
2278
|
+
solanaWalletId: approvedSession.solanaWalletId,
|
|
2279
|
+
solanaAddress: approvedSession.solanaAddress,
|
|
2280
|
+
privyKeyQuorumId: approvedSession.privyKeyQuorumId,
|
|
2281
|
+
privySignerId: approvedSession.privySignerId,
|
|
2282
|
+
chainType: approvedSession.chainType ?? "evm",
|
|
2283
|
+
capabilities: approvedSession.capabilities ?? { ...DEFAULT_WALLET_CAPABILITIES },
|
|
2395
2284
|
backendBaseUrl: getWalletApiBaseUrl(),
|
|
2396
2285
|
environment: sessionEnvironment
|
|
2397
2286
|
});
|
|
2398
2287
|
if (isJSONMode()) {
|
|
2399
2288
|
printJSON({
|
|
2400
|
-
|
|
2401
|
-
sessionId: firstApprovedSession.sessionId ?? remoteRequest.sessions[0].walletSessionId,
|
|
2402
|
-
walletSessionId: firstApprovedSession.sessionId ?? remoteRequest.sessions[0].walletSessionId,
|
|
2289
|
+
sessionId: approvedSession.sessionId ?? remoteSession.sessionId,
|
|
2403
2290
|
status: "approved",
|
|
2404
|
-
privyAppId:
|
|
2405
|
-
walletId
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
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
|
|
2291
|
+
privyAppId: approvedSession.privyAppId,
|
|
2292
|
+
walletId,
|
|
2293
|
+
evmAddress,
|
|
2294
|
+
evmWalletId: approvedSession.evmWalletId ?? walletId,
|
|
2295
|
+
chainType: approvedSession.chainType ?? "evm",
|
|
2296
|
+
capabilities: approvedSession.capabilities ?? { ...DEFAULT_WALLET_CAPABILITIES },
|
|
2297
|
+
expiresAt: approvedSession.expiresAt ?? remoteSession.expiresAt ?? session.expiresAt
|
|
2421
2298
|
});
|
|
2422
2299
|
} else {
|
|
2423
|
-
|
|
2424
|
-
["
|
|
2425
|
-
["Status", green("approved")]
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
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
|
|
2300
|
+
printKeyValue([
|
|
2301
|
+
["Session ID", approvedSession.sessionId ?? remoteSession.sessionId],
|
|
2302
|
+
["Status", green("approved")],
|
|
2303
|
+
["Wallet ID", walletId],
|
|
2304
|
+
["EVM Address", green(evmAddress)],
|
|
2305
|
+
["Expires", approvedSession.expiresAt ?? remoteSession.expiresAt ?? session.expiresAt]
|
|
2438
2306
|
]);
|
|
2439
|
-
printKeyValue(pairs);
|
|
2440
2307
|
console.log(` ${green("\u2713")} Wallet connected`);
|
|
2441
2308
|
}
|
|
2442
2309
|
}
|
|
@@ -2505,6 +2372,17 @@ async function runConnectFlow(program2, opts) {
|
|
|
2505
2372
|
}
|
|
2506
2373
|
mode2 = "local";
|
|
2507
2374
|
}
|
|
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";
|
|
2508
2386
|
if (!mode2) {
|
|
2509
2387
|
if (!isInteractiveAllowed(program2)) {
|
|
2510
2388
|
throw errInvalidArgs(
|
|
@@ -2514,7 +2392,7 @@ async function runConnectFlow(program2, opts) {
|
|
|
2514
2392
|
const choice = await promptSelect({
|
|
2515
2393
|
message: "Choose a wallet to connect",
|
|
2516
2394
|
options: [
|
|
2517
|
-
{ value: "session", label: "Session wallet", hint: "Recommended \u2014 Alchemy-managed, more secure" },
|
|
2395
|
+
{ value: "session", label: "Session wallet", hint: "Recommended \u2014 Alchemy/Privy-managed, more secure" },
|
|
2518
2396
|
{ value: "local", label: "Local wallet", hint: "Private key stored on this machine" }
|
|
2519
2397
|
],
|
|
2520
2398
|
initialValue: "session",
|
|
@@ -2524,11 +2402,7 @@ async function runConnectFlow(program2, opts) {
|
|
|
2524
2402
|
mode2 = choice;
|
|
2525
2403
|
}
|
|
2526
2404
|
if (mode2 === "session") {
|
|
2527
|
-
await runSessionConnect({
|
|
2528
|
-
program: program2,
|
|
2529
|
-
force,
|
|
2530
|
-
instanceName: opts.instanceName
|
|
2531
|
-
});
|
|
2405
|
+
await runSessionConnect({ program: program2, force, instanceName: opts.instanceName });
|
|
2532
2406
|
printCrossModeHintAfterSessionConnect();
|
|
2533
2407
|
return;
|
|
2534
2408
|
}
|
|
@@ -2538,30 +2412,9 @@ async function runConnectFlow(program2, opts) {
|
|
|
2538
2412
|
printCrossModeHintAfterLocal("evm");
|
|
2539
2413
|
return;
|
|
2540
2414
|
}
|
|
2541
|
-
const result = await runLocalCreate({ force, program: program2 });
|
|
2415
|
+
const result = await runLocalCreate({ chain, force, program: program2 });
|
|
2542
2416
|
printPostLocalCreateSummary(result);
|
|
2543
|
-
printCrossModeHintAfterLocal(
|
|
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
|
-
);
|
|
2417
|
+
printCrossModeHintAfterLocal(chain);
|
|
2565
2418
|
}
|
|
2566
2419
|
async function buildSessionSnapshot(program2, verify) {
|
|
2567
2420
|
let session = loadStoredSession?.() ?? loadSession();
|
|
@@ -2569,55 +2422,25 @@ async function buildSessionSnapshot(program2, verify) {
|
|
|
2569
2422
|
if (verify && session) {
|
|
2570
2423
|
const authToken = resolveAuthToken();
|
|
2571
2424
|
if (!authToken) throw errAuthRequired();
|
|
2572
|
-
const
|
|
2573
|
-
uniqueSessionIds(session).map(
|
|
2574
|
-
(sessionId) => getRemoteWalletSession(authToken, sessionId)
|
|
2575
|
-
)
|
|
2576
|
-
);
|
|
2577
|
-
const remote = selectRemoteSessionForStatus(session, remoteSessions);
|
|
2425
|
+
const remote = await getRemoteWalletSession(authToken, session.sessionId);
|
|
2578
2426
|
remoteStatus = remote.status;
|
|
2579
|
-
const
|
|
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;
|
|
2427
|
+
const walletId2 = remote.walletId ?? remote.evmWalletId;
|
|
2604
2428
|
session = {
|
|
2605
2429
|
...session,
|
|
2606
2430
|
status: normalizeRemoteStatusForStorage(remote.status),
|
|
2607
2431
|
expiresAt: remote.expiresAt ?? session.expiresAt,
|
|
2608
2432
|
privyAppId: remote.privyAppId ?? session.privyAppId,
|
|
2609
|
-
walletId:
|
|
2610
|
-
evmWalletId,
|
|
2611
|
-
evmAddress,
|
|
2612
|
-
solanaWalletId,
|
|
2613
|
-
solanaAddress,
|
|
2614
|
-
chainType,
|
|
2615
|
-
capabilities:
|
|
2616
|
-
sessionsByChain: nextSessionsByChain
|
|
2433
|
+
walletId: walletId2 ?? session.walletId,
|
|
2434
|
+
evmWalletId: remote.evmWalletId ?? walletId2 ?? session.evmWalletId,
|
|
2435
|
+
evmAddress: remote.evmAddress ?? remote.address ?? session.evmAddress,
|
|
2436
|
+
solanaWalletId: remote.solanaWalletId ?? session.solanaWalletId,
|
|
2437
|
+
solanaAddress: remote.solanaAddress ?? session.solanaAddress,
|
|
2438
|
+
chainType: remote.chainType ?? session.chainType,
|
|
2439
|
+
capabilities: remote.capabilities ?? session.capabilities
|
|
2617
2440
|
};
|
|
2618
2441
|
saveSession(session);
|
|
2619
2442
|
}
|
|
2620
|
-
const status = deriveWalletStatus(session);
|
|
2443
|
+
const status = deriveWalletStatus(session, remoteStatus ?? void 0);
|
|
2621
2444
|
const walletAddress = resolveSessionAddress(session);
|
|
2622
2445
|
const environment = resolveSessionEnvironment(session);
|
|
2623
2446
|
const signerCapabilities = resolveEnabledCapabilities(session);
|
|
@@ -2633,16 +2456,14 @@ async function buildSessionSnapshot(program2, verify) {
|
|
|
2633
2456
|
walletId,
|
|
2634
2457
|
expiresAt,
|
|
2635
2458
|
sessionId: session?.sessionId ?? null,
|
|
2636
|
-
connectionRequestId: session?.connectionRequestId ?? null,
|
|
2637
2459
|
sessionState: session?.status ?? null,
|
|
2638
2460
|
chainType: session?.chainType ?? null,
|
|
2639
|
-
sessionsByChain: session?.sessionsByChain ?? null,
|
|
2640
2461
|
valid: session ? isSessionValid(session) : false
|
|
2641
2462
|
};
|
|
2642
2463
|
}
|
|
2643
2464
|
function registerWallets(program2) {
|
|
2644
2465
|
const cmd = program2.command("wallet").description("Manage wallets");
|
|
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
|
|
2466
|
+
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) => {
|
|
2646
2467
|
try {
|
|
2647
2468
|
await runConnectFlow(program2, opts);
|
|
2648
2469
|
} catch (err) {
|
|
@@ -2672,12 +2493,10 @@ function registerWallets(program2) {
|
|
|
2672
2493
|
expiresAt: snap.expiresAt,
|
|
2673
2494
|
environment: snap.environment,
|
|
2674
2495
|
signerCapabilities: snap.signerCapabilities,
|
|
2675
|
-
connectionRequestId: snap.connectionRequestId,
|
|
2676
2496
|
sessionId: snap.sessionId,
|
|
2677
2497
|
sessionState: snap.sessionState,
|
|
2678
2498
|
walletId: snap.walletId,
|
|
2679
2499
|
chainType: snap.chainType,
|
|
2680
|
-
sessionsByChain: snap.sessionsByChain,
|
|
2681
2500
|
verified: Boolean(opts.verify),
|
|
2682
2501
|
remoteStatus: snap.remoteStatus,
|
|
2683
2502
|
valid: snap.valid,
|
|
@@ -2688,12 +2507,10 @@ function registerWallets(program2) {
|
|
|
2688
2507
|
expiresAt: snap.expiresAt,
|
|
2689
2508
|
environment: snap.environment,
|
|
2690
2509
|
signerCapabilities: snap.signerCapabilities,
|
|
2691
|
-
connectionRequestId: snap.connectionRequestId,
|
|
2692
2510
|
sessionId: snap.sessionId,
|
|
2693
2511
|
sessionState: snap.sessionState,
|
|
2694
2512
|
walletId: snap.walletId,
|
|
2695
2513
|
chainType: snap.chainType,
|
|
2696
|
-
sessionsByChain: snap.sessionsByChain,
|
|
2697
2514
|
valid: snap.valid
|
|
2698
2515
|
},
|
|
2699
2516
|
localEvm: localState.evmAddress ? { address: localState.evmAddress, keyFile: localState.evmKeyFile } : null,
|
|
@@ -2711,11 +2528,7 @@ function registerWallets(program2) {
|
|
|
2711
2528
|
["Environment", snap.environment ?? dim("none")],
|
|
2712
2529
|
["Signer Capabilities", snap.signerCapabilities.length > 0 ? snap.signerCapabilities.join(", ") : dim("none")]
|
|
2713
2530
|
];
|
|
2714
|
-
if (snap.
|
|
2715
|
-
pairs.push(["Connection Request ID", snap.connectionRequestId]);
|
|
2716
|
-
} else if (snap.sessionId) {
|
|
2717
|
-
pairs.push(["Session ID", snap.sessionId]);
|
|
2718
|
-
}
|
|
2531
|
+
if (snap.sessionId) pairs.push(["Session ID", snap.sessionId]);
|
|
2719
2532
|
if (snap.walletId) pairs.push(["Wallet ID", snap.walletId]);
|
|
2720
2533
|
if (opts.verify) {
|
|
2721
2534
|
pairs.push(["Backend Status", snap.remoteStatus ?? dim("not checked")]);
|
|
@@ -2870,7 +2683,7 @@ function registerWallets(program2) {
|
|
|
2870
2683
|
}
|
|
2871
2684
|
if (target === "local" && !hasLocalEvmKey()) {
|
|
2872
2685
|
throw errInvalidArgs(
|
|
2873
|
-
"No local EVM key configured. Run `alchemy wallet connect --mode local` first."
|
|
2686
|
+
"No local EVM key configured. Run `alchemy wallet connect --mode local --chain evm` first."
|
|
2874
2687
|
);
|
|
2875
2688
|
}
|
|
2876
2689
|
const cfg = load();
|
|
@@ -2885,11 +2698,8 @@ function registerWallets(program2) {
|
|
|
2885
2698
|
exitWithError(err);
|
|
2886
2699
|
}
|
|
2887
2700
|
});
|
|
2888
|
-
cmd.command("disconnect").description("Revoke the current wallet session").
|
|
2701
|
+
cmd.command("disconnect").description("Revoke the current wallet session").action(async () => {
|
|
2889
2702
|
try {
|
|
2890
|
-
if (opts.chain !== void 0 && opts.chain !== "evm" && opts.chain !== "solana") {
|
|
2891
|
-
throw errInvalidArgs("`--chain` must be 'evm' or 'solana'.");
|
|
2892
|
-
}
|
|
2893
2703
|
const session = loadStoredSession?.() ?? loadSession();
|
|
2894
2704
|
if (!session) {
|
|
2895
2705
|
if (isJSONMode()) {
|
|
@@ -2907,40 +2717,15 @@ function registerWallets(program2) {
|
|
|
2907
2717
|
let revoked = false;
|
|
2908
2718
|
let alreadyDisconnected = false;
|
|
2909
2719
|
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];
|
|
2925
2720
|
if (authToken) {
|
|
2926
|
-
const
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
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;
|
|
2721
|
+
const remote = await disconnectRemoteWalletSession(authToken, session.sessionId);
|
|
2722
|
+
revoked = !remote.alreadyDisconnected;
|
|
2723
|
+
alreadyDisconnected = remote.alreadyDisconnected;
|
|
2724
|
+
remoteStatus = remote.status;
|
|
2725
|
+
}
|
|
2726
|
+
const removed = clearSession();
|
|
2942
2727
|
const cfg = load();
|
|
2943
|
-
if (cfg.active_signer === "session"
|
|
2728
|
+
if (cfg.active_signer === "session") {
|
|
2944
2729
|
const { active_signer: _omit, ...rest } = cfg;
|
|
2945
2730
|
save(rest);
|
|
2946
2731
|
}
|
|
@@ -3335,10 +3120,9 @@ import {
|
|
|
3335
3120
|
createKeyPairSignerFromBytes as createKeyPairSignerFromBytes2,
|
|
3336
3121
|
createKeyPairSignerFromPrivateKeyBytes as createKeyPairSignerFromPrivateKeyBytes2
|
|
3337
3122
|
} from "@solana/kit";
|
|
3338
|
-
import {
|
|
3123
|
+
import { getTransferSolInstruction } from "@solana-program/system";
|
|
3339
3124
|
var SOL_DECIMALS = 9;
|
|
3340
3125
|
var SPONSOR_FEE_PAYER_PLACEHOLDER = address("Amh6quo1FcmL16Qmzdugzjq3Lv1zXzTW7ktswyLDzits");
|
|
3341
|
-
var SYSTEM_PROGRAM_ADDRESS = address("11111111111111111111111111111111");
|
|
3342
3126
|
var SPL_TOKEN_PROGRAM_ADDRESS = address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
|
|
3343
3127
|
function parseSolanaKeyBytes(secret) {
|
|
3344
3128
|
const trimmed = secret.trim();
|
|
@@ -3369,28 +3153,11 @@ async function createSolanaSignerFromKeyBytes(keyBytes) {
|
|
|
3369
3153
|
throw errInvalidArgs("Invalid Solana key: expected 64-byte secret key or 32-byte private key.");
|
|
3370
3154
|
}
|
|
3371
3155
|
function buildSolTransferInstruction(from, to, lamports) {
|
|
3372
|
-
return {
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
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;
|
|
3156
|
+
return getTransferSolInstruction({
|
|
3157
|
+
source: from,
|
|
3158
|
+
destination: to,
|
|
3159
|
+
amount: lamports
|
|
3160
|
+
});
|
|
3394
3161
|
}
|
|
3395
3162
|
function encodeU64LE(value) {
|
|
3396
3163
|
if (value < 0n || value > 0xffffffffffffffffn) {
|
|
@@ -3471,38 +3238,6 @@ async function buildAndSendSolanaTransaction(opts) {
|
|
|
3471
3238
|
const signature = await client.call("sendTransaction", [wireTransaction, { encoding: "base64" }]);
|
|
3472
3239
|
return { signature, fromAddress: signer.address };
|
|
3473
3240
|
}
|
|
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
|
-
}
|
|
3506
3241
|
async function waitForSolanaConfirmation(client, signature, timeoutMs = 6e4, pollIntervalMs = 2e3) {
|
|
3507
3242
|
const start = Date.now();
|
|
3508
3243
|
while (Date.now() - start < timeoutMs) {
|
|
@@ -3519,87 +3254,29 @@ async function waitForSolanaConfirmation(client, signature, timeoutMs = 6e4, pol
|
|
|
3519
3254
|
}
|
|
3520
3255
|
return false;
|
|
3521
3256
|
}
|
|
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
|
-
}
|
|
3592
3257
|
|
|
3593
3258
|
// src/lib/solana-fees.ts
|
|
3594
|
-
function resolveSolanaFeeSponsorship(program2) {
|
|
3259
|
+
async function resolveSolanaFeeSponsorship(program2) {
|
|
3595
3260
|
const sponsored = resolveSolanaFeeSponsored(program2);
|
|
3596
|
-
const
|
|
3597
|
-
if (sponsored
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
);
|
|
3261
|
+
const existing = resolveSolanaFeePolicyId(program2);
|
|
3262
|
+
if (!sponsored) return { sponsored, feePolicyId: existing };
|
|
3263
|
+
if (existing) return { sponsored, feePolicyId: existing };
|
|
3264
|
+
if (!isInteractiveAllowed(program2)) {
|
|
3265
|
+
throw errSponsorshipNeedsPolicy("solana");
|
|
3266
|
+
}
|
|
3267
|
+
if (!hasAuthLoginToken()) {
|
|
3268
|
+
throw errNotLoggedInForPolicyLookup();
|
|
3601
3269
|
}
|
|
3602
|
-
|
|
3270
|
+
const network = resolveSolanaNetwork(program2);
|
|
3271
|
+
const selected = await selectOrCreatePolicy({
|
|
3272
|
+
flavor: "solana",
|
|
3273
|
+
network,
|
|
3274
|
+
program: program2
|
|
3275
|
+
});
|
|
3276
|
+
if (!selected) {
|
|
3277
|
+
throw errSponsorshipNeedsPolicy("solana");
|
|
3278
|
+
}
|
|
3279
|
+
return { sponsored, feePolicyId: selected };
|
|
3603
3280
|
}
|
|
3604
3281
|
|
|
3605
3282
|
// src/commands/solana-delegate.ts
|
|
@@ -3610,54 +3287,23 @@ function parseDecimals(value) {
|
|
|
3610
3287
|
}
|
|
3611
3288
|
return decimals;
|
|
3612
3289
|
}
|
|
3613
|
-
async function
|
|
3290
|
+
async function resolveLocalSolanaDelegateSigner(program2, signerOpt) {
|
|
3614
3291
|
const signer = parseSignerOpt(signerOpt);
|
|
3615
3292
|
if (signer === "session") {
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
return resolveSessionSolanaDelegateSigner();
|
|
3293
|
+
throw errInvalidArgs(
|
|
3294
|
+
"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`."
|
|
3295
|
+
);
|
|
3620
3296
|
}
|
|
3621
3297
|
const solanaKey = resolveSolanaWalletKey(program2);
|
|
3622
3298
|
if (!solanaKey) {
|
|
3623
|
-
if (signer === void 0) {
|
|
3624
|
-
const sessionSigner = tryResolveSessionSolanaDelegateSigner();
|
|
3625
|
-
if (sessionSigner) {
|
|
3626
|
-
return sessionSigner;
|
|
3627
|
-
}
|
|
3628
|
-
}
|
|
3629
3299
|
throw errSolanaWalletKeyRequired();
|
|
3630
3300
|
}
|
|
3631
3301
|
const keyBytes = parseSolanaKeyBytes(solanaKey);
|
|
3632
3302
|
return {
|
|
3633
|
-
type: "local",
|
|
3634
3303
|
keyBytes,
|
|
3635
3304
|
signer: await createSolanaSignerFromKeyBytes(keyBytes)
|
|
3636
3305
|
};
|
|
3637
3306
|
}
|
|
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
|
-
}
|
|
3661
3307
|
function registerSolanaDelegate(program2) {
|
|
3662
3308
|
const cmd = program2.command("delegate").description("Delegate Solana token authority");
|
|
3663
3309
|
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");
|
|
@@ -3691,40 +3337,28 @@ async function performSolanaDelegateApprove(program2, opts) {
|
|
|
3691
3337
|
validateSolanaAddress(opts.delegate);
|
|
3692
3338
|
const decimals = parseDecimals(opts.decimals);
|
|
3693
3339
|
const rawAmount = parseAmount(opts.amount, decimals);
|
|
3694
|
-
const signer = await
|
|
3340
|
+
const { keyBytes, signer } = await resolveLocalSolanaDelegateSigner(program2, opts.signer);
|
|
3695
3341
|
const network = resolveSolanaNetwork(program2);
|
|
3696
|
-
const { sponsored, feePolicyId } = resolveSolanaFeeSponsorship(program2);
|
|
3342
|
+
const { sponsored, feePolicyId } = await resolveSolanaFeeSponsorship(program2);
|
|
3697
3343
|
const client = clientFromFlags(program2, { forceNetwork: network });
|
|
3698
3344
|
const instruction = buildSplTokenApproveCheckedInstruction({
|
|
3699
3345
|
tokenAccount: solAddress(opts.tokenAccount),
|
|
3700
3346
|
mint: solAddress(opts.mint),
|
|
3701
3347
|
delegate: solAddress(opts.delegate),
|
|
3702
|
-
owner:
|
|
3348
|
+
owner: signer,
|
|
3703
3349
|
amount: rawAmount,
|
|
3704
3350
|
decimals
|
|
3705
3351
|
});
|
|
3706
3352
|
const result = await withSpinner(
|
|
3707
3353
|
"Approving delegate...",
|
|
3708
3354
|
"Delegate approved",
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
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
|
-
}
|
|
3355
|
+
() => buildAndSendSolanaTransaction({
|
|
3356
|
+
client,
|
|
3357
|
+
instructions: [instruction],
|
|
3358
|
+
senderKeyBytes: keyBytes,
|
|
3359
|
+
sponsored,
|
|
3360
|
+
gasPolicyId: feePolicyId
|
|
3361
|
+
})
|
|
3728
3362
|
);
|
|
3729
3363
|
const confirmed = await withSpinner(
|
|
3730
3364
|
"Waiting for confirmation...",
|
|
@@ -3765,36 +3399,24 @@ async function performSolanaDelegateApprove(program2, opts) {
|
|
|
3765
3399
|
}
|
|
3766
3400
|
async function performSolanaDelegateRevoke(program2, opts) {
|
|
3767
3401
|
validateSolanaAddress(opts.tokenAccount);
|
|
3768
|
-
const signer = await
|
|
3402
|
+
const { keyBytes, signer } = await resolveLocalSolanaDelegateSigner(program2, opts.signer);
|
|
3769
3403
|
const network = resolveSolanaNetwork(program2);
|
|
3770
|
-
const { sponsored, feePolicyId } = resolveSolanaFeeSponsorship(program2);
|
|
3404
|
+
const { sponsored, feePolicyId } = await resolveSolanaFeeSponsorship(program2);
|
|
3771
3405
|
const client = clientFromFlags(program2, { forceNetwork: network });
|
|
3772
3406
|
const instruction = buildSplTokenRevokeInstruction({
|
|
3773
3407
|
tokenAccount: solAddress(opts.tokenAccount),
|
|
3774
|
-
owner:
|
|
3408
|
+
owner: signer
|
|
3775
3409
|
});
|
|
3776
3410
|
const result = await withSpinner(
|
|
3777
3411
|
"Revoking delegate...",
|
|
3778
3412
|
"Delegate revoked",
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
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
|
-
}
|
|
3413
|
+
() => buildAndSendSolanaTransaction({
|
|
3414
|
+
client,
|
|
3415
|
+
instructions: [instruction],
|
|
3416
|
+
senderKeyBytes: keyBytes,
|
|
3417
|
+
sponsored,
|
|
3418
|
+
gasPolicyId: feePolicyId
|
|
3419
|
+
})
|
|
3798
3420
|
);
|
|
3799
3421
|
const confirmed = await withSpinner(
|
|
3800
3422
|
"Waiting for confirmation...",
|
|
@@ -4038,41 +3660,35 @@ async function performSolanaSend(program2, toArg, amountArg, tokenAddress, opts
|
|
|
4038
3660
|
if (tokenAddress) {
|
|
4039
3661
|
throw errInvalidArgs("SPL token transfers are not yet supported. Omit --token for native SOL transfers.");
|
|
4040
3662
|
}
|
|
4041
|
-
|
|
3663
|
+
if (opts.signer === "session") {
|
|
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);
|
|
4042
3673
|
validateSolanaAddress(toArg);
|
|
4043
3674
|
const to = solAddress2(toArg);
|
|
4044
3675
|
const network = resolveSolanaNetwork(program2);
|
|
4045
3676
|
const symbol = nativeTokenSymbol(network);
|
|
4046
3677
|
const lamports = parseAmount(amountArg, SOL_DECIMALS);
|
|
4047
|
-
const
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
lamports
|
|
4051
|
-
);
|
|
4052
|
-
const { sponsored, feePolicyId } = resolveSolanaFeeSponsorship(program2);
|
|
3678
|
+
const signer = await createSolanaSignerFromKeyBytes(keyBytes);
|
|
3679
|
+
const instruction = buildSolTransferInstruction(signer, to, lamports);
|
|
3680
|
+
const { sponsored, feePolicyId } = await resolveSolanaFeeSponsorship(program2);
|
|
4053
3681
|
const client = clientFromFlags(program2, { forceNetwork: network });
|
|
4054
3682
|
const result = await withSpinner(
|
|
4055
3683
|
"Sending transaction\u2026",
|
|
4056
3684
|
"Transaction submitted",
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
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
|
-
}
|
|
3685
|
+
() => buildAndSendSolanaTransaction({
|
|
3686
|
+
client,
|
|
3687
|
+
instructions: [instruction],
|
|
3688
|
+
senderKeyBytes: keyBytes,
|
|
3689
|
+
sponsored,
|
|
3690
|
+
gasPolicyId: feePolicyId
|
|
3691
|
+
})
|
|
4076
3692
|
);
|
|
4077
3693
|
const confirmed = await withSpinner(
|
|
4078
3694
|
"Waiting for confirmation\u2026",
|
|
@@ -4105,70 +3721,6 @@ async function performSolanaSend(program2, toArg, amountArg, tokenAddress, opts
|
|
|
4105
3721
|
printKeyValue(pairs);
|
|
4106
3722
|
}
|
|
4107
3723
|
}
|
|
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
|
-
}
|
|
4172
3724
|
|
|
4173
3725
|
// src/lib/smart-wallet.ts
|
|
4174
3726
|
import { createSmartWalletClient } from "@alchemy/wallet-apis";
|
|
@@ -4228,7 +3780,7 @@ function networkToChain(network) {
|
|
|
4228
3780
|
}
|
|
4229
3781
|
|
|
4230
3782
|
// src/lib/delegated-signer.ts
|
|
4231
|
-
import { sign as
|
|
3783
|
+
import { sign as signWithPrivateKey } from "crypto";
|
|
4232
3784
|
import { isAddressEqual, recoverMessageAddress, recoverTypedDataAddress } from "viem";
|
|
4233
3785
|
import { toAccount } from "viem/accounts";
|
|
4234
3786
|
var messageCapabilities = {
|
|
@@ -4242,8 +3794,8 @@ function toHex(bytes) {
|
|
|
4242
3794
|
function normalizeSignedChallengeSignature(signature) {
|
|
4243
3795
|
return signature.toString("base64url");
|
|
4244
3796
|
}
|
|
4245
|
-
function
|
|
4246
|
-
const signature =
|
|
3797
|
+
function signChallengePayload(args) {
|
|
3798
|
+
const signature = signWithPrivateKey(
|
|
4247
3799
|
"sha256",
|
|
4248
3800
|
Buffer.from(args.challengePayload, "utf8"),
|
|
4249
3801
|
{
|
|
@@ -4426,7 +3978,7 @@ function createDelegatedAccount(args) {
|
|
|
4426
3978
|
message: remoteMessage.message,
|
|
4427
3979
|
encoding: remoteMessage.encoding
|
|
4428
3980
|
});
|
|
4429
|
-
const signature =
|
|
3981
|
+
const signature = signChallengePayload({
|
|
4430
3982
|
challengePayload: challenge.challenge,
|
|
4431
3983
|
privateKeyPem: args.session.privateKeyPem
|
|
4432
3984
|
});
|
|
@@ -4461,7 +4013,7 @@ function createDelegatedAccount(args) {
|
|
|
4461
4013
|
...sessionBinding,
|
|
4462
4014
|
typedData: serializedTypedData
|
|
4463
4015
|
});
|
|
4464
|
-
const signature =
|
|
4016
|
+
const signature = signChallengePayload({
|
|
4465
4017
|
challengePayload: challenge.challenge,
|
|
4466
4018
|
privateKeyPem: args.session.privateKeyPem
|
|
4467
4019
|
});
|
|
@@ -4490,7 +4042,7 @@ function createDelegatedAccount(args) {
|
|
|
4490
4042
|
...sessionBinding,
|
|
4491
4043
|
authorization
|
|
4492
4044
|
});
|
|
4493
|
-
const signature =
|
|
4045
|
+
const signature = signChallengePayload({
|
|
4494
4046
|
challengePayload: challenge.challenge,
|
|
4495
4047
|
privateKeyPem: args.session.privateKeyPem
|
|
4496
4048
|
});
|
|
@@ -4522,6 +4074,28 @@ function createAlchemyWalletTransport(apiKey) {
|
|
|
4522
4074
|
}
|
|
4523
4075
|
|
|
4524
4076
|
// src/lib/smart-wallet.ts
|
|
4077
|
+
async function ensureGasPolicyResolved(program2) {
|
|
4078
|
+
const cfg = load();
|
|
4079
|
+
if (!resolveGasSponsored(program2, cfg)) return void 0;
|
|
4080
|
+
const existing = resolveGasPolicyId(program2, cfg);
|
|
4081
|
+
if (existing) return existing;
|
|
4082
|
+
if (!isInteractiveAllowed(program2)) {
|
|
4083
|
+
throw errSponsorshipNeedsPolicy("sponsorship");
|
|
4084
|
+
}
|
|
4085
|
+
if (!hasAuthLoginToken(cfg)) {
|
|
4086
|
+
throw errNotLoggedInForPolicyLookup();
|
|
4087
|
+
}
|
|
4088
|
+
const network = resolveNetwork(program2, cfg);
|
|
4089
|
+
const policyId = await selectOrCreatePolicy({
|
|
4090
|
+
flavor: "sponsorship",
|
|
4091
|
+
network,
|
|
4092
|
+
program: program2
|
|
4093
|
+
});
|
|
4094
|
+
if (!policyId) {
|
|
4095
|
+
throw errSponsorshipNeedsPolicy("sponsorship");
|
|
4096
|
+
}
|
|
4097
|
+
return policyId;
|
|
4098
|
+
}
|
|
4525
4099
|
function normalizeKey(key) {
|
|
4526
4100
|
const trimmed = key.trim();
|
|
4527
4101
|
return trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
@@ -4569,7 +4143,7 @@ function buildWalletClient(program2, options = {}) {
|
|
|
4569
4143
|
const network = resolveNetwork(program2, cfg);
|
|
4570
4144
|
const chain = networkToChain(network);
|
|
4571
4145
|
const gasSponsored = resolveGasSponsored(program2, cfg);
|
|
4572
|
-
const gasPolicyId = resolveGasPolicyId(program2, cfg);
|
|
4146
|
+
const gasPolicyId = options.gasPolicyIdOverride ?? resolveGasPolicyId(program2, cfg);
|
|
4573
4147
|
if (gasSponsored && !gasPolicyId) {
|
|
4574
4148
|
throw errInvalidArgs(
|
|
4575
4149
|
"Gas sponsorship requires a gas policy ID. Set one with --gas-policy-id or `alchemy config set evm-gas-policy-id <id>`."
|
|
@@ -4589,13 +4163,12 @@ function buildWalletClient(program2, options = {}) {
|
|
|
4589
4163
|
}
|
|
4590
4164
|
throw errNoActiveSession();
|
|
4591
4165
|
}
|
|
4592
|
-
|
|
4593
|
-
if (
|
|
4166
|
+
assertSessionMetadata(validSession);
|
|
4167
|
+
if (validSession.chainType && validSession.chainType !== "evm") {
|
|
4594
4168
|
throw errInvalidArgs(
|
|
4595
|
-
|
|
4169
|
+
`Wallet session is configured for '${validSession.chainType}', not EVM. Run 'alchemy wallet connect --force'.`
|
|
4596
4170
|
);
|
|
4597
4171
|
}
|
|
4598
|
-
assertSessionMetadata(evmSession);
|
|
4599
4172
|
const authToken = resolveAuthToken(cfg);
|
|
4600
4173
|
if (!authToken) {
|
|
4601
4174
|
throw errAuthRequired();
|
|
@@ -4603,9 +4176,9 @@ function buildWalletClient(program2, options = {}) {
|
|
|
4603
4176
|
return {
|
|
4604
4177
|
signer: createDelegatedAccount({
|
|
4605
4178
|
authToken,
|
|
4606
|
-
session:
|
|
4179
|
+
session: validSession
|
|
4607
4180
|
}),
|
|
4608
|
-
address:
|
|
4181
|
+
address: validSession.evmAddress
|
|
4609
4182
|
};
|
|
4610
4183
|
}
|
|
4611
4184
|
if (!localKey) throw errWalletKeyRequired();
|
|
@@ -5344,7 +4917,7 @@ function buildAgentPrompt(program2) {
|
|
|
5344
4917
|
method: "Local wallet + API key",
|
|
5345
4918
|
envVar: "ALCHEMY_WALLET_KEY",
|
|
5346
4919
|
flag: "--wallet-key-file <path> | --signer local",
|
|
5347
|
-
setup: "alchemy wallet connect --mode local",
|
|
4920
|
+
setup: "alchemy wallet connect --mode local --chain evm",
|
|
5348
4921
|
commandFamilies: [
|
|
5349
4922
|
"evm send",
|
|
5350
4923
|
"evm contract call",
|
|
@@ -5608,7 +5181,11 @@ async function performApprove(program2, spenderArg, opts) {
|
|
|
5608
5181
|
}
|
|
5609
5182
|
validateApprovalMode(opts);
|
|
5610
5183
|
const signer = parseSignerOpt(opts.signer);
|
|
5611
|
-
const
|
|
5184
|
+
const gasPolicyIdOverride = await ensureGasPolicyResolved(program2);
|
|
5185
|
+
const { client, network, address: from, paymaster } = buildWalletClient(program2, {
|
|
5186
|
+
signer,
|
|
5187
|
+
...gasPolicyIdOverride && { gasPolicyIdOverride }
|
|
5188
|
+
});
|
|
5612
5189
|
const rpcClient = clientFromFlags(program2);
|
|
5613
5190
|
const tokenMeta = await fetchTokenDecimals(program2, opts.tokenAddress);
|
|
5614
5191
|
const approval = buildApprovalRequest(opts, tokenMeta);
|
|
@@ -6084,7 +5661,11 @@ async function performContractCall(program2, addressArg, functionArg, opts) {
|
|
|
6084
5661
|
const { abi, functionName } = resolveAbi(functionArg, opts);
|
|
6085
5662
|
const args = parseArgs(opts.args);
|
|
6086
5663
|
const signer = parseSignerOpt(opts.signer);
|
|
6087
|
-
const
|
|
5664
|
+
const gasPolicyIdOverride = await ensureGasPolicyResolved(program2);
|
|
5665
|
+
const { client, network, address: from, paymaster } = buildWalletClient(program2, {
|
|
5666
|
+
signer,
|
|
5667
|
+
...gasPolicyIdOverride && { gasPolicyIdOverride }
|
|
5668
|
+
});
|
|
6088
5669
|
const rpcClient = clientFromFlags(program2);
|
|
6089
5670
|
const contractAddress = await resolveAddress(addressArg, rpcClient);
|
|
6090
5671
|
const data = encodeFunctionData2({ abi, functionName, args });
|
|
@@ -7247,7 +6828,7 @@ Examples:
|
|
|
7247
6828
|
dryRun: opts.dryRun
|
|
7248
6829
|
});
|
|
7249
6830
|
} catch (err) {
|
|
7250
|
-
const { exitWithError: exitWithError2 } = await import("./errors-
|
|
6831
|
+
const { exitWithError: exitWithError2 } = await import("./errors-A53DVJDY.js");
|
|
7251
6832
|
exitWithError2(err);
|
|
7252
6833
|
}
|
|
7253
6834
|
});
|
|
@@ -7256,7 +6837,11 @@ async function performEvmSend(program2, toArg, amountArg, tokenAddress, opts = {
|
|
|
7256
6837
|
if (tokenAddress) {
|
|
7257
6838
|
validateAddress(tokenAddress);
|
|
7258
6839
|
}
|
|
7259
|
-
const
|
|
6840
|
+
const gasPolicyIdOverride = await ensureGasPolicyResolved(program2);
|
|
6841
|
+
const { client, network, address: from, paymaster } = buildWalletClient(program2, {
|
|
6842
|
+
signer: opts.signer,
|
|
6843
|
+
...gasPolicyIdOverride && { gasPolicyIdOverride }
|
|
6844
|
+
});
|
|
7260
6845
|
const rpcClient = clientFromFlags(program2);
|
|
7261
6846
|
const to = await resolveAddress(toArg, rpcClient);
|
|
7262
6847
|
let decimals;
|
|
@@ -7680,7 +7265,11 @@ async function performSwapExecute(program2, opts) {
|
|
|
7680
7265
|
validateAddress(opts.from);
|
|
7681
7266
|
validateAddress(opts.to);
|
|
7682
7267
|
const signer = parseSignerOpt(opts.signer);
|
|
7683
|
-
const
|
|
7268
|
+
const gasPolicyIdOverride = await ensureGasPolicyResolved(program2);
|
|
7269
|
+
const { client, network, address: from, paymaster } = buildWalletClient(program2, {
|
|
7270
|
+
signer,
|
|
7271
|
+
...gasPolicyIdOverride && { gasPolicyIdOverride }
|
|
7272
|
+
});
|
|
7684
7273
|
const swapClient = client.extend(swapActions);
|
|
7685
7274
|
const fromInfo = await resolveTokenInfo(network, program2, opts.from);
|
|
7686
7275
|
const rawAmount = parseAmount(opts.amount, fromInfo.decimals);
|
|
@@ -7873,6 +7462,174 @@ function registerEvm(program2) {
|
|
|
7873
7462
|
registerSimulate(cmd);
|
|
7874
7463
|
}
|
|
7875
7464
|
|
|
7465
|
+
// src/commands/gas-manager.ts
|
|
7466
|
+
function summariseNetworks(p) {
|
|
7467
|
+
return p.networks.map(fromAdminNetworkId).join(", ");
|
|
7468
|
+
}
|
|
7469
|
+
function policyToRow(p) {
|
|
7470
|
+
return [
|
|
7471
|
+
p.policyId,
|
|
7472
|
+
p.policyName,
|
|
7473
|
+
p.policyType,
|
|
7474
|
+
p.status === "active" ? green(p.status) : dim(p.status),
|
|
7475
|
+
summariseNetworks(p) || dim("(none)")
|
|
7476
|
+
];
|
|
7477
|
+
}
|
|
7478
|
+
function policyToJSON(p) {
|
|
7479
|
+
return {
|
|
7480
|
+
policyId: p.policyId,
|
|
7481
|
+
policyName: p.policyName,
|
|
7482
|
+
policyType: p.policyType,
|
|
7483
|
+
status: p.status,
|
|
7484
|
+
appId: p.appId,
|
|
7485
|
+
networks: p.networks,
|
|
7486
|
+
networkSlugs: p.networks.map(fromAdminNetworkId),
|
|
7487
|
+
policyState: p.policyState ?? null,
|
|
7488
|
+
lastUpdatedUnix: p.lastUpdatedUnix ?? null,
|
|
7489
|
+
policyVersion: p.policyVersion ?? null
|
|
7490
|
+
};
|
|
7491
|
+
}
|
|
7492
|
+
function requireAppId(program2, opts) {
|
|
7493
|
+
if (opts.appId) return opts.appId;
|
|
7494
|
+
const resolved = resolveAppId(program2);
|
|
7495
|
+
if (!resolved) throw errAppRequired();
|
|
7496
|
+
return resolved;
|
|
7497
|
+
}
|
|
7498
|
+
function parseTypeFilter(value) {
|
|
7499
|
+
if (!value) return null;
|
|
7500
|
+
if (value === "sponsorship" || value === "erc20" || value === "solana") return value;
|
|
7501
|
+
throw errInvalidArgs(`Unknown --type ${value}. Expected one of: sponsorship, erc20, solana.`);
|
|
7502
|
+
}
|
|
7503
|
+
function parseStatusFilter(value) {
|
|
7504
|
+
if (!value) return null;
|
|
7505
|
+
if (value === "active" || value === "inactive") return value;
|
|
7506
|
+
throw errInvalidArgs(`Unknown --status ${value}. Expected one of: active, inactive.`);
|
|
7507
|
+
}
|
|
7508
|
+
function registerGasManager(program2) {
|
|
7509
|
+
const cmd = program2.command("gas-manager").description("Manage Alchemy Gas Manager policies");
|
|
7510
|
+
const policyCmd = cmd.command("policy").description("Manage gas sponsorship policies");
|
|
7511
|
+
policyCmd.command("list").description("List gas policies for the default app").option("--app-id <id>", "Override the default app ID").option("--type <type>", "Filter by policy type (sponsorship | erc20 | solana)").option("--network <slug>", "Filter by network slug (e.g. eth-mainnet)").option("--status <status>", "Filter by status (active | inactive)").action(async (opts) => {
|
|
7512
|
+
try {
|
|
7513
|
+
const client = gasManagerClientFromFlags(program2);
|
|
7514
|
+
const appId = requireAppId(program2, opts);
|
|
7515
|
+
const typeFilter = parseTypeFilter(opts.type);
|
|
7516
|
+
const statusFilter = parseStatusFilter(opts.status);
|
|
7517
|
+
const networkFilter = opts.network ? toAdminNetworkId(opts.network) : null;
|
|
7518
|
+
const policies = await withSpinner(
|
|
7519
|
+
"Fetching policies\u2026",
|
|
7520
|
+
"Policies fetched",
|
|
7521
|
+
() => client.listAllPolicies({ appId })
|
|
7522
|
+
);
|
|
7523
|
+
const filtered = policies.filter((p) => {
|
|
7524
|
+
if (typeFilter && p.policyType !== typeFilter) return false;
|
|
7525
|
+
if (statusFilter && p.status !== statusFilter) return false;
|
|
7526
|
+
if (networkFilter && !p.networks.includes(networkFilter)) return false;
|
|
7527
|
+
return true;
|
|
7528
|
+
});
|
|
7529
|
+
if (isJSONMode()) {
|
|
7530
|
+
printJSON({ appId, policies: filtered.map(policyToJSON) });
|
|
7531
|
+
return;
|
|
7532
|
+
}
|
|
7533
|
+
if (filtered.length === 0) {
|
|
7534
|
+
console.log(
|
|
7535
|
+
`
|
|
7536
|
+
${dim(`No policies for app ${appId}${networkFilter ? ` on ${opts.network}` : ""}.`)}`
|
|
7537
|
+
);
|
|
7538
|
+
console.log(
|
|
7539
|
+
` ${dim("Create one with: alchemy gas-manager policy create")}`
|
|
7540
|
+
);
|
|
7541
|
+
return;
|
|
7542
|
+
}
|
|
7543
|
+
printTable(
|
|
7544
|
+
["Policy ID", "Name", "Type", "Status", "Networks"],
|
|
7545
|
+
filtered.map(policyToRow)
|
|
7546
|
+
);
|
|
7547
|
+
console.log(`
|
|
7548
|
+
${dim(`${filtered.length} policies (app ${appId}).`)}`);
|
|
7549
|
+
} catch (err) {
|
|
7550
|
+
exitWithError(err);
|
|
7551
|
+
}
|
|
7552
|
+
});
|
|
7553
|
+
policyCmd.command("get <policy-id>").description("Show details for a single policy").action(async (policyId) => {
|
|
7554
|
+
try {
|
|
7555
|
+
const client = gasManagerClientFromFlags(program2);
|
|
7556
|
+
const policy = await withSpinner(
|
|
7557
|
+
"Fetching policy\u2026",
|
|
7558
|
+
"Policy fetched",
|
|
7559
|
+
() => client.getPolicy(policyId)
|
|
7560
|
+
);
|
|
7561
|
+
if (isJSONMode()) {
|
|
7562
|
+
printJSON(policyToJSON(policy));
|
|
7563
|
+
return;
|
|
7564
|
+
}
|
|
7565
|
+
printKeyValue([
|
|
7566
|
+
["Policy ID", policy.policyId],
|
|
7567
|
+
["Name", policy.policyName],
|
|
7568
|
+
["Type", policy.policyType],
|
|
7569
|
+
["Status", policy.status === "active" ? green("active") : dim(policy.status)],
|
|
7570
|
+
["App", policy.appId],
|
|
7571
|
+
["Networks", summariseNetworks(policy) || dim("(none)")],
|
|
7572
|
+
...policy.lastUpdatedUnix ? [["Updated", policy.lastUpdatedUnix]] : []
|
|
7573
|
+
]);
|
|
7574
|
+
} catch (err) {
|
|
7575
|
+
exitWithError(err);
|
|
7576
|
+
}
|
|
7577
|
+
});
|
|
7578
|
+
policyCmd.command("create").description("Create a new gas policy interactively").option("--type <type>", "Policy type (sponsorship | solana)", "sponsorship").action(async (opts) => {
|
|
7579
|
+
try {
|
|
7580
|
+
const type = parseTypeFilter(opts.type ?? "sponsorship");
|
|
7581
|
+
if (type === "erc20") {
|
|
7582
|
+
throw errInvalidArgs(
|
|
7583
|
+
"ERC-20 policies are not supported in `gas-manager policy create` yet. Create them in the Alchemy dashboard."
|
|
7584
|
+
);
|
|
7585
|
+
}
|
|
7586
|
+
if (!isInteractiveAllowed(program2)) {
|
|
7587
|
+
throw errInvalidArgs(
|
|
7588
|
+
"Policy creation requires an interactive terminal. Create policies in the Alchemy dashboard for non-interactive environments."
|
|
7589
|
+
);
|
|
7590
|
+
}
|
|
7591
|
+
const flavor = type === "solana" ? "solana" : "sponsorship";
|
|
7592
|
+
const network = flavor === "solana" ? resolveSolanaNetwork(program2) : resolveNetwork(program2);
|
|
7593
|
+
const result = await createPolicyInteractive({
|
|
7594
|
+
flavor,
|
|
7595
|
+
network,
|
|
7596
|
+
program: program2
|
|
7597
|
+
});
|
|
7598
|
+
if (!result) return;
|
|
7599
|
+
if (isJSONMode()) {
|
|
7600
|
+
printJSON({
|
|
7601
|
+
policyId: result.policyId,
|
|
7602
|
+
status: result.status,
|
|
7603
|
+
activated: result.activated
|
|
7604
|
+
});
|
|
7605
|
+
}
|
|
7606
|
+
} catch (err) {
|
|
7607
|
+
exitWithError(err);
|
|
7608
|
+
}
|
|
7609
|
+
});
|
|
7610
|
+
policyCmd.command("activate <policy-id>").description("Activate a policy so it can be used for sponsorship").action(async (policyId) => {
|
|
7611
|
+
try {
|
|
7612
|
+
const client = gasManagerClientFromFlags(program2);
|
|
7613
|
+
const policy = await withSpinner(
|
|
7614
|
+
"Activating policy\u2026",
|
|
7615
|
+
"Policy active",
|
|
7616
|
+
() => client.setPolicyStatus(policyId, "active")
|
|
7617
|
+
);
|
|
7618
|
+
if (isJSONMode()) {
|
|
7619
|
+
printJSON(policyToJSON(policy));
|
|
7620
|
+
return;
|
|
7621
|
+
}
|
|
7622
|
+
printKeyValue([
|
|
7623
|
+
["Policy ID", policy.policyId],
|
|
7624
|
+
["Name", policy.policyName],
|
|
7625
|
+
["Status", green(policy.status)]
|
|
7626
|
+
]);
|
|
7627
|
+
} catch (err) {
|
|
7628
|
+
exitWithError(err);
|
|
7629
|
+
}
|
|
7630
|
+
});
|
|
7631
|
+
}
|
|
7632
|
+
|
|
7876
7633
|
// src/commands/bridge.ts
|
|
7877
7634
|
import {
|
|
7878
7635
|
swapActions as swapActions2
|
|
@@ -8073,7 +7830,11 @@ async function performBridgeExecute(program2, opts) {
|
|
|
8073
7830
|
const toChainId = bridgeDestinationChainId(opts.toNetwork);
|
|
8074
7831
|
validateAddress(opts.to);
|
|
8075
7832
|
const signer = parseSignerOpt(opts.signer);
|
|
8076
|
-
const
|
|
7833
|
+
const gasPolicyIdOverride = await ensureGasPolicyResolved(program2);
|
|
7834
|
+
const { client, network, address: from, paymaster } = buildWalletClient(program2, {
|
|
7835
|
+
signer,
|
|
7836
|
+
...gasPolicyIdOverride && { gasPolicyIdOverride }
|
|
7837
|
+
});
|
|
8077
7838
|
validateBridgeNetworks(network, opts.toNetwork);
|
|
8078
7839
|
const swapClient = client.extend(swapActions2);
|
|
8079
7840
|
const fromInfo = await resolveTokenInfo2(network, program2, opts.from);
|
|
@@ -8823,7 +8584,7 @@ async function flushProcessOutput() {
|
|
|
8823
8584
|
}
|
|
8824
8585
|
program.name("alchemy").description(
|
|
8825
8586
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
8826
|
-
).version("0.
|
|
8587
|
+
).version("0.8.0", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
|
|
8827
8588
|
"-n, --network <network>",
|
|
8828
8589
|
"Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
|
|
8829
8590
|
).option("--x402", "Use x402 wallet-based gateway auth").option(
|
|
@@ -9010,11 +8771,11 @@ ${styledLine}`;
|
|
|
9010
8771
|
"wallet"
|
|
9011
8772
|
];
|
|
9012
8773
|
if (!skipAppPrompt.includes(cmdName) && isInteractiveAllowed(program) && !opts.apiKey && !process.env.ALCHEMY_API_KEY) {
|
|
9013
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
8774
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-N3SX252M.js");
|
|
9014
8775
|
const authToken = resolveAuthToken2(cfg);
|
|
9015
8776
|
const hasApiKey = Boolean(cfg.api_key?.trim() || cfg.app?.apiKey);
|
|
9016
8777
|
if (authToken && !hasApiKey) {
|
|
9017
|
-
const { selectAppAfterAuth } = await import("./auth-
|
|
8778
|
+
const { selectAppAfterAuth } = await import("./auth-RINQSQDT.js");
|
|
9018
8779
|
console.log("");
|
|
9019
8780
|
console.log(` No app selected. Please select an app to continue.`);
|
|
9020
8781
|
await selectAppAfterAuth(authToken);
|
|
@@ -9049,7 +8810,7 @@ ${styledLine}`;
|
|
|
9049
8810
|
if (isInteractiveAllowed(program)) {
|
|
9050
8811
|
let latestForInteractiveStartup = null;
|
|
9051
8812
|
if (shouldRunOnboarding(program, cfg)) {
|
|
9052
|
-
const { runOnboarding } = await import("./onboarding-
|
|
8813
|
+
const { runOnboarding } = await import("./onboarding-YHYXW4F3.js");
|
|
9053
8814
|
const latest = getAvailableUpdateOnce();
|
|
9054
8815
|
const completed = await runOnboarding(program, latest);
|
|
9055
8816
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -9063,7 +8824,7 @@ ${styledLine}`;
|
|
|
9063
8824
|
latestForInteractiveStartup
|
|
9064
8825
|
);
|
|
9065
8826
|
}
|
|
9066
|
-
const { startREPL } = await import("./interactive-
|
|
8827
|
+
const { startREPL } = await import("./interactive-6R3VKAPQ.js");
|
|
9067
8828
|
program.exitOverride();
|
|
9068
8829
|
program.configureOutput({
|
|
9069
8830
|
writeErr: () => {
|
|
@@ -9078,6 +8839,7 @@ registerEvm(program);
|
|
|
9078
8839
|
registerSolana(program);
|
|
9079
8840
|
registerXchain(program);
|
|
9080
8841
|
registerWallets(program);
|
|
8842
|
+
registerGasManager(program);
|
|
9081
8843
|
registerApps(program);
|
|
9082
8844
|
registerWebhooks(program);
|
|
9083
8845
|
registerAuth(program);
|