@net-protocol/cli 0.1.2 → 0.1.4
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 +1 -1
- package/dist/cli/index.mjs +295 -6
- package/dist/cli/index.mjs.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
package/dist/cli/index.mjs
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import 'dotenv/config';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
+
import { createRequire } from 'module';
|
|
4
5
|
import chalk4 from 'chalk';
|
|
5
6
|
import * as fs from 'fs';
|
|
6
7
|
import { readFileSync } from 'fs';
|
|
7
|
-
import { StorageClient, detectFileTypeFromBase64, base64ToDataUri, shouldSuggestXmlStorage, getStorageKeyBytes, encodeStorageKeyForUrl, STORAGE_CONTRACT, CHUNKED_STORAGE_CONTRACT } from '@net-protocol/storage';
|
|
8
|
-
import { stringToHex, createWalletClient, http, hexToString, parseEther, encodeFunctionData, defineChain } from 'viem';
|
|
8
|
+
import { StorageClient, detectFileTypeFromBase64, base64ToDataUri, shouldSuggestXmlStorage, getStorageKeyBytes, encodeStorageKeyForUrl, STORAGE_CONTRACT as STORAGE_CONTRACT$1, CHUNKED_STORAGE_CONTRACT } from '@net-protocol/storage';
|
|
9
|
+
import { stringToHex, createWalletClient, http, hexToString, parseEther, encodeFunctionData, publicActions, defineChain } from 'viem';
|
|
9
10
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
10
11
|
import { getNetContract, getChainName, getPublicClient, getChainRpcUrls, NetClient } from '@net-protocol/core';
|
|
11
12
|
import { createRelayX402Client, createRelaySession, checkBackendWalletBalance, fundBackendWallet, batchTransactions, submitTransactionsViaRelay, waitForConfirmations, retryFailedTransactions as retryFailedTransactions$1 } from '@net-protocol/relay';
|
|
12
13
|
import { isNetrSupportedChain, NetrClient } from '@net-protocol/netr';
|
|
14
|
+
import { PROFILE_PICTURE_STORAGE_KEY, PROFILE_METADATA_STORAGE_KEY, parseProfileMetadata, isValidUrl, getProfilePictureStorageArgs, STORAGE_CONTRACT, isValidXUsername, getXUsernameStorageArgs } from '@net-protocol/profiles';
|
|
15
|
+
import { base } from 'viem/chains';
|
|
13
16
|
|
|
14
17
|
function getRequiredChainId(optionValue) {
|
|
15
18
|
const chainId = optionValue || (process.env.NET_CHAIN_ID ? parseInt(process.env.NET_CHAIN_ID, 10) : void 0);
|
|
@@ -296,7 +299,7 @@ async function filterExistingTransactions(params) {
|
|
|
296
299
|
async function filterXmlStorageTransactions(params) {
|
|
297
300
|
const { storageClient, transactions, operatorAddress } = params;
|
|
298
301
|
const metadataTx = transactions.find(
|
|
299
|
-
(tx) => tx.to.toLowerCase() === STORAGE_CONTRACT.address.toLowerCase()
|
|
302
|
+
(tx) => tx.to.toLowerCase() === STORAGE_CONTRACT$1.address.toLowerCase()
|
|
300
303
|
);
|
|
301
304
|
const chunkTxs = transactions.filter(
|
|
302
305
|
(tx) => tx.to.toLowerCase() === CHUNKED_STORAGE_CONTRACT.address.toLowerCase()
|
|
@@ -1467,8 +1470,8 @@ function registerStorageCommand(program2) {
|
|
|
1467
1470
|
console.log(chalk4.blue(`\u{1F4C1} Reading file: ${options.file}`));
|
|
1468
1471
|
console.log(chalk4.blue(`\u{1F517} Using relay API: ${options.apiUrl}`));
|
|
1469
1472
|
const result = await uploadFileWithRelay(uploadRelayOptions);
|
|
1470
|
-
const { privateKeyToAccount:
|
|
1471
|
-
const userAccount =
|
|
1473
|
+
const { privateKeyToAccount: privateKeyToAccount8 } = await import('viem/accounts');
|
|
1474
|
+
const userAccount = privateKeyToAccount8(commonOptions.privateKey);
|
|
1472
1475
|
const storageUrl = generateStorageUrl(
|
|
1473
1476
|
userAccount.address,
|
|
1474
1477
|
commonOptions.chainId,
|
|
@@ -2215,15 +2218,301 @@ function registerTokenCommand(program2) {
|
|
|
2215
2218
|
tokenCommand.addCommand(deployCommand);
|
|
2216
2219
|
tokenCommand.addCommand(infoCommand);
|
|
2217
2220
|
}
|
|
2221
|
+
async function executeProfileGet(options) {
|
|
2222
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
2223
|
+
chainId: options.chainId,
|
|
2224
|
+
rpcUrl: options.rpcUrl
|
|
2225
|
+
});
|
|
2226
|
+
const client = new StorageClient({
|
|
2227
|
+
chainId: readOnlyOptions.chainId,
|
|
2228
|
+
overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
|
|
2229
|
+
});
|
|
2230
|
+
try {
|
|
2231
|
+
let profilePicture;
|
|
2232
|
+
try {
|
|
2233
|
+
const pictureResult = await client.readStorageData({
|
|
2234
|
+
key: PROFILE_PICTURE_STORAGE_KEY,
|
|
2235
|
+
operator: options.address
|
|
2236
|
+
});
|
|
2237
|
+
if (pictureResult.data) {
|
|
2238
|
+
profilePicture = pictureResult.data;
|
|
2239
|
+
}
|
|
2240
|
+
} catch (error) {
|
|
2241
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2242
|
+
if (errorMessage !== "StoredDataNotFound") {
|
|
2243
|
+
throw error;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
let xUsername;
|
|
2247
|
+
try {
|
|
2248
|
+
const metadataResult = await client.readStorageData({
|
|
2249
|
+
key: PROFILE_METADATA_STORAGE_KEY,
|
|
2250
|
+
operator: options.address
|
|
2251
|
+
});
|
|
2252
|
+
if (metadataResult.data) {
|
|
2253
|
+
const metadata = parseProfileMetadata(metadataResult.data);
|
|
2254
|
+
xUsername = metadata?.x_username;
|
|
2255
|
+
}
|
|
2256
|
+
} catch (error) {
|
|
2257
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2258
|
+
if (errorMessage !== "StoredDataNotFound") {
|
|
2259
|
+
throw error;
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
const hasProfile = profilePicture || xUsername;
|
|
2263
|
+
if (options.json) {
|
|
2264
|
+
const output = {
|
|
2265
|
+
address: options.address,
|
|
2266
|
+
chainId: readOnlyOptions.chainId,
|
|
2267
|
+
profilePicture: profilePicture || null,
|
|
2268
|
+
xUsername: xUsername || null,
|
|
2269
|
+
hasProfile
|
|
2270
|
+
};
|
|
2271
|
+
console.log(JSON.stringify(output, null, 2));
|
|
2272
|
+
return;
|
|
2273
|
+
}
|
|
2274
|
+
console.log(chalk4.white.bold("\nProfile:\n"));
|
|
2275
|
+
console.log(` ${chalk4.cyan("Address:")} ${options.address}`);
|
|
2276
|
+
console.log(` ${chalk4.cyan("Chain ID:")} ${readOnlyOptions.chainId}`);
|
|
2277
|
+
console.log(
|
|
2278
|
+
` ${chalk4.cyan("Profile Picture:")} ${profilePicture || chalk4.gray("(not set)")}`
|
|
2279
|
+
);
|
|
2280
|
+
console.log(
|
|
2281
|
+
` ${chalk4.cyan("X Username:")} ${xUsername ? `@${xUsername}` : chalk4.gray("(not set)")}`
|
|
2282
|
+
);
|
|
2283
|
+
if (!hasProfile) {
|
|
2284
|
+
console.log(chalk4.yellow("\n No profile data found for this address."));
|
|
2285
|
+
}
|
|
2286
|
+
console.log();
|
|
2287
|
+
} catch (error) {
|
|
2288
|
+
exitWithError(
|
|
2289
|
+
`Failed to read profile: ${error instanceof Error ? error.message : String(error)}`
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
async function executeProfileSetPicture(options) {
|
|
2294
|
+
if (!isValidUrl(options.url)) {
|
|
2295
|
+
exitWithError(
|
|
2296
|
+
`Invalid URL: "${options.url}". Please provide a valid URL (e.g., https://example.com/image.jpg)`
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
const storageArgs = getProfilePictureStorageArgs(options.url);
|
|
2300
|
+
if (options.encodeOnly) {
|
|
2301
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
2302
|
+
chainId: options.chainId,
|
|
2303
|
+
rpcUrl: options.rpcUrl
|
|
2304
|
+
});
|
|
2305
|
+
const encoded = encodeTransaction(
|
|
2306
|
+
{
|
|
2307
|
+
to: STORAGE_CONTRACT.address,
|
|
2308
|
+
abi: STORAGE_CONTRACT.abi,
|
|
2309
|
+
functionName: "put",
|
|
2310
|
+
args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
|
|
2311
|
+
},
|
|
2312
|
+
readOnlyOptions.chainId
|
|
2313
|
+
);
|
|
2314
|
+
console.log(JSON.stringify(encoded, null, 2));
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
const commonOptions = parseCommonOptions({
|
|
2318
|
+
privateKey: options.privateKey,
|
|
2319
|
+
chainId: options.chainId,
|
|
2320
|
+
rpcUrl: options.rpcUrl
|
|
2321
|
+
});
|
|
2322
|
+
try {
|
|
2323
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
2324
|
+
const rpcUrls = getChainRpcUrls({
|
|
2325
|
+
chainId: commonOptions.chainId,
|
|
2326
|
+
rpcUrl: commonOptions.rpcUrl
|
|
2327
|
+
});
|
|
2328
|
+
const client = createWalletClient({
|
|
2329
|
+
account,
|
|
2330
|
+
chain: base,
|
|
2331
|
+
// TODO: Support other chains
|
|
2332
|
+
transport: http(rpcUrls[0])
|
|
2333
|
+
}).extend(publicActions);
|
|
2334
|
+
console.log(chalk4.blue(`\u{1F4F7} Setting profile picture...`));
|
|
2335
|
+
console.log(chalk4.gray(` URL: ${options.url}`));
|
|
2336
|
+
console.log(chalk4.gray(` Address: ${account.address}`));
|
|
2337
|
+
const hash = await client.writeContract({
|
|
2338
|
+
address: STORAGE_CONTRACT.address,
|
|
2339
|
+
abi: STORAGE_CONTRACT.abi,
|
|
2340
|
+
functionName: "put",
|
|
2341
|
+
args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
|
|
2342
|
+
});
|
|
2343
|
+
console.log(chalk4.blue(`\u23F3 Waiting for confirmation...`));
|
|
2344
|
+
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
2345
|
+
if (receipt.status === "success") {
|
|
2346
|
+
console.log(
|
|
2347
|
+
chalk4.green(
|
|
2348
|
+
`
|
|
2349
|
+
\u2713 Profile picture updated successfully!
|
|
2350
|
+
Transaction: ${hash}
|
|
2351
|
+
URL: ${options.url}`
|
|
2352
|
+
)
|
|
2353
|
+
);
|
|
2354
|
+
} else {
|
|
2355
|
+
exitWithError(`Transaction failed: ${hash}`);
|
|
2356
|
+
}
|
|
2357
|
+
} catch (error) {
|
|
2358
|
+
exitWithError(
|
|
2359
|
+
`Failed to set profile picture: ${error instanceof Error ? error.message : String(error)}`
|
|
2360
|
+
);
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
async function executeProfileSetUsername(options) {
|
|
2364
|
+
if (!isValidXUsername(options.username)) {
|
|
2365
|
+
exitWithError(
|
|
2366
|
+
`Invalid X username: "${options.username}". Usernames must be 1-15 characters, alphanumeric and underscores only.`
|
|
2367
|
+
);
|
|
2368
|
+
}
|
|
2369
|
+
const storageArgs = getXUsernameStorageArgs(options.username);
|
|
2370
|
+
const displayUsername = options.username.startsWith("@") ? options.username : `@${options.username}`;
|
|
2371
|
+
if (options.encodeOnly) {
|
|
2372
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
2373
|
+
chainId: options.chainId,
|
|
2374
|
+
rpcUrl: options.rpcUrl
|
|
2375
|
+
});
|
|
2376
|
+
const encoded = encodeTransaction(
|
|
2377
|
+
{
|
|
2378
|
+
to: STORAGE_CONTRACT.address,
|
|
2379
|
+
abi: STORAGE_CONTRACT.abi,
|
|
2380
|
+
functionName: "put",
|
|
2381
|
+
args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
|
|
2382
|
+
},
|
|
2383
|
+
readOnlyOptions.chainId
|
|
2384
|
+
);
|
|
2385
|
+
console.log(JSON.stringify(encoded, null, 2));
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2388
|
+
const commonOptions = parseCommonOptions({
|
|
2389
|
+
privateKey: options.privateKey,
|
|
2390
|
+
chainId: options.chainId,
|
|
2391
|
+
rpcUrl: options.rpcUrl
|
|
2392
|
+
});
|
|
2393
|
+
try {
|
|
2394
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
2395
|
+
const rpcUrls = getChainRpcUrls({
|
|
2396
|
+
chainId: commonOptions.chainId,
|
|
2397
|
+
rpcUrl: commonOptions.rpcUrl
|
|
2398
|
+
});
|
|
2399
|
+
const client = createWalletClient({
|
|
2400
|
+
account,
|
|
2401
|
+
chain: base,
|
|
2402
|
+
// TODO: Support other chains
|
|
2403
|
+
transport: http(rpcUrls[0])
|
|
2404
|
+
}).extend(publicActions);
|
|
2405
|
+
console.log(chalk4.blue(`\u{1F426} Setting X username...`));
|
|
2406
|
+
console.log(chalk4.gray(` Username: ${displayUsername}`));
|
|
2407
|
+
console.log(chalk4.gray(` Address: ${account.address}`));
|
|
2408
|
+
const hash = await client.writeContract({
|
|
2409
|
+
address: STORAGE_CONTRACT.address,
|
|
2410
|
+
abi: STORAGE_CONTRACT.abi,
|
|
2411
|
+
functionName: "put",
|
|
2412
|
+
args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
|
|
2413
|
+
});
|
|
2414
|
+
console.log(chalk4.blue(`\u23F3 Waiting for confirmation...`));
|
|
2415
|
+
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
2416
|
+
if (receipt.status === "success") {
|
|
2417
|
+
console.log(
|
|
2418
|
+
chalk4.green(
|
|
2419
|
+
`
|
|
2420
|
+
\u2713 X username updated successfully!
|
|
2421
|
+
Transaction: ${hash}
|
|
2422
|
+
Username: ${displayUsername}`
|
|
2423
|
+
)
|
|
2424
|
+
);
|
|
2425
|
+
} else {
|
|
2426
|
+
exitWithError(`Transaction failed: ${hash}`);
|
|
2427
|
+
}
|
|
2428
|
+
} catch (error) {
|
|
2429
|
+
exitWithError(
|
|
2430
|
+
`Failed to set X username: ${error instanceof Error ? error.message : String(error)}`
|
|
2431
|
+
);
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
// src/commands/profile/index.ts
|
|
2436
|
+
function registerProfileCommand(program2) {
|
|
2437
|
+
const profileCommand = program2.command("profile").description("User profile operations");
|
|
2438
|
+
const getCommand = new Command("get").description("Get profile data for an address").requiredOption("--address <address>", "Wallet address to get profile for").option(
|
|
2439
|
+
"--chain-id <id>",
|
|
2440
|
+
"Chain ID. Can also be set via NET_CHAIN_ID env var",
|
|
2441
|
+
(value) => parseInt(value, 10)
|
|
2442
|
+
).option(
|
|
2443
|
+
"--rpc-url <url>",
|
|
2444
|
+
"Custom RPC URL. Can also be set via NET_RPC_URL env var"
|
|
2445
|
+
).option("--json", "Output in JSON format").action(async (options) => {
|
|
2446
|
+
await executeProfileGet({
|
|
2447
|
+
address: options.address,
|
|
2448
|
+
chainId: options.chainId,
|
|
2449
|
+
rpcUrl: options.rpcUrl,
|
|
2450
|
+
json: options.json
|
|
2451
|
+
});
|
|
2452
|
+
});
|
|
2453
|
+
const setPictureCommand = new Command("set-picture").description("Set your profile picture URL").requiredOption("--url <url>", "Image URL for profile picture").option(
|
|
2454
|
+
"--private-key <key>",
|
|
2455
|
+
"Private key (0x-prefixed hex, 66 characters). Can also be set via NET_PRIVATE_KEY env var"
|
|
2456
|
+
).option(
|
|
2457
|
+
"--chain-id <id>",
|
|
2458
|
+
"Chain ID. Can also be set via NET_CHAIN_ID env var",
|
|
2459
|
+
(value) => parseInt(value, 10)
|
|
2460
|
+
).option(
|
|
2461
|
+
"--rpc-url <url>",
|
|
2462
|
+
"Custom RPC URL. Can also be set via NET_RPC_URL env var"
|
|
2463
|
+
).option(
|
|
2464
|
+
"--encode-only",
|
|
2465
|
+
"Output transaction data as JSON instead of executing"
|
|
2466
|
+
).action(async (options) => {
|
|
2467
|
+
await executeProfileSetPicture({
|
|
2468
|
+
url: options.url,
|
|
2469
|
+
privateKey: options.privateKey,
|
|
2470
|
+
chainId: options.chainId,
|
|
2471
|
+
rpcUrl: options.rpcUrl,
|
|
2472
|
+
encodeOnly: options.encodeOnly
|
|
2473
|
+
});
|
|
2474
|
+
});
|
|
2475
|
+
const setUsernameCommand = new Command("set-x-username").description("Set your X (Twitter) username for your profile").requiredOption(
|
|
2476
|
+
"--username <username>",
|
|
2477
|
+
"Your X (Twitter) username (with or without @)"
|
|
2478
|
+
).option(
|
|
2479
|
+
"--private-key <key>",
|
|
2480
|
+
"Private key (0x-prefixed hex, 66 characters). Can also be set via NET_PRIVATE_KEY env var"
|
|
2481
|
+
).option(
|
|
2482
|
+
"--chain-id <id>",
|
|
2483
|
+
"Chain ID. Can also be set via NET_CHAIN_ID env var",
|
|
2484
|
+
(value) => parseInt(value, 10)
|
|
2485
|
+
).option(
|
|
2486
|
+
"--rpc-url <url>",
|
|
2487
|
+
"Custom RPC URL. Can also be set via NET_RPC_URL env var"
|
|
2488
|
+
).option(
|
|
2489
|
+
"--encode-only",
|
|
2490
|
+
"Output transaction data as JSON instead of executing"
|
|
2491
|
+
).action(async (options) => {
|
|
2492
|
+
await executeProfileSetUsername({
|
|
2493
|
+
username: options.username,
|
|
2494
|
+
privateKey: options.privateKey,
|
|
2495
|
+
chainId: options.chainId,
|
|
2496
|
+
rpcUrl: options.rpcUrl,
|
|
2497
|
+
encodeOnly: options.encodeOnly
|
|
2498
|
+
});
|
|
2499
|
+
});
|
|
2500
|
+
profileCommand.addCommand(getCommand);
|
|
2501
|
+
profileCommand.addCommand(setPictureCommand);
|
|
2502
|
+
profileCommand.addCommand(setUsernameCommand);
|
|
2503
|
+
}
|
|
2218
2504
|
|
|
2219
2505
|
// src/cli/index.ts
|
|
2506
|
+
var require2 = createRequire(import.meta.url);
|
|
2507
|
+
var { version } = require2("../../package.json");
|
|
2220
2508
|
var program = new Command();
|
|
2221
|
-
program.name("netp").description("CLI tool for Net Protocol").version(
|
|
2509
|
+
program.name("netp").description("CLI tool for Net Protocol").version(version);
|
|
2222
2510
|
registerStorageCommand(program);
|
|
2223
2511
|
registerMessageCommand(program);
|
|
2224
2512
|
registerChainsCommand(program);
|
|
2225
2513
|
registerInfoCommand(program);
|
|
2226
2514
|
registerTokenCommand(program);
|
|
2515
|
+
registerProfileCommand(program);
|
|
2227
2516
|
program.parse();
|
|
2228
2517
|
//# sourceMappingURL=index.mjs.map
|
|
2229
2518
|
//# sourceMappingURL=index.mjs.map
|