@paylobster/cli 4.0.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/BUILD_SUMMARY.md +429 -0
- package/CHANGELOG.md +78 -0
- package/CONTRIBUTING.md +368 -0
- package/EXAMPLES.md +432 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +189 -0
- package/README.md +377 -0
- package/TEST_REPORT.md +191 -0
- package/bin/plob.js +9 -0
- package/bin/plob.ts +9 -0
- package/demo.sh +154 -0
- package/dist/bin/plob.d.ts +7 -0
- package/dist/bin/plob.d.ts.map +1 -0
- package/dist/bin/plob.js +10 -0
- package/dist/bin/plob.js.map +1 -0
- package/dist/src/commands/auth.d.ts +3 -0
- package/dist/src/commands/auth.d.ts.map +1 -0
- package/dist/src/commands/auth.js +75 -0
- package/dist/src/commands/auth.js.map +1 -0
- package/dist/src/commands/config.d.ts +3 -0
- package/dist/src/commands/config.d.ts.map +1 -0
- package/dist/src/commands/config.js +79 -0
- package/dist/src/commands/config.js.map +1 -0
- package/dist/src/commands/escrow.d.ts +3 -0
- package/dist/src/commands/escrow.d.ts.map +1 -0
- package/dist/src/commands/escrow.js +193 -0
- package/dist/src/commands/escrow.js.map +1 -0
- package/dist/src/commands/mandate.d.ts +8 -0
- package/dist/src/commands/mandate.d.ts.map +1 -0
- package/dist/src/commands/mandate.js +54 -0
- package/dist/src/commands/mandate.js.map +1 -0
- package/dist/src/commands/pay.d.ts +6 -0
- package/dist/src/commands/pay.d.ts.map +1 -0
- package/dist/src/commands/pay.js +77 -0
- package/dist/src/commands/pay.js.map +1 -0
- package/dist/src/commands/register.d.ts +3 -0
- package/dist/src/commands/register.d.ts.map +1 -0
- package/dist/src/commands/register.js +51 -0
- package/dist/src/commands/register.js.map +1 -0
- package/dist/src/commands/reputation.d.ts +3 -0
- package/dist/src/commands/reputation.d.ts.map +1 -0
- package/dist/src/commands/reputation.js +116 -0
- package/dist/src/commands/reputation.js.map +1 -0
- package/dist/src/commands/status.d.ts +3 -0
- package/dist/src/commands/status.d.ts.map +1 -0
- package/dist/src/commands/status.js +82 -0
- package/dist/src/commands/status.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +59 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lib/config.d.ts +26 -0
- package/dist/src/lib/config.d.ts.map +1 -0
- package/dist/src/lib/config.js +91 -0
- package/dist/src/lib/config.js.map +1 -0
- package/dist/src/lib/contracts.d.ts +18798 -0
- package/dist/src/lib/contracts.d.ts.map +1 -0
- package/dist/src/lib/contracts.js +361 -0
- package/dist/src/lib/contracts.js.map +1 -0
- package/dist/src/lib/display.d.ts +83 -0
- package/dist/src/lib/display.d.ts.map +1 -0
- package/dist/src/lib/display.js +293 -0
- package/dist/src/lib/display.js.map +1 -0
- package/dist/src/lib/types.d.ts +49 -0
- package/dist/src/lib/types.d.ts.map +1 -0
- package/dist/src/lib/types.js +3 -0
- package/dist/src/lib/types.js.map +1 -0
- package/dist/src/lib/wallet.d.ts +30 -0
- package/dist/src/lib/wallet.d.ts.map +1 -0
- package/dist/src/lib/wallet.js +143 -0
- package/dist/src/lib/wallet.js.map +1 -0
- package/jest.config.js +15 -0
- package/package.json +55 -0
- package/src/__tests__/cli.test.ts +38 -0
- package/src/commands/auth.ts +75 -0
- package/src/commands/config.ts +84 -0
- package/src/commands/escrow.ts +222 -0
- package/src/commands/mandate.ts +56 -0
- package/src/commands/pay.ts +96 -0
- package/src/commands/register.ts +57 -0
- package/src/commands/reputation.ts +84 -0
- package/src/commands/status.ts +91 -0
- package/src/index.ts +63 -0
- package/src/lib/config.ts +90 -0
- package/src/lib/contracts.ts +392 -0
- package/src/lib/display.ts +265 -0
- package/src/lib/types.ts +57 -0
- package/src/lib/wallet.ts +146 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import Table from 'cli-table3';
|
|
3
|
+
import type { OutputOptions } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Print JSON output if --json flag is set
|
|
7
|
+
*/
|
|
8
|
+
export function outputJSON(data: any, options?: OutputOptions): boolean {
|
|
9
|
+
if (options?.json) {
|
|
10
|
+
console.log(JSON.stringify(data, null, 2));
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Print success message
|
|
18
|
+
*/
|
|
19
|
+
export function success(message: string): void {
|
|
20
|
+
console.log(chalk.green('✅ ' + message));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Print error message
|
|
25
|
+
*/
|
|
26
|
+
export function error(message: string): void {
|
|
27
|
+
console.error(chalk.red('❌ ' + message));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Print warning message
|
|
32
|
+
*/
|
|
33
|
+
export function warning(message: string): void {
|
|
34
|
+
console.warn(chalk.yellow('⚠️ ' + message));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Print info message
|
|
39
|
+
*/
|
|
40
|
+
export function info(message: string): void {
|
|
41
|
+
console.log(chalk.blue('ℹ️ ' + message));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Print section header
|
|
46
|
+
*/
|
|
47
|
+
export function header(text: string): void {
|
|
48
|
+
console.log();
|
|
49
|
+
console.log(chalk.bold.cyan('🦞 ' + text));
|
|
50
|
+
console.log(chalk.gray('─'.repeat(text.length + 3)));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create a table
|
|
55
|
+
*/
|
|
56
|
+
export function createTable(options?: any): Table.Table {
|
|
57
|
+
return new Table({
|
|
58
|
+
chars: {
|
|
59
|
+
top: '─',
|
|
60
|
+
'top-mid': '┬',
|
|
61
|
+
'top-left': '┌',
|
|
62
|
+
'top-right': '┐',
|
|
63
|
+
bottom: '─',
|
|
64
|
+
'bottom-mid': '┴',
|
|
65
|
+
'bottom-left': '└',
|
|
66
|
+
'bottom-right': '┘',
|
|
67
|
+
left: '│',
|
|
68
|
+
'left-mid': '├',
|
|
69
|
+
mid: '─',
|
|
70
|
+
'mid-mid': '┼',
|
|
71
|
+
right: '│',
|
|
72
|
+
'right-mid': '┤',
|
|
73
|
+
middle: '│',
|
|
74
|
+
},
|
|
75
|
+
style: {
|
|
76
|
+
head: ['cyan', 'bold'],
|
|
77
|
+
border: ['gray'],
|
|
78
|
+
},
|
|
79
|
+
...options,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Print key-value pairs
|
|
85
|
+
*/
|
|
86
|
+
export function printKeyValue(data: Record<string, any>): void {
|
|
87
|
+
const maxKeyLength = Math.max(...Object.keys(data).map(k => k.length));
|
|
88
|
+
|
|
89
|
+
for (const [key, value] of Object.entries(data)) {
|
|
90
|
+
const paddedKey = key.padEnd(maxKeyLength);
|
|
91
|
+
console.log(chalk.gray(paddedKey + ':'), chalk.white(value));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Format address (shorten)
|
|
97
|
+
*/
|
|
98
|
+
export function formatAddress(address: string): string {
|
|
99
|
+
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Format status with color
|
|
104
|
+
*/
|
|
105
|
+
export function formatStatus(status: number | string): string {
|
|
106
|
+
const statusMap: Record<string, { text: string; color: any }> = {
|
|
107
|
+
0: { text: 'Pending', color: chalk.yellow },
|
|
108
|
+
1: { text: 'Active', color: chalk.blue },
|
|
109
|
+
2: { text: 'Released', color: chalk.green },
|
|
110
|
+
3: { text: 'Disputed', color: chalk.red },
|
|
111
|
+
pending: { text: 'Pending', color: chalk.yellow },
|
|
112
|
+
active: { text: 'Active', color: chalk.blue },
|
|
113
|
+
released: { text: 'Released', color: chalk.green },
|
|
114
|
+
disputed: { text: 'Disputed', color: chalk.red },
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const statusKey = status.toString();
|
|
118
|
+
const statusInfo = statusMap[statusKey] || { text: status.toString(), color: chalk.white };
|
|
119
|
+
|
|
120
|
+
return statusInfo.color(statusInfo.text);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Format boolean as emoji
|
|
125
|
+
*/
|
|
126
|
+
export function formatBoolean(value: boolean): string {
|
|
127
|
+
return value ? chalk.green('✅') : chalk.red('❌');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Format number with commas
|
|
132
|
+
*/
|
|
133
|
+
export function formatNumber(num: number | string): string {
|
|
134
|
+
return Number(num).toLocaleString();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Print a horizontal divider
|
|
139
|
+
*/
|
|
140
|
+
export function divider(): void {
|
|
141
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Print agent status header
|
|
146
|
+
*/
|
|
147
|
+
export function printAgentHeader(name: string, address: string): void {
|
|
148
|
+
console.log();
|
|
149
|
+
console.log(chalk.bold.cyan('🦞 PayLobster Agent Status'));
|
|
150
|
+
divider();
|
|
151
|
+
console.log(chalk.gray('Name: ') + chalk.white.bold(name));
|
|
152
|
+
console.log(chalk.gray('Address: ') + chalk.white(address));
|
|
153
|
+
divider();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Print escrow table
|
|
158
|
+
*/
|
|
159
|
+
export function printEscrowTable(escrows: any[]): void {
|
|
160
|
+
if (escrows.length === 0) {
|
|
161
|
+
info('No escrows found');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const table = createTable({
|
|
166
|
+
head: ['ID', 'From', 'To', 'Amount', 'Status'],
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
for (const escrow of escrows) {
|
|
170
|
+
table.push([
|
|
171
|
+
escrow.id,
|
|
172
|
+
formatAddress(escrow.from),
|
|
173
|
+
formatAddress(escrow.to),
|
|
174
|
+
escrow.amount,
|
|
175
|
+
formatStatus(escrow.status),
|
|
176
|
+
]);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log(table.toString());
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Spinner/loading indicator using ora
|
|
184
|
+
*/
|
|
185
|
+
export async function withSpinner<T>(
|
|
186
|
+
text: string,
|
|
187
|
+
fn: () => Promise<T>
|
|
188
|
+
): Promise<T> {
|
|
189
|
+
const ora = (await import('ora')).default;
|
|
190
|
+
const spinner = ora(text).start();
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
const result = await fn();
|
|
194
|
+
spinner.succeed();
|
|
195
|
+
return result;
|
|
196
|
+
} catch (error) {
|
|
197
|
+
spinner.fail();
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Format network name
|
|
204
|
+
*/
|
|
205
|
+
export function formatNetwork(network: string): string {
|
|
206
|
+
const networkMap: Record<string, string> = {
|
|
207
|
+
mainnet: 'Base Mainnet',
|
|
208
|
+
sepolia: 'Base Sepolia',
|
|
209
|
+
};
|
|
210
|
+
return networkMap[network] || network;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Print configuration table
|
|
215
|
+
*/
|
|
216
|
+
export function printConfig(config: Record<string, any>): void {
|
|
217
|
+
const table = createTable({
|
|
218
|
+
head: ['Setting', 'Value'],
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
for (const [key, value] of Object.entries(config)) {
|
|
222
|
+
if (key === 'wallet' && typeof value === 'object') {
|
|
223
|
+
table.push([key, value.type || 'env']);
|
|
224
|
+
} else {
|
|
225
|
+
table.push([key, value?.toString() || 'not set']);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
console.log(table.toString());
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Print reputation score with visual indicator
|
|
234
|
+
*/
|
|
235
|
+
export function printReputation(score: number): string {
|
|
236
|
+
const stars = Math.floor(score / 20); // Convert 0-100 to 0-5 stars
|
|
237
|
+
const fullStar = '★';
|
|
238
|
+
const emptyStar = '☆';
|
|
239
|
+
|
|
240
|
+
const starsStr = fullStar.repeat(stars) + emptyStar.repeat(5 - stars);
|
|
241
|
+
|
|
242
|
+
if (score >= 80) {
|
|
243
|
+
return chalk.green(starsStr + ` ${score}`);
|
|
244
|
+
} else if (score >= 60) {
|
|
245
|
+
return chalk.yellow(starsStr + ` ${score}`);
|
|
246
|
+
} else {
|
|
247
|
+
return chalk.red(starsStr + ` ${score}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Confirm action (simple yes/no prompt)
|
|
253
|
+
*/
|
|
254
|
+
export async function confirm(message: string): Promise<boolean> {
|
|
255
|
+
const inquirer = (await import('inquirer')).default;
|
|
256
|
+
const { confirmed } = await inquirer.prompt([
|
|
257
|
+
{
|
|
258
|
+
type: 'confirm',
|
|
259
|
+
name: 'confirmed',
|
|
260
|
+
message,
|
|
261
|
+
default: false,
|
|
262
|
+
},
|
|
263
|
+
]);
|
|
264
|
+
return confirmed;
|
|
265
|
+
}
|
package/src/lib/types.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Address } from 'viem';
|
|
2
|
+
|
|
3
|
+
export type Network = 'mainnet' | 'sepolia';
|
|
4
|
+
|
|
5
|
+
export interface CLIConfig {
|
|
6
|
+
network: Network;
|
|
7
|
+
rpcUrl?: string;
|
|
8
|
+
wallet?: {
|
|
9
|
+
type: 'private-key' | 'keystore' | 'env';
|
|
10
|
+
path?: string;
|
|
11
|
+
};
|
|
12
|
+
indexerUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AgentInfo {
|
|
16
|
+
name: string;
|
|
17
|
+
tokenId: bigint;
|
|
18
|
+
registered: boolean;
|
|
19
|
+
address: Address;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Reputation {
|
|
23
|
+
score: bigint;
|
|
24
|
+
trustVector: bigint;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface CreditStatus {
|
|
28
|
+
limit: bigint;
|
|
29
|
+
available: bigint;
|
|
30
|
+
inUse: bigint;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface EscrowInfo {
|
|
34
|
+
sender: Address;
|
|
35
|
+
recipient: Address;
|
|
36
|
+
amount: bigint;
|
|
37
|
+
token: Address;
|
|
38
|
+
status: number; // 0=pending, 1=active, 2=released, 3=disputed
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Balance {
|
|
42
|
+
usdc: bigint;
|
|
43
|
+
eth: bigint;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ServiceListing {
|
|
47
|
+
serviceId: string;
|
|
48
|
+
provider: Address;
|
|
49
|
+
name: string;
|
|
50
|
+
category: string;
|
|
51
|
+
price: bigint;
|
|
52
|
+
reputation: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface OutputOptions {
|
|
56
|
+
json?: boolean;
|
|
57
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { createWalletClient, http, type WalletClient, type Account } from 'viem';
|
|
5
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
6
|
+
import { base, baseSepolia } from 'viem/chains';
|
|
7
|
+
import { loadConfig, getRpcUrl } from './config';
|
|
8
|
+
import type { Network } from './types';
|
|
9
|
+
|
|
10
|
+
const KEYSTORE_DIR = path.join(os.homedir(), '.plob', 'keystore');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Load wallet from configured source
|
|
14
|
+
*/
|
|
15
|
+
export async function loadWallet(): Promise<{ client: WalletClient; account: Account }> {
|
|
16
|
+
const config = loadConfig();
|
|
17
|
+
const network = config.network;
|
|
18
|
+
const chain = network === 'mainnet' ? base : baseSepolia;
|
|
19
|
+
|
|
20
|
+
let privateKey: `0x${string}`;
|
|
21
|
+
|
|
22
|
+
// Try different sources in order:
|
|
23
|
+
// 1. Environment variable PRIVATE_KEY or PAYLOBSTER_PRIVATE_KEY
|
|
24
|
+
// 2. Keystore file
|
|
25
|
+
// 3. Config file (not recommended for production)
|
|
26
|
+
|
|
27
|
+
if (process.env.PRIVATE_KEY) {
|
|
28
|
+
privateKey = process.env.PRIVATE_KEY as `0x${string}`;
|
|
29
|
+
} else if (process.env.PAYLOBSTER_PRIVATE_KEY) {
|
|
30
|
+
privateKey = process.env.PAYLOBSTER_PRIVATE_KEY as `0x${string}`;
|
|
31
|
+
} else if (config.wallet?.type === 'keystore' && config.wallet.path) {
|
|
32
|
+
privateKey = loadFromKeystore(config.wallet.path);
|
|
33
|
+
} else {
|
|
34
|
+
throw new Error(
|
|
35
|
+
'No wallet configured. Run `plob auth --private-key <key>` or set PRIVATE_KEY env var'
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Validate private key format
|
|
40
|
+
if (!privateKey.startsWith('0x') || privateKey.length !== 66) {
|
|
41
|
+
throw new Error('Invalid private key format. Must be 0x-prefixed 64-character hex string');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const account = privateKeyToAccount(privateKey);
|
|
45
|
+
|
|
46
|
+
const client = createWalletClient({
|
|
47
|
+
account,
|
|
48
|
+
chain,
|
|
49
|
+
transport: http(getRpcUrl(network)),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return { client, account };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Save private key to keystore (encrypted)
|
|
57
|
+
* Note: For production, use a proper keystore with password encryption
|
|
58
|
+
*/
|
|
59
|
+
export function saveToKeystore(privateKey: string, filename?: string): string {
|
|
60
|
+
try {
|
|
61
|
+
if (!fs.existsSync(KEYSTORE_DIR)) {
|
|
62
|
+
fs.mkdirSync(KEYSTORE_DIR, { recursive: true, mode: 0o700 });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const keystoreFile = filename || 'default.key';
|
|
66
|
+
const keystorePath = path.join(KEYSTORE_DIR, keystoreFile);
|
|
67
|
+
|
|
68
|
+
// WARNING: This is a simple file storage. For production, use proper encryption!
|
|
69
|
+
fs.writeFileSync(keystorePath, privateKey, { mode: 0o600 });
|
|
70
|
+
|
|
71
|
+
return keystorePath;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
throw new Error(`Failed to save keystore: ${error}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Load private key from keystore
|
|
79
|
+
*/
|
|
80
|
+
export function loadFromKeystore(filename: string): `0x${string}` {
|
|
81
|
+
try {
|
|
82
|
+
let keystorePath: string;
|
|
83
|
+
|
|
84
|
+
if (path.isAbsolute(filename)) {
|
|
85
|
+
keystorePath = filename;
|
|
86
|
+
} else {
|
|
87
|
+
keystorePath = path.join(KEYSTORE_DIR, filename);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!fs.existsSync(keystorePath)) {
|
|
91
|
+
throw new Error(`Keystore file not found: ${keystorePath}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const privateKey = fs.readFileSync(keystorePath, 'utf-8').trim();
|
|
95
|
+
return privateKey as `0x${string}`;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
throw new Error(`Failed to load keystore: ${error}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Delete keystore file
|
|
103
|
+
*/
|
|
104
|
+
export function deleteKeystore(filename: string): void {
|
|
105
|
+
const keystorePath = path.join(KEYSTORE_DIR, filename);
|
|
106
|
+
if (fs.existsSync(keystorePath)) {
|
|
107
|
+
fs.unlinkSync(keystorePath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* List all keystore files
|
|
113
|
+
*/
|
|
114
|
+
export function listKeystores(): string[] {
|
|
115
|
+
if (!fs.existsSync(KEYSTORE_DIR)) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
return fs.readdirSync(KEYSTORE_DIR).filter(file => file.endsWith('.key'));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get wallet address without loading full client
|
|
123
|
+
*/
|
|
124
|
+
export function getWalletAddress(): string {
|
|
125
|
+
try {
|
|
126
|
+
let privateKey: `0x${string}`;
|
|
127
|
+
|
|
128
|
+
if (process.env.PRIVATE_KEY) {
|
|
129
|
+
privateKey = process.env.PRIVATE_KEY as `0x${string}`;
|
|
130
|
+
} else if (process.env.PAYLOBSTER_PRIVATE_KEY) {
|
|
131
|
+
privateKey = process.env.PAYLOBSTER_PRIVATE_KEY as `0x${string}`;
|
|
132
|
+
} else {
|
|
133
|
+
const config = loadConfig();
|
|
134
|
+
if (config.wallet?.type === 'keystore' && config.wallet.path) {
|
|
135
|
+
privateKey = loadFromKeystore(config.wallet.path);
|
|
136
|
+
} else {
|
|
137
|
+
throw new Error('No wallet configured');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const account = privateKeyToAccount(privateKey);
|
|
142
|
+
return account.address;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
throw new Error(`Failed to get wallet address: ${error}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2022", "DOM"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"moduleResolution": "node",
|
|
17
|
+
"types": ["node"]
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*", "bin/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
21
|
+
}
|