crumb-alpha-cli 0.1.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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +38 -0
- package/dist/commands/balance.d.ts +2 -0
- package/dist/commands/balance.d.ts.map +1 -0
- package/dist/commands/balance.js +43 -0
- package/dist/commands/balance.js.map +1 -0
- package/dist/commands/deposit.d.ts +2 -0
- package/dist/commands/deposit.d.ts.map +1 -0
- package/dist/commands/deposit.js +52 -0
- package/dist/commands/deposit.js.map +1 -0
- package/dist/commands/history.d.ts +4 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +10 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +76 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/pay.d.ts +4 -0
- package/dist/commands/pay.d.ts.map +1 -0
- package/dist/commands/pay.js +50 -0
- package/dist/commands/pay.js.map +1 -0
- package/dist/commands/serve.d.ts +5 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +43 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/wallet.d.ts +4 -0
- package/dist/commands/wallet.d.ts.map +1 -0
- package/dist/commands/wallet.js +69 -0
- package/dist/commands/wallet.js.map +1 -0
- package/dist/commands/withdraw.d.ts +4 -0
- package/dist/commands/withdraw.d.ts.map +1 -0
- package/dist/commands/withdraw.js +54 -0
- package/dist/commands/withdraw.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +30 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/keystore.d.ts +5 -0
- package/dist/utils/keystore.d.ts.map +1 -0
- package/dist/utils/keystore.js +51 -0
- package/dist/utils/keystore.js.map +1 -0
- package/dist/utils/output.d.ts +8 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +35 -0
- package/dist/utils/output.js.map +1 -0
- package/package.json +39 -0
- package/src/commands/balance.ts +48 -0
- package/src/commands/deposit.ts +57 -0
- package/src/commands/history.ts +11 -0
- package/src/commands/init.ts +86 -0
- package/src/commands/pay.ts +55 -0
- package/src/commands/serve.ts +58 -0
- package/src/commands/wallet.ts +81 -0
- package/src/commands/withdraw.ts +62 -0
- package/src/index.ts +83 -0
- package/src/utils/config.ts +41 -0
- package/src/utils/keystore.ts +65 -0
- package/src/utils/output.ts +40 -0
- package/test/config.test.ts +109 -0
- package/test/keystore.test.ts +118 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CrumbConfig {
|
|
2
|
+
activeWallet?: string;
|
|
3
|
+
chain: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function ensureCrumbDir(): void;
|
|
6
|
+
export declare function getCrumbDir(): string;
|
|
7
|
+
export declare function getConfigPath(): string;
|
|
8
|
+
export declare function readConfig(): CrumbConfig;
|
|
9
|
+
export declare function writeConfig(config: CrumbConfig): void;
|
|
10
|
+
export declare function configExists(): boolean;
|
|
11
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,cAAc,IAAI,IAAI,CAIrC;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,UAAU,IAAI,WAAW,CAKxC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAGrD;AAED,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const CRUMB_DIR = join(homedir(), '.crumb');
|
|
5
|
+
const CONFIG_PATH = join(CRUMB_DIR, 'config.json');
|
|
6
|
+
export function ensureCrumbDir() {
|
|
7
|
+
if (!existsSync(CRUMB_DIR)) {
|
|
8
|
+
mkdirSync(CRUMB_DIR, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function getCrumbDir() {
|
|
12
|
+
return CRUMB_DIR;
|
|
13
|
+
}
|
|
14
|
+
export function getConfigPath() {
|
|
15
|
+
return CONFIG_PATH;
|
|
16
|
+
}
|
|
17
|
+
export function readConfig() {
|
|
18
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
19
|
+
return { chain: 'arcTestnet' };
|
|
20
|
+
}
|
|
21
|
+
return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
|
|
22
|
+
}
|
|
23
|
+
export function writeConfig(config) {
|
|
24
|
+
ensureCrumbDir();
|
|
25
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
26
|
+
}
|
|
27
|
+
export function configExists() {
|
|
28
|
+
return existsSync(CONFIG_PATH);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAA;AAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;AAOlD,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAA;IAChC,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAmB;IAC7C,cAAc,EAAE,CAAA;IAChB,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AAC7D,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,UAAU,CAAC,WAAW,CAAC,CAAA;AAChC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function keystoreExists(): boolean;
|
|
2
|
+
export declare function encryptAndSave(privateKey: string, password: string): void;
|
|
3
|
+
export declare function loadPrivateKey(password: string): string;
|
|
4
|
+
export declare function getPassword(): string;
|
|
5
|
+
//# sourceMappingURL=keystore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keystore.d.ts","sourceRoot":"","sources":["../../src/utils/keystore.ts"],"names":[],"mappings":"AAWA,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAoBzE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAmBvD;AAED,wBAAgB,WAAW,IAAI,MAAM,CAMpC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'node:crypto';
|
|
4
|
+
import { getCrumbDir, ensureCrumbDir } from './config.js';
|
|
5
|
+
const KEYSTORE_FILE = 'keystore.enc';
|
|
6
|
+
function getKeystorePath() {
|
|
7
|
+
return join(getCrumbDir(), KEYSTORE_FILE);
|
|
8
|
+
}
|
|
9
|
+
export function keystoreExists() {
|
|
10
|
+
return existsSync(getKeystorePath());
|
|
11
|
+
}
|
|
12
|
+
export function encryptAndSave(privateKey, password) {
|
|
13
|
+
ensureCrumbDir();
|
|
14
|
+
const salt = randomBytes(32);
|
|
15
|
+
const key = scryptSync(password, salt, 32);
|
|
16
|
+
const iv = randomBytes(16);
|
|
17
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
18
|
+
let encrypted = cipher.update(privateKey, 'utf-8', 'hex');
|
|
19
|
+
encrypted += cipher.final('hex');
|
|
20
|
+
const authTag = cipher.getAuthTag();
|
|
21
|
+
const payload = {
|
|
22
|
+
salt: salt.toString('hex'),
|
|
23
|
+
iv: iv.toString('hex'),
|
|
24
|
+
authTag: authTag.toString('hex'),
|
|
25
|
+
encrypted,
|
|
26
|
+
};
|
|
27
|
+
writeFileSync(getKeystorePath(), JSON.stringify(payload, null, 2));
|
|
28
|
+
}
|
|
29
|
+
export function loadPrivateKey(password) {
|
|
30
|
+
const path = getKeystorePath();
|
|
31
|
+
if (!existsSync(path)) {
|
|
32
|
+
throw new Error('No keystore found. Run `crumb init` first.');
|
|
33
|
+
}
|
|
34
|
+
const payload = JSON.parse(readFileSync(path, 'utf-8'));
|
|
35
|
+
const salt = Buffer.from(payload.salt, 'hex');
|
|
36
|
+
const iv = Buffer.from(payload.iv, 'hex');
|
|
37
|
+
const authTag = Buffer.from(payload.authTag, 'hex');
|
|
38
|
+
const key = scryptSync(password, salt, 32);
|
|
39
|
+
const decipher = createDecipheriv('aes-256-gcm', key, iv);
|
|
40
|
+
decipher.setAuthTag(authTag);
|
|
41
|
+
let decrypted = decipher.update(payload.encrypted, 'hex', 'utf-8');
|
|
42
|
+
decrypted += decipher.final('utf-8');
|
|
43
|
+
return decrypted;
|
|
44
|
+
}
|
|
45
|
+
export function getPassword() {
|
|
46
|
+
const envPassword = process.env.CRUMB_KEYSTORE_PASSWORD;
|
|
47
|
+
if (envPassword)
|
|
48
|
+
return envPassword;
|
|
49
|
+
throw new Error('No password provided. Set CRUMB_KEYSTORE_PASSWORD env var or pass --password flag.');
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=keystore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keystore.js","sourceRoot":"","sources":["../../src/utils/keystore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function heading(text: string): void;
|
|
2
|
+
export declare function success(text: string): void;
|
|
3
|
+
export declare function error(text: string): void;
|
|
4
|
+
export declare function info(text: string): void;
|
|
5
|
+
export declare function keyValue(key: string, value: string): void;
|
|
6
|
+
export declare function box(lines: string[]): void;
|
|
7
|
+
export declare function truncateAddress(address: string): string;
|
|
8
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"AAEA,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI1C;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAExC;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAUzC;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
export function heading(text) {
|
|
3
|
+
console.log();
|
|
4
|
+
console.log(chalk.bold.cyan(` ◆ ${text}`));
|
|
5
|
+
console.log();
|
|
6
|
+
}
|
|
7
|
+
export function success(text) {
|
|
8
|
+
console.log(chalk.green(` ✔ ${text}`));
|
|
9
|
+
}
|
|
10
|
+
export function error(text) {
|
|
11
|
+
console.log(chalk.red(` ✖ ${text}`));
|
|
12
|
+
}
|
|
13
|
+
export function info(text) {
|
|
14
|
+
console.log(chalk.gray(` ${text}`));
|
|
15
|
+
}
|
|
16
|
+
export function keyValue(key, value) {
|
|
17
|
+
console.log(` ${chalk.dim(key.padEnd(12))} ${value}`);
|
|
18
|
+
}
|
|
19
|
+
export function box(lines) {
|
|
20
|
+
const maxLen = Math.max(...lines.map((l) => l.length));
|
|
21
|
+
const border = '─'.repeat(maxLen + 4);
|
|
22
|
+
console.log();
|
|
23
|
+
console.log(` ┌${border}┐`);
|
|
24
|
+
for (const line of lines) {
|
|
25
|
+
console.log(` │ ${line.padEnd(maxLen + 2)}│`);
|
|
26
|
+
}
|
|
27
|
+
console.log(` └${border}┘`);
|
|
28
|
+
console.log();
|
|
29
|
+
}
|
|
30
|
+
export function truncateAddress(address) {
|
|
31
|
+
if (address.length <= 12)
|
|
32
|
+
return address;
|
|
33
|
+
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAA;IAC3C,OAAO,CAAC,GAAG,EAAE,CAAA;AACf,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAY;IAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAA;AACtC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,KAAa;IACjD,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,KAAe;IACjC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IACtD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACrC,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,OAAO,CAAC,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,CAAA;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,CAAA;IAC5B,OAAO,CAAC,GAAG,EAAE,CAAA;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE;QAAE,OAAO,OAAO,CAAA;IACxC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AACxD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "crumb-alpha-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"crumb": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"commander": "^13.1.0",
|
|
13
|
+
"inquirer": "^12.3.0",
|
|
14
|
+
"chalk": "^5.4.0",
|
|
15
|
+
"ora": "^8.2.0",
|
|
16
|
+
"viem": "^2.23.0",
|
|
17
|
+
"@circle-fin/x402-batching": "^2.0.4",
|
|
18
|
+
"crumb-alpha-core": "0.1.0",
|
|
19
|
+
"crumb-alpha-sdk": "0.1.0"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"express": ">=4.0.0"
|
|
23
|
+
},
|
|
24
|
+
"peerDependenciesMeta": {
|
|
25
|
+
"express": {
|
|
26
|
+
"optional": true
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/express": "^5.0.0",
|
|
31
|
+
"@types/inquirer": "^9.0.0"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc",
|
|
35
|
+
"dev": "tsc --watch",
|
|
36
|
+
"clean": "rm -rf dist",
|
|
37
|
+
"test": "vitest run"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { GatewayClient, walletFromPrivateKey } from 'crumb-alpha-core'
|
|
2
|
+
import type { SupportedChainName } from 'crumb-alpha-core'
|
|
3
|
+
import { readConfig } from '../utils/config.js'
|
|
4
|
+
import { loadPrivateKey, getPassword } from '../utils/keystore.js'
|
|
5
|
+
import { heading, error, box, truncateAddress, keyValue } from '../utils/output.js'
|
|
6
|
+
|
|
7
|
+
export async function balanceCommand(): Promise<void> {
|
|
8
|
+
const config = readConfig()
|
|
9
|
+
|
|
10
|
+
if (!config.activeWallet) {
|
|
11
|
+
heading('Balance')
|
|
12
|
+
error('No wallet configured. Run `crumb init` first.')
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let password: string
|
|
17
|
+
try {
|
|
18
|
+
password = getPassword()
|
|
19
|
+
} catch {
|
|
20
|
+
error('No password provided. Set CRUMB_KEYSTORE_PASSWORD env var.')
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let privateKey: string
|
|
25
|
+
try {
|
|
26
|
+
privateKey = loadPrivateKey(password)
|
|
27
|
+
} catch (err: any) {
|
|
28
|
+
error(`Failed to decrypt keystore: ${err.message}`)
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const chain = (config.chain ?? 'arcTestnet') as SupportedChainName
|
|
33
|
+
const gateway = new GatewayClient({
|
|
34
|
+
chain,
|
|
35
|
+
privateKey: privateKey as `0x${string}`,
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const balances = await gateway.getBalances()
|
|
39
|
+
|
|
40
|
+
box([
|
|
41
|
+
`Wallet ${truncateAddress(config.activeWallet)}`,
|
|
42
|
+
`Chain ${chain}`,
|
|
43
|
+
``,
|
|
44
|
+
`Wallet ${balances.wallet.formatted} USDC`,
|
|
45
|
+
`Gateway ${balances.gateway.formattedAvailable} USDC available`,
|
|
46
|
+
` ${balances.gateway.formattedTotal} USDC total`,
|
|
47
|
+
])
|
|
48
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { GatewayClient } from 'crumb-alpha-core'
|
|
2
|
+
import type { SupportedChainName } from 'crumb-alpha-core'
|
|
3
|
+
import { readConfig } from '../utils/config.js'
|
|
4
|
+
import { loadPrivateKey, getPassword } from '../utils/keystore.js'
|
|
5
|
+
import { heading, success, error, info, keyValue } from '../utils/output.js'
|
|
6
|
+
import ora from 'ora'
|
|
7
|
+
|
|
8
|
+
export async function depositCommand(amount: string): Promise<void> {
|
|
9
|
+
heading('Deposit')
|
|
10
|
+
|
|
11
|
+
const config = readConfig()
|
|
12
|
+
if (!config.activeWallet) {
|
|
13
|
+
error('No wallet configured. Run `crumb init` first.')
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let password: string
|
|
18
|
+
try {
|
|
19
|
+
password = getPassword()
|
|
20
|
+
} catch {
|
|
21
|
+
error('No password provided. Set CRUMB_KEYSTORE_PASSWORD env var.')
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let privateKey: string
|
|
26
|
+
try {
|
|
27
|
+
privateKey = loadPrivateKey(password)
|
|
28
|
+
} catch (err: any) {
|
|
29
|
+
error(`Failed to decrypt keystore: ${err.message}`)
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const chain = (config.chain ?? 'arcTestnet') as SupportedChainName
|
|
34
|
+
const gateway = new GatewayClient({
|
|
35
|
+
chain,
|
|
36
|
+
privateKey: privateKey as `0x${string}`,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
info(`Depositing ${amount} USDC into Gateway...`)
|
|
40
|
+
const spinner = ora(' Processing deposit...').start()
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const result = await gateway.deposit(amount)
|
|
44
|
+
spinner.stop()
|
|
45
|
+
|
|
46
|
+
console.log()
|
|
47
|
+
success('Deposited')
|
|
48
|
+
keyValue('Amount:', `${result.formattedAmount} USDC`)
|
|
49
|
+
keyValue('Deposit Tx:', result.depositTxHash)
|
|
50
|
+
if (result.approvalTxHash) {
|
|
51
|
+
keyValue('Approval Tx:', result.approvalTxHash)
|
|
52
|
+
}
|
|
53
|
+
} catch (err: any) {
|
|
54
|
+
spinner.stop()
|
|
55
|
+
error(`Deposit failed: ${err.message}`)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { heading, info } from '../utils/output.js'
|
|
2
|
+
|
|
3
|
+
export async function historyCommand(options: { limit?: number }): Promise<void> {
|
|
4
|
+
heading('Transaction History')
|
|
5
|
+
|
|
6
|
+
// TODO: Integrate with Arc indexer or local transaction log
|
|
7
|
+
// For now, this is a placeholder that will be implemented once
|
|
8
|
+
// we have access to a transaction indexing API
|
|
9
|
+
info('Transaction history is not yet available.')
|
|
10
|
+
info('This feature will be added in a future release.')
|
|
11
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createWallet } from 'crumb-alpha-core'
|
|
2
|
+
import { configExists, writeConfig, getConfigPath } from '../utils/config.js'
|
|
3
|
+
import { encryptAndSave } from '../utils/keystore.js'
|
|
4
|
+
import { heading, success, info, keyValue } from '../utils/output.js'
|
|
5
|
+
import inquirer from 'inquirer'
|
|
6
|
+
|
|
7
|
+
export async function initCommand(): Promise<void> {
|
|
8
|
+
heading('Welcome to Crumb')
|
|
9
|
+
|
|
10
|
+
if (configExists()) {
|
|
11
|
+
info(`Config already exists at ${getConfigPath()}`)
|
|
12
|
+
|
|
13
|
+
const { overwrite } = await inquirer.prompt([
|
|
14
|
+
{
|
|
15
|
+
type: 'confirm',
|
|
16
|
+
name: 'overwrite',
|
|
17
|
+
message: 'Overwrite existing config?',
|
|
18
|
+
default: false,
|
|
19
|
+
},
|
|
20
|
+
])
|
|
21
|
+
|
|
22
|
+
if (!overwrite) {
|
|
23
|
+
info('Aborted.')
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
info(`Creating config at ${getConfigPath()}`)
|
|
29
|
+
console.log()
|
|
30
|
+
|
|
31
|
+
const { chain } = await inquirer.prompt([
|
|
32
|
+
{
|
|
33
|
+
type: 'list',
|
|
34
|
+
name: 'chain',
|
|
35
|
+
message: 'Select chain:',
|
|
36
|
+
choices: [
|
|
37
|
+
{ name: 'Arc Testnet', value: 'arcTestnet' },
|
|
38
|
+
],
|
|
39
|
+
default: 'arcTestnet',
|
|
40
|
+
},
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
const { generateWallet } = await inquirer.prompt([
|
|
44
|
+
{
|
|
45
|
+
type: 'confirm',
|
|
46
|
+
name: 'generateWallet',
|
|
47
|
+
message: 'Generate a new wallet?',
|
|
48
|
+
default: true,
|
|
49
|
+
},
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
if (generateWallet) {
|
|
53
|
+
const wallet = createWallet()
|
|
54
|
+
|
|
55
|
+
const { password } = await inquirer.prompt([
|
|
56
|
+
{
|
|
57
|
+
type: 'password',
|
|
58
|
+
name: 'password',
|
|
59
|
+
message: 'Set a keystore password:',
|
|
60
|
+
mask: '*',
|
|
61
|
+
},
|
|
62
|
+
])
|
|
63
|
+
|
|
64
|
+
encryptAndSave(wallet.privateKey, password)
|
|
65
|
+
|
|
66
|
+
writeConfig({
|
|
67
|
+
activeWallet: wallet.address,
|
|
68
|
+
chain,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
console.log()
|
|
72
|
+
success('Wallet created')
|
|
73
|
+
keyValue('Address:', wallet.address)
|
|
74
|
+
keyValue('Chain:', chain)
|
|
75
|
+
keyValue('Saved to:', '~/.crumb/keystore.enc (AES-256-GCM, password-protected)')
|
|
76
|
+
console.log()
|
|
77
|
+
info('Next steps:')
|
|
78
|
+
info(' 1. Fund your wallet with testnet USDC')
|
|
79
|
+
info(' 2. Deposit into Gateway: npx crumb deposit <amount>')
|
|
80
|
+
info(' 3. Start paying: npx crumb pay <url>')
|
|
81
|
+
} else {
|
|
82
|
+
writeConfig({ chain })
|
|
83
|
+
success('Config created')
|
|
84
|
+
info('Run `npx crumb wallet create` to create a wallet later.')
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { GatewayClient } from 'crumb-alpha-core'
|
|
2
|
+
import type { SupportedChainName } from 'crumb-alpha-core'
|
|
3
|
+
import { readConfig } from '../utils/config.js'
|
|
4
|
+
import { loadPrivateKey, getPassword } from '../utils/keystore.js'
|
|
5
|
+
import { heading, success, error, info, keyValue } from '../utils/output.js'
|
|
6
|
+
import ora from 'ora'
|
|
7
|
+
|
|
8
|
+
export async function payCommand(url: string, options: { maxPayment?: string }): Promise<void> {
|
|
9
|
+
heading('Pay')
|
|
10
|
+
|
|
11
|
+
const config = readConfig()
|
|
12
|
+
if (!config.activeWallet) {
|
|
13
|
+
error('No wallet configured. Run `crumb init` first.')
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let password: string
|
|
18
|
+
try {
|
|
19
|
+
password = getPassword()
|
|
20
|
+
} catch {
|
|
21
|
+
error('No password provided. Set CRUMB_KEYSTORE_PASSWORD env var.')
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let privateKey: string
|
|
26
|
+
try {
|
|
27
|
+
privateKey = loadPrivateKey(password)
|
|
28
|
+
} catch (err: any) {
|
|
29
|
+
error(`Failed to decrypt keystore: ${err.message}`)
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const chain = (config.chain ?? 'arcTestnet') as SupportedChainName
|
|
34
|
+
const gateway = new GatewayClient({
|
|
35
|
+
chain,
|
|
36
|
+
privateKey: privateKey as `0x${string}`,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
info(`Paying for ${url}...`)
|
|
40
|
+
const spinner = ora(' Processing payment...').start()
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const result = await gateway.pay(url)
|
|
44
|
+
spinner.stop()
|
|
45
|
+
|
|
46
|
+
console.log()
|
|
47
|
+
success('Payment complete')
|
|
48
|
+
keyValue('Amount:', `${result.formattedAmount} USDC`)
|
|
49
|
+
keyValue('Tx:', result.transaction)
|
|
50
|
+
keyValue('Status:', result.status.toString())
|
|
51
|
+
} catch (err: any) {
|
|
52
|
+
spinner.stop()
|
|
53
|
+
error(`Payment failed: ${err.message}`)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { readConfig } from '../utils/config.js'
|
|
2
|
+
import { heading, success, error, info, keyValue } from '../utils/output.js'
|
|
3
|
+
|
|
4
|
+
export async function serveCommand(
|
|
5
|
+
file: string,
|
|
6
|
+
options: { port?: string; price?: string },
|
|
7
|
+
): Promise<void> {
|
|
8
|
+
heading('Crumb Provider')
|
|
9
|
+
|
|
10
|
+
const config = readConfig()
|
|
11
|
+
if (!config.activeWallet) {
|
|
12
|
+
error('No wallet configured. Run `crumb init` first.')
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const port = parseInt(options.port ?? '3000', 10)
|
|
17
|
+
const price = options.price ?? '$0.01'
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const express = (await import('express')).default
|
|
21
|
+
const { createGatewayMiddleware } = await import('@circle-fin/x402-batching/server')
|
|
22
|
+
|
|
23
|
+
const handler = await import(file)
|
|
24
|
+
const userHandler = handler.default ?? handler
|
|
25
|
+
|
|
26
|
+
const app = express()
|
|
27
|
+
app.use(express.json())
|
|
28
|
+
|
|
29
|
+
const gateway = createGatewayMiddleware({
|
|
30
|
+
sellerAddress: config.activeWallet,
|
|
31
|
+
description: `Local provider — ${price} per call`,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
app.all(
|
|
35
|
+
'*',
|
|
36
|
+
gateway.require(price),
|
|
37
|
+
(req: any, res: any, next: any) => {
|
|
38
|
+
if (req.payment) {
|
|
39
|
+
success(`Payment received — ${req.payment.amount} USDC from ${req.payment.payer} (tx: ${req.payment.transaction?.slice(0, 8)}...)`)
|
|
40
|
+
}
|
|
41
|
+
next()
|
|
42
|
+
},
|
|
43
|
+
userHandler,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
app.listen(port, () => {
|
|
47
|
+
keyValue('Endpoint:', `http://localhost:${port}`)
|
|
48
|
+
keyValue('Price:', `${price} per call`)
|
|
49
|
+
keyValue('Wallet:', config.activeWallet!)
|
|
50
|
+
console.log()
|
|
51
|
+
info('Waiting for payments...')
|
|
52
|
+
console.log()
|
|
53
|
+
})
|
|
54
|
+
} catch (err: any) {
|
|
55
|
+
error(`Failed to start server: ${err.message}`)
|
|
56
|
+
info('Make sure express is installed: pnpm add express')
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createWallet } from 'crumb-alpha-core'
|
|
2
|
+
import { readConfig, writeConfig } from '../utils/config.js'
|
|
3
|
+
import { encryptAndSave, keystoreExists } from '../utils/keystore.js'
|
|
4
|
+
import { heading, success, info, keyValue, error } from '../utils/output.js'
|
|
5
|
+
import inquirer from 'inquirer'
|
|
6
|
+
|
|
7
|
+
export async function walletCreateCommand(): Promise<void> {
|
|
8
|
+
heading('Create Wallet')
|
|
9
|
+
|
|
10
|
+
if (keystoreExists()) {
|
|
11
|
+
const { overwrite } = await inquirer.prompt([
|
|
12
|
+
{
|
|
13
|
+
type: 'confirm',
|
|
14
|
+
name: 'overwrite',
|
|
15
|
+
message: 'A wallet already exists. Overwrite?',
|
|
16
|
+
default: false,
|
|
17
|
+
},
|
|
18
|
+
])
|
|
19
|
+
if (!overwrite) {
|
|
20
|
+
info('Aborted.')
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const wallet = createWallet()
|
|
26
|
+
|
|
27
|
+
const { password } = await inquirer.prompt([
|
|
28
|
+
{
|
|
29
|
+
type: 'password',
|
|
30
|
+
name: 'password',
|
|
31
|
+
message: 'Set a keystore password:',
|
|
32
|
+
mask: '*',
|
|
33
|
+
},
|
|
34
|
+
])
|
|
35
|
+
|
|
36
|
+
encryptAndSave(wallet.privateKey, password)
|
|
37
|
+
|
|
38
|
+
const config = readConfig()
|
|
39
|
+
config.activeWallet = wallet.address
|
|
40
|
+
writeConfig(config)
|
|
41
|
+
|
|
42
|
+
console.log()
|
|
43
|
+
success('Wallet created')
|
|
44
|
+
keyValue('Address:', wallet.address)
|
|
45
|
+
keyValue('Saved to:', '~/.crumb/keystore.enc')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function walletShowCommand(): Promise<void> {
|
|
49
|
+
heading('Wallet')
|
|
50
|
+
|
|
51
|
+
const config = readConfig()
|
|
52
|
+
if (!config.activeWallet) {
|
|
53
|
+
error('No wallet configured. Run `crumb wallet create` first.')
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
keyValue('Address:', config.activeWallet)
|
|
58
|
+
keyValue('Chain:', config.chain)
|
|
59
|
+
keyValue('Keystore:', '~/.crumb/keystore.enc')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function walletFundCommand(): Promise<void> {
|
|
63
|
+
heading('Fund Wallet')
|
|
64
|
+
|
|
65
|
+
const config = readConfig()
|
|
66
|
+
if (!config.activeWallet) {
|
|
67
|
+
error('No wallet configured. Run `crumb wallet create` first.')
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
info('To fund your wallet with testnet USDC:')
|
|
72
|
+
console.log()
|
|
73
|
+
keyValue('Address:', config.activeWallet)
|
|
74
|
+
keyValue('Chain:', config.chain)
|
|
75
|
+
console.log()
|
|
76
|
+
info('1. Get testnet USDC from a faucet for your chain')
|
|
77
|
+
info('2. Send USDC to your address above')
|
|
78
|
+
info('3. Run `npx crumb deposit <amount>` to move USDC into Gateway')
|
|
79
|
+
console.log()
|
|
80
|
+
info('Once deposited, run `npx crumb balance` to check your balance.')
|
|
81
|
+
}
|