@alchemy/x402 0.3.0 → 0.4.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/README.md +12 -5
- package/dist/cli/index.mjs +6 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -1
package/README.md
CHANGED
|
@@ -14,20 +14,27 @@ pnpm add @alchemy/x402
|
|
|
14
14
|
# Generate a new wallet
|
|
15
15
|
npx @alchemy/x402 wallet generate
|
|
16
16
|
|
|
17
|
-
# Import an existing wallet (accepts key or file
|
|
18
|
-
npx @alchemy/x402 wallet import --private-key
|
|
17
|
+
# Import an existing wallet (accepts hex key or path to a key file)
|
|
18
|
+
npx @alchemy/x402 wallet import --private-key 0xac09...
|
|
19
|
+
npx @alchemy/x402 wallet import --private-key /path/to/keyfile
|
|
19
20
|
|
|
20
21
|
# Generate a SIWE token
|
|
21
|
-
npx @alchemy/x402 sign-siwe --private-key
|
|
22
|
+
npx @alchemy/x402 sign-siwe --private-key /path/to/keyfile --expires-after 1h
|
|
22
23
|
|
|
23
24
|
# Create an x402 payment from a PAYMENT-REQUIRED header
|
|
24
|
-
npx @alchemy/x402 pay --private-key
|
|
25
|
+
npx @alchemy/x402 pay --private-key /path/to/keyfile --payment-required <header>
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
## Library
|
|
28
29
|
|
|
29
30
|
```ts
|
|
30
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
signSiwe,
|
|
33
|
+
generateWallet,
|
|
34
|
+
getWalletAddress,
|
|
35
|
+
createPayment,
|
|
36
|
+
buildX402Client,
|
|
37
|
+
} from "@alchemy/x402";
|
|
31
38
|
```
|
|
32
39
|
|
|
33
40
|
### Generate a wallet
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "module";
|
|
2
3
|
import { Command } from "@commander-js/extra-typings";
|
|
3
4
|
import { randomBytes } from "crypto";
|
|
4
5
|
import ms from "ms";
|
|
@@ -63,7 +64,7 @@ async function signSiwe(opts) {
|
|
|
63
64
|
|
|
64
65
|
//#endregion
|
|
65
66
|
//#region src/cli/commands/sign-siwe.ts
|
|
66
|
-
const signSiweCommand = new Command("sign-siwe").description("Generate a SIWE authentication token").requiredOption("--private-key <key>", "Wallet private key").option("--expires-after <duration>", "Token expiration duration (e.g. 1h, 30m, 7d)", "1h").action(async (opts) => {
|
|
67
|
+
const signSiweCommand = new Command("sign-siwe").description("Generate a SIWE authentication token").requiredOption("--private-key <key-or-path>", "Wallet private key (hex string or path to a key file)").option("--expires-after <duration>", "Token expiration duration (e.g. 1h, 30m, 7d)", "1h").action(async (opts) => {
|
|
67
68
|
const token = await signSiwe({
|
|
68
69
|
privateKey: opts.privateKey,
|
|
69
70
|
expiresAfter: opts.expiresAfter
|
|
@@ -78,7 +79,7 @@ walletCommand.command("generate").description("Generate a new wallet").action(()
|
|
|
78
79
|
const wallet = generateWallet();
|
|
79
80
|
console.log(JSON.stringify(wallet, null, 2));
|
|
80
81
|
});
|
|
81
|
-
walletCommand.command("import").description("Import an existing wallet and display its address").requiredOption("--private-key <key>", "Wallet private key").action((opts) => {
|
|
82
|
+
walletCommand.command("import").description("Import an existing wallet and display its address").requiredOption("--private-key <key-or-path>", "Wallet private key (hex string or path to a key file)").action((opts) => {
|
|
82
83
|
const address = getWalletAddress(opts.privateKey);
|
|
83
84
|
console.log(JSON.stringify({ address }, null, 2));
|
|
84
85
|
});
|
|
@@ -113,7 +114,7 @@ async function createPayment(opts) {
|
|
|
113
114
|
|
|
114
115
|
//#endregion
|
|
115
116
|
//#region src/cli/commands/pay.ts
|
|
116
|
-
const payCommand = new Command("pay").description("Create an x402 payment from a PAYMENT-REQUIRED header").requiredOption("--private-key <key>", "Wallet private key").requiredOption("--payment-required <header>", "Raw PAYMENT-REQUIRED header value").action(async (opts) => {
|
|
117
|
+
const payCommand = new Command("pay").description("Create an x402 payment from a PAYMENT-REQUIRED header").requiredOption("--private-key <key-or-path>", "Wallet private key (hex string or path to a key file)").requiredOption("--payment-required <header>", "Raw PAYMENT-REQUIRED header value").action(async (opts) => {
|
|
117
118
|
const paymentHeader = await createPayment({
|
|
118
119
|
privateKey: opts.privateKey,
|
|
119
120
|
paymentRequiredHeader: opts.paymentRequired
|
|
@@ -123,7 +124,8 @@ const payCommand = new Command("pay").description("Create an x402 payment from a
|
|
|
123
124
|
|
|
124
125
|
//#endregion
|
|
125
126
|
//#region src/cli/index.ts
|
|
126
|
-
const
|
|
127
|
+
const { version } = createRequire(import.meta.url)("../../package.json");
|
|
128
|
+
const program = new Command().name("@alchemy/x402").description("CLI for Alchemy x402 authentication and payments").version(version);
|
|
127
129
|
program.addCommand(signSiweCommand);
|
|
128
130
|
program.addCommand(walletCommand);
|
|
129
131
|
program.addCommand(payCommand);
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/lib/siwe.ts","../src/lib/wallet.ts","../src/lib/payment.ts"],"mappings":";;;KAAY,GAAA;AAAA,UAEK,UAAA;EACf,UAAA,EAAY,GAAA;EACZ,OAAA,EAAS,GAAA;AAAA;AAAA,UAGM,eAAA;EACf,UAAA;EACA,YAAA;EACA,KAAA;EACA,QAAA;AAAA;AAAA,UAGe,oBAAA;EACf,UAAA;EACA,qBAAA;AAAA;;;iBCNoB,QAAA,CAAS,IAAA,EAAM,eAAA,GAAkB,OAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/lib/siwe.ts","../src/lib/wallet.ts","../src/lib/payment.ts"],"mappings":";;;KAAY,GAAA;AAAA,UAEK,UAAA;EACf,UAAA,EAAY,GAAA;EACZ,OAAA,EAAS,GAAA;AAAA;AAAA,UAGM,eAAA;EACf,UAAA;EACA,YAAA;EACA,KAAA;EACA,QAAA;AAAA;AAAA,UAGe,oBAAA;EACf,UAAA;EACA,qBAAA;AAAA;;;iBCNoB,QAAA,CAAS,IAAA,EAAM,eAAA,GAAkB,OAAA;;;iBCavC,cAAA,CAAA,GAAkB,UAAA;AAAA,iBAMlB,gBAAA,CAAiB,UAAA,WAAqB,GAAA;;;iBCjBtC,eAAA,CAAgB,UAAA,WAAkB,UAAA;AAAA,iBA8B5B,aAAA,CACpB,IAAA,EAAM,oBAAA,GACL,OAAA"}
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/lib/siwe.ts","../src/lib/wallet.ts","../src/lib/payment.ts"],"mappings":";;;KAAY,GAAA;AAAA,UAEK,UAAA;EACf,UAAA,EAAY,GAAA;EACZ,OAAA,EAAS,GAAA;AAAA;AAAA,UAGM,eAAA;EACf,UAAA;EACA,YAAA;EACA,KAAA;EACA,QAAA;AAAA;AAAA,UAGe,oBAAA;EACf,UAAA;EACA,qBAAA;AAAA;;;iBCNoB,QAAA,CAAS,IAAA,EAAM,eAAA,GAAkB,OAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/lib/siwe.ts","../src/lib/wallet.ts","../src/lib/payment.ts"],"mappings":";;;KAAY,GAAA;AAAA,UAEK,UAAA;EACf,UAAA,EAAY,GAAA;EACZ,OAAA,EAAS,GAAA;AAAA;AAAA,UAGM,eAAA;EACf,UAAA;EACA,YAAA;EACA,KAAA;EACA,QAAA;AAAA;AAAA,UAGe,oBAAA;EACf,UAAA;EACA,qBAAA;AAAA;;;iBCNoB,QAAA,CAAS,IAAA,EAAM,eAAA,GAAkB,OAAA;;;iBCavC,cAAA,CAAA,GAAkB,UAAA;AAAA,iBAMlB,gBAAA,CAAiB,UAAA,WAAqB,GAAA;;;iBCjBtC,eAAA,CAAgB,UAAA,WAAkB,UAAA;AAAA,iBA8B5B,aAAA,CACpB,IAAA,EAAM,oBAAA,GACL,OAAA"}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/lib/wallet.ts","../src/lib/siwe.ts","../src/lib/payment.ts"],"sourcesContent":["import { readFileSync, existsSync } from \"fs\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { Hex, WalletInfo } from \"../types.js\";\n\nconst RAW_HEX_RE = /^[0-9a-fA-F]{64}$/;\n\nexport function resolvePrivateKey(keyOrPath: string): string {\n if (keyOrPath.startsWith(\"0x\") || RAW_HEX_RE.test(keyOrPath)) {\n return keyOrPath;\n }\n if (existsSync(keyOrPath)) {\n return readFileSync(keyOrPath, \"utf-8\").trim();\n }\n return keyOrPath;\n}\n\nexport function normalizePrivateKey(key: string): Hex {\n const resolved = resolvePrivateKey(key);\n return resolved.startsWith(\"0x\")
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/lib/wallet.ts","../src/lib/siwe.ts","../src/lib/payment.ts"],"sourcesContent":["import { readFileSync, existsSync } from \"fs\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { Hex, WalletInfo } from \"../types.js\";\n\nconst RAW_HEX_RE = /^[0-9a-fA-F]{64}$/;\n\nexport function resolvePrivateKey(keyOrPath: string): string {\n if (keyOrPath.startsWith(\"0x\") || RAW_HEX_RE.test(keyOrPath)) {\n return keyOrPath;\n }\n if (existsSync(keyOrPath)) {\n return readFileSync(keyOrPath, \"utf-8\").trim();\n }\n return keyOrPath;\n}\n\nexport function normalizePrivateKey(key: string): Hex {\n const resolved = resolvePrivateKey(key);\n return resolved.startsWith(\"0x\")\n ? (resolved as Hex)\n : (`0x${resolved}` as Hex);\n}\n\nexport function generateWallet(): WalletInfo {\n const privateKey = generatePrivateKey();\n const account = privateKeyToAccount(privateKey);\n return { privateKey, address: account.address };\n}\n\nexport function getWalletAddress(privateKey: string): Hex {\n const normalized = normalizePrivateKey(privateKey);\n const account = privateKeyToAccount(normalized);\n return account.address;\n}\n","import { randomBytes } from \"crypto\";\nimport ms from \"ms\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport type { SignSiweOptions } from \"../types.js\";\nimport { normalizePrivateKey } from \"./wallet.js\";\n\nfunction generateNonce(): string {\n return randomBytes(16).toString(\"hex\");\n}\n\nexport async function signSiwe(opts: SignSiweOptions): Promise<string> {\n const normalized = normalizePrivateKey(opts.privateKey);\n const account = privateKeyToAccount(normalized);\n\n const issuedAt = opts.issuedAt ?? new Date().toISOString();\n const nonce = opts.nonce ?? generateNonce();\n\n const duration = ms((opts.expiresAfter ?? \"1h\") as Parameters<typeof ms>[0]);\n if (duration === undefined) {\n throw new Error(`Invalid duration: ${opts.expiresAfter}`);\n }\n const expirationTime = new Date(\n new Date(issuedAt).getTime() + duration,\n ).toISOString();\n\n const message = [\n \"x402.alchemy.com wants you to sign in with your Ethereum account:\",\n account.address,\n \"\",\n \"Sign in to Alchemy Gateway\",\n \"\",\n \"URI: https://x402.alchemy.com\",\n \"Version: 1\",\n \"Chain ID: 8453\",\n `Nonce: ${nonce}`,\n `Issued At: ${issuedAt}`,\n `Expiration Time: ${expirationTime}`,\n ].join(\"\\n\");\n\n const signature = await account.signMessage({ message });\n\n const encodedMessage = Buffer.from(message).toString(\"base64url\");\n return `${encodedMessage}.${signature}`;\n}\n","import { createPublicClient, http } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { ExactEvmScheme, toClientEvmSigner } from \"@x402/evm\";\nimport { x402Client } from \"@x402/core/client\";\nimport {\n decodePaymentRequiredHeader,\n encodePaymentSignatureHeader,\n} from \"@x402/core/http\";\nimport type { CreatePaymentOptions } from \"../types.js\";\nimport { normalizePrivateKey } from \"./wallet.js\";\n\nexport function buildX402Client(privateKey: string) {\n const normalized = normalizePrivateKey(privateKey);\n const account = privateKeyToAccount(normalized);\n\n const publicClient = createPublicClient({\n chain: base,\n transport: http(),\n });\n\n const signer = toClientEvmSigner({\n address: account.address,\n signTypedData: async (params) => {\n return account.signTypedData(\n params as Parameters<typeof account.signTypedData>[0],\n );\n },\n readContract: async (params) => {\n return publicClient.readContract(\n params as Parameters<typeof publicClient.readContract>[0],\n );\n },\n });\n\n const scheme = new ExactEvmScheme(signer);\n const client = new x402Client();\n client.register(\"eip155:8453\", scheme);\n client.register(\"eip155:84532\", scheme);\n return client;\n}\n\nexport async function createPayment(\n opts: CreatePaymentOptions,\n): Promise<string> {\n const client = buildX402Client(opts.privateKey);\n const paymentRequired = decodePaymentRequiredHeader(\n opts.paymentRequiredHeader,\n );\n const payload = await client.createPaymentPayload(paymentRequired);\n return encodePaymentSignatureHeader(payload);\n}\n"],"mappings":";;;;;;;;;;;AAIA,MAAM,aAAa;AAEnB,SAAgB,kBAAkB,WAA2B;AAC3D,KAAI,UAAU,WAAW,KAAK,IAAI,WAAW,KAAK,UAAU,CAC1D,QAAO;AAET,KAAI,WAAW,UAAU,CACvB,QAAO,aAAa,WAAW,QAAQ,CAAC,MAAM;AAEhD,QAAO;;AAGT,SAAgB,oBAAoB,KAAkB;CACpD,MAAM,WAAW,kBAAkB,IAAI;AACvC,QAAO,SAAS,WAAW,KAAK,GAC3B,WACA,KAAK;;AAGZ,SAAgB,iBAA6B;CAC3C,MAAM,aAAa,oBAAoB;AAEvC,QAAO;EAAE;EAAY,SADL,oBAAoB,WAAW,CACT;EAAS;;AAGjD,SAAgB,iBAAiB,YAAyB;AAGxD,QADgB,oBADG,oBAAoB,WAAW,CACH,CAChC;;;;;AC1BjB,SAAS,gBAAwB;AAC/B,QAAO,YAAY,GAAG,CAAC,SAAS,MAAM;;AAGxC,eAAsB,SAAS,MAAwC;CAErE,MAAM,UAAU,oBADG,oBAAoB,KAAK,WAAW,CACR;CAE/C,MAAM,WAAW,KAAK,6BAAY,IAAI,MAAM,EAAC,aAAa;CAC1D,MAAM,QAAQ,KAAK,SAAS,eAAe;CAE3C,MAAM,WAAW,GAAI,KAAK,gBAAgB,KAAkC;AAC5E,KAAI,aAAa,OACf,OAAM,IAAI,MAAM,qBAAqB,KAAK,eAAe;CAE3D,MAAM,iBAAiB,IAAI,KACzB,IAAI,KAAK,SAAS,CAAC,SAAS,GAAG,SAChC,CAAC,aAAa;CAEf,MAAM,UAAU;EACd;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA;EACA;EACA,UAAU;EACV,cAAc;EACd,oBAAoB;EACrB,CAAC,KAAK,KAAK;CAEZ,MAAM,YAAY,MAAM,QAAQ,YAAY,EAAE,SAAS,CAAC;AAGxD,QAAO,GADgB,OAAO,KAAK,QAAQ,CAAC,SAAS,YAAY,CACxC,GAAG;;;;;AC9B9B,SAAgB,gBAAgB,YAAoB;CAElD,MAAM,UAAU,oBADG,oBAAoB,WAAW,CACH;CAE/C,MAAM,eAAe,mBAAmB;EACtC,OAAO;EACP,WAAW,MAAM;EAClB,CAAC;CAgBF,MAAM,SAAS,IAAI,eAdJ,kBAAkB;EAC/B,SAAS,QAAQ;EACjB,eAAe,OAAO,WAAW;AAC/B,UAAO,QAAQ,cACb,OACD;;EAEH,cAAc,OAAO,WAAW;AAC9B,UAAO,aAAa,aAClB,OACD;;EAEJ,CAAC,CAEuC;CACzC,MAAM,SAAS,IAAI,YAAY;AAC/B,QAAO,SAAS,eAAe,OAAO;AACtC,QAAO,SAAS,gBAAgB,OAAO;AACvC,QAAO;;AAGT,eAAsB,cACpB,MACiB;CACjB,MAAM,SAAS,gBAAgB,KAAK,WAAW;CAC/C,MAAM,kBAAkB,4BACtB,KAAK,sBACN;AAED,QAAO,6BADS,MAAM,OAAO,qBAAqB,gBAAgB,CACtB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alchemy/x402",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "CLI and library for Alchemy x402 authentication and payments",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"bin": {
|
|
19
19
|
"alchemy-x402": "./dist/cli/index.mjs"
|
|
20
20
|
},
|
|
21
|
+
"lint-staged": {
|
|
22
|
+
"*.{js,ts,mjs,mts,cjs,cts}": "eslint --fix",
|
|
23
|
+
"*.{json,md,yml,yaml}": "prettier --write"
|
|
24
|
+
},
|
|
21
25
|
"dependencies": {
|
|
22
26
|
"@commander-js/extra-typings": "^14.0.0",
|
|
23
27
|
"@x402/core": "^2.4.0",
|
|
@@ -30,10 +34,17 @@
|
|
|
30
34
|
"devDependencies": {
|
|
31
35
|
"@changesets/changelog-github": "^0.5.2",
|
|
32
36
|
"@changesets/cli": "^2.29.8",
|
|
37
|
+
"@eslint/js": "^10.0.1",
|
|
33
38
|
"@types/ms": "^2.1.0",
|
|
34
39
|
"@types/node": "^25.3.0",
|
|
40
|
+
"eslint": "^10.0.2",
|
|
41
|
+
"eslint-config-prettier": "^10.1.8",
|
|
42
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
43
|
+
"lint-staged": "^16.2.7",
|
|
44
|
+
"prettier": "^3.8.1",
|
|
35
45
|
"tsdown": "^0.20.3",
|
|
36
46
|
"typescript": "^5.9.3",
|
|
47
|
+
"typescript-eslint": "^8.56.1",
|
|
37
48
|
"vitest": "^4.0.18"
|
|
38
49
|
},
|
|
39
50
|
"files": [
|
|
@@ -50,6 +61,8 @@
|
|
|
50
61
|
"build": "tsdown",
|
|
51
62
|
"typecheck": "tsc --noEmit",
|
|
52
63
|
"test": "vitest run",
|
|
64
|
+
"lint": "eslint . && prettier --check .",
|
|
65
|
+
"lint:fix": "eslint . --fix && prettier --write .",
|
|
53
66
|
"changeset": "changeset",
|
|
54
67
|
"version-packages": "changeset version",
|
|
55
68
|
"release": "pnpm run build && changeset publish"
|