@net-protocol/cli 0.1.21 → 0.1.23

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 CHANGED
@@ -375,6 +375,7 @@ Profile operations for managing your Net Protocol profile.
375
375
  - `profile set-picture` - Set your profile picture URL
376
376
  - `profile set-x-username` - Set your X (Twitter) username
377
377
  - `profile set-bio` - Set your profile bio
378
+ - `profile set-display-name` - Set your profile display name
378
379
  - `profile set-token-address` - Set your profile token address (ERC-20 token)
379
380
  - `profile set-canvas` - Set your profile canvas (HTML content)
380
381
  - `profile get-canvas` - Get profile canvas for an address
@@ -527,6 +528,42 @@ netp profile set-bio \
527
528
  --encode-only
528
529
  ```
529
530
 
531
+ ##### Profile Set Display Name
532
+
533
+ Set your profile display name (max 25 characters).
534
+
535
+ ```bash
536
+ netp profile set-display-name \
537
+ --name <display-name> \
538
+ [--private-key <0x...>] \
539
+ [--chain-id <8453|1|...>] \
540
+ [--rpc-url <custom-rpc>] \
541
+ [--encode-only]
542
+ ```
543
+
544
+ **Profile Set Display Name Arguments:**
545
+
546
+ - `--name` (required): Your display name (max 25 characters, no control characters)
547
+ - `--private-key` (optional): Private key. Can also be set via `NET_PRIVATE_KEY` environment variable
548
+ - `--chain-id` (optional): Chain ID. Can also be set via `NET_CHAIN_ID` environment variable
549
+ - `--rpc-url` (optional): Custom RPC URL. Can also be set via `NET_RPC_URL` environment variable
550
+ - `--encode-only` (optional): Output transaction data as JSON instead of executing
551
+
552
+ **Example:**
553
+
554
+ ```bash
555
+ # Set display name
556
+ netp profile set-display-name \
557
+ --name "Alice" \
558
+ --chain-id 8453
559
+
560
+ # Encode-only
561
+ netp profile set-display-name \
562
+ --name "Alice" \
563
+ --chain-id 8453 \
564
+ --encode-only
565
+ ```
566
+
530
567
  ##### Profile Set Token Address
531
568
 
532
569
  Set an ERC-20 token address that represents you on your profile.
@@ -13,7 +13,7 @@ import { getNetContract, getChainName, getPublicClient, getChainRpcUrls, NetClie
13
13
  import { createRelayX402Client, createRelaySession, checkBackendWalletBalance, fundBackendWallet, batchTransactions, submitTransactionsViaRelay, waitForConfirmations, retryFailedTransactions as retryFailedTransactions$1 } from '@net-protocol/relay';
14
14
  import { FeedRegistryClient, FeedClient, AgentRegistryClient } from '@net-protocol/feeds';
15
15
  import { isNetrSupportedChain, NetrClient } from '@net-protocol/netr';
16
- import { PROFILE_PICTURE_STORAGE_KEY, PROFILE_METADATA_STORAGE_KEY, parseProfileMetadata, PROFILE_CANVAS_STORAGE_KEY, isValidUrl, getProfilePictureStorageArgs, STORAGE_CONTRACT, isValidXUsername, getProfileMetadataStorageArgs, isValidBio, isValidTokenAddress } from '@net-protocol/profiles';
16
+ import { PROFILE_PICTURE_STORAGE_KEY, PROFILE_METADATA_STORAGE_KEY, parseProfileMetadata, PROFILE_CANVAS_STORAGE_KEY, isValidUrl, getProfilePictureStorageArgs, STORAGE_CONTRACT, isValidXUsername, getProfileMetadataStorageArgs, isValidBio, isValidDisplayName, isValidTokenAddress } from '@net-protocol/profiles';
17
17
  import { base } from 'viem/chains';
18
18
  import * as path from 'path';
19
19
  import { BazaarClient } from '@net-protocol/bazaar';
@@ -1558,8 +1558,8 @@ function registerStorageCommand(program2) {
1558
1558
  console.log(chalk4.blue(`\u{1F4C1} Reading file: ${options.file}`));
1559
1559
  console.log(chalk4.blue(`\u{1F517} Using relay API: ${options.apiUrl}`));
1560
1560
  const result = await uploadFileWithRelay(uploadRelayOptions);
1561
- const { privateKeyToAccount: privateKeyToAccount24 } = await import('viem/accounts');
1562
- const userAccount = privateKeyToAccount24(commonOptions.privateKey);
1561
+ const { privateKeyToAccount: privateKeyToAccount25 } = await import('viem/accounts');
1562
+ const userAccount = privateKeyToAccount25(commonOptions.privateKey);
1563
1563
  const storageUrl = generateStorageUrl(
1564
1564
  userAccount.address,
1565
1565
  commonOptions.chainId,
@@ -2549,8 +2549,19 @@ async function executeProfileSetUsername(options) {
2549
2549
  chainId: options.chainId,
2550
2550
  rpcUrl: options.rpcUrl
2551
2551
  });
2552
+ let existing = {};
2553
+ if (options.address) {
2554
+ const storageClient = new StorageClient({
2555
+ chainId: readOnlyOptions.chainId,
2556
+ overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
2557
+ });
2558
+ existing = await readExistingMetadata(options.address, storageClient);
2559
+ }
2552
2560
  const storageArgs = getProfileMetadataStorageArgs({
2553
- x_username: usernameForStorage
2561
+ x_username: usernameForStorage,
2562
+ bio: existing.bio,
2563
+ display_name: existing.display_name,
2564
+ token_address: existing.token_address
2554
2565
  });
2555
2566
  const encoded = encodeTransaction(
2556
2567
  {
@@ -2639,7 +2650,20 @@ async function executeProfileSetBio(options) {
2639
2650
  chainId: options.chainId,
2640
2651
  rpcUrl: options.rpcUrl
2641
2652
  });
2642
- const storageArgs = getProfileMetadataStorageArgs({ bio: options.bio });
2653
+ let existing = {};
2654
+ if (options.address) {
2655
+ const storageClient = new StorageClient({
2656
+ chainId: readOnlyOptions.chainId,
2657
+ overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
2658
+ });
2659
+ existing = await readExistingMetadata(options.address, storageClient);
2660
+ }
2661
+ const storageArgs = getProfileMetadataStorageArgs({
2662
+ bio: options.bio,
2663
+ x_username: existing.x_username,
2664
+ display_name: existing.display_name,
2665
+ token_address: existing.token_address
2666
+ });
2643
2667
  const encoded = encodeTransaction(
2644
2668
  {
2645
2669
  to: STORAGE_CONTRACT.address,
@@ -2716,6 +2740,107 @@ Bio updated successfully!
2716
2740
  );
2717
2741
  }
2718
2742
  }
2743
+ async function executeProfileSetDisplayName(options) {
2744
+ if (!isValidDisplayName(options.name)) {
2745
+ exitWithError(
2746
+ `Invalid display name: "${options.name}". Display name must be 1-25 characters and cannot contain control characters.`
2747
+ );
2748
+ }
2749
+ if (options.encodeOnly) {
2750
+ const readOnlyOptions = parseReadOnlyOptions({
2751
+ chainId: options.chainId,
2752
+ rpcUrl: options.rpcUrl
2753
+ });
2754
+ let existing = {};
2755
+ if (options.address) {
2756
+ const storageClient = new StorageClient({
2757
+ chainId: readOnlyOptions.chainId,
2758
+ overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
2759
+ });
2760
+ existing = await readExistingMetadata(options.address, storageClient);
2761
+ }
2762
+ const storageArgs = getProfileMetadataStorageArgs({
2763
+ display_name: options.name,
2764
+ bio: existing.bio,
2765
+ x_username: existing.x_username,
2766
+ token_address: existing.token_address
2767
+ });
2768
+ const encoded = encodeTransaction(
2769
+ {
2770
+ to: STORAGE_CONTRACT.address,
2771
+ abi: STORAGE_CONTRACT.abi,
2772
+ functionName: "put",
2773
+ args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
2774
+ },
2775
+ readOnlyOptions.chainId
2776
+ );
2777
+ console.log(JSON.stringify(encoded, null, 2));
2778
+ return;
2779
+ }
2780
+ const commonOptions = parseCommonOptions(
2781
+ {
2782
+ privateKey: options.privateKey,
2783
+ chainId: options.chainId,
2784
+ rpcUrl: options.rpcUrl
2785
+ },
2786
+ true
2787
+ // supports --encode-only
2788
+ );
2789
+ try {
2790
+ const account = privateKeyToAccount(commonOptions.privateKey);
2791
+ const rpcUrls = getChainRpcUrls({
2792
+ chainId: commonOptions.chainId,
2793
+ rpcUrl: commonOptions.rpcUrl
2794
+ });
2795
+ const client = createWalletClient({
2796
+ account,
2797
+ chain: base,
2798
+ // TODO: Support other chains
2799
+ transport: http(rpcUrls[0])
2800
+ }).extend(publicActions);
2801
+ console.log(chalk4.blue(`Setting display name...`));
2802
+ console.log(chalk4.gray(` Name: ${options.name}`));
2803
+ console.log(chalk4.gray(` Address: ${account.address}`));
2804
+ const storageClient = new StorageClient({
2805
+ chainId: commonOptions.chainId,
2806
+ overrides: commonOptions.rpcUrl ? { rpcUrls: [commonOptions.rpcUrl] } : void 0
2807
+ });
2808
+ const existing = await readExistingMetadata(
2809
+ account.address,
2810
+ storageClient
2811
+ );
2812
+ const storageArgs = getProfileMetadataStorageArgs({
2813
+ display_name: options.name,
2814
+ bio: existing.bio,
2815
+ x_username: existing.x_username,
2816
+ token_address: existing.token_address
2817
+ });
2818
+ const hash = await client.writeContract({
2819
+ address: STORAGE_CONTRACT.address,
2820
+ abi: STORAGE_CONTRACT.abi,
2821
+ functionName: "put",
2822
+ args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
2823
+ });
2824
+ console.log(chalk4.blue(`Waiting for confirmation...`));
2825
+ const receipt = await client.waitForTransactionReceipt({ hash });
2826
+ if (receipt.status === "success") {
2827
+ console.log(
2828
+ chalk4.green(
2829
+ `
2830
+ Display name updated successfully!
2831
+ Transaction: ${hash}
2832
+ Name: ${options.name}`
2833
+ )
2834
+ );
2835
+ } else {
2836
+ exitWithError(`Transaction failed: ${hash}`);
2837
+ }
2838
+ } catch (error) {
2839
+ exitWithError(
2840
+ `Failed to set display name: ${error instanceof Error ? error.message : String(error)}`
2841
+ );
2842
+ }
2843
+ }
2719
2844
  async function executeProfileSetTokenAddress(options) {
2720
2845
  if (!isValidTokenAddress(options.tokenAddress)) {
2721
2846
  exitWithError(
@@ -2728,8 +2853,19 @@ async function executeProfileSetTokenAddress(options) {
2728
2853
  chainId: options.chainId,
2729
2854
  rpcUrl: options.rpcUrl
2730
2855
  });
2856
+ let existing = {};
2857
+ if (options.address) {
2858
+ const storageClient = new StorageClient({
2859
+ chainId: readOnlyOptions.chainId,
2860
+ overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
2861
+ });
2862
+ existing = await readExistingMetadata(options.address, storageClient);
2863
+ }
2731
2864
  const storageArgs = getProfileMetadataStorageArgs({
2732
- token_address: normalizedAddress
2865
+ token_address: normalizedAddress,
2866
+ x_username: existing.x_username,
2867
+ bio: existing.bio,
2868
+ display_name: existing.display_name
2733
2869
  });
2734
2870
  const encoded = encodeTransaction(
2735
2871
  {
@@ -3109,13 +3245,17 @@ function registerProfileCommand(program2) {
3109
3245
  ).option(
3110
3246
  "--encode-only",
3111
3247
  "Output transaction data as JSON instead of executing"
3248
+ ).option(
3249
+ "--address <address>",
3250
+ "Wallet address to preserve existing metadata for (used with --encode-only)"
3112
3251
  ).action(async (options) => {
3113
3252
  await executeProfileSetUsername({
3114
3253
  username: options.username,
3115
3254
  privateKey: options.privateKey,
3116
3255
  chainId: options.chainId,
3117
3256
  rpcUrl: options.rpcUrl,
3118
- encodeOnly: options.encodeOnly
3257
+ encodeOnly: options.encodeOnly,
3258
+ address: options.address
3119
3259
  });
3120
3260
  });
3121
3261
  const setBioCommand = new Command("set-bio").description("Set your profile bio").requiredOption("--bio <bio>", "Your profile bio (max 280 characters)").option(
@@ -3131,13 +3271,43 @@ function registerProfileCommand(program2) {
3131
3271
  ).option(
3132
3272
  "--encode-only",
3133
3273
  "Output transaction data as JSON instead of executing"
3274
+ ).option(
3275
+ "--address <address>",
3276
+ "Wallet address to preserve existing metadata for (used with --encode-only)"
3134
3277
  ).action(async (options) => {
3135
3278
  await executeProfileSetBio({
3136
3279
  bio: options.bio,
3137
3280
  privateKey: options.privateKey,
3138
3281
  chainId: options.chainId,
3139
3282
  rpcUrl: options.rpcUrl,
3140
- encodeOnly: options.encodeOnly
3283
+ encodeOnly: options.encodeOnly,
3284
+ address: options.address
3285
+ });
3286
+ });
3287
+ const setDisplayNameCommand = new Command("set-display-name").description("Set your profile display name").requiredOption("--name <name>", "Your display name (max 25 characters)").option(
3288
+ "--private-key <key>",
3289
+ "Private key (0x-prefixed hex, 66 characters). Can also be set via NET_PRIVATE_KEY env var"
3290
+ ).option(
3291
+ "--chain-id <id>",
3292
+ "Chain ID. Can also be set via NET_CHAIN_ID env var",
3293
+ (value) => parseInt(value, 10)
3294
+ ).option(
3295
+ "--rpc-url <url>",
3296
+ "Custom RPC URL. Can also be set via NET_RPC_URL env var"
3297
+ ).option(
3298
+ "--encode-only",
3299
+ "Output transaction data as JSON instead of executing"
3300
+ ).option(
3301
+ "--address <address>",
3302
+ "Wallet address to preserve existing metadata for (used with --encode-only)"
3303
+ ).action(async (options) => {
3304
+ await executeProfileSetDisplayName({
3305
+ name: options.name,
3306
+ privateKey: options.privateKey,
3307
+ chainId: options.chainId,
3308
+ rpcUrl: options.rpcUrl,
3309
+ encodeOnly: options.encodeOnly,
3310
+ address: options.address
3141
3311
  });
3142
3312
  });
3143
3313
  const setTokenAddressCommand = new Command("set-token-address").description("Set your profile token address (ERC-20 token that represents you)").requiredOption(
@@ -3156,13 +3326,17 @@ function registerProfileCommand(program2) {
3156
3326
  ).option(
3157
3327
  "--encode-only",
3158
3328
  "Output transaction data as JSON instead of executing"
3329
+ ).option(
3330
+ "--address <address>",
3331
+ "Wallet address to preserve existing metadata for (used with --encode-only)"
3159
3332
  ).action(async (options) => {
3160
3333
  await executeProfileSetTokenAddress({
3161
3334
  tokenAddress: options.tokenAddress,
3162
3335
  privateKey: options.privateKey,
3163
3336
  chainId: options.chainId,
3164
3337
  rpcUrl: options.rpcUrl,
3165
- encodeOnly: options.encodeOnly
3338
+ encodeOnly: options.encodeOnly,
3339
+ address: options.address
3166
3340
  });
3167
3341
  });
3168
3342
  const setCanvasCommand = new Command("set-canvas").description("Set your profile canvas (HTML content)").option("--file <path>", "Path to file containing canvas content").option("--content <html>", "HTML content for canvas (inline)").option(
@@ -3208,6 +3382,7 @@ function registerProfileCommand(program2) {
3208
3382
  profileCommand.addCommand(setPictureCommand);
3209
3383
  profileCommand.addCommand(setUsernameCommand);
3210
3384
  profileCommand.addCommand(setBioCommand);
3385
+ profileCommand.addCommand(setDisplayNameCommand);
3211
3386
  profileCommand.addCommand(setTokenAddressCommand);
3212
3387
  profileCommand.addCommand(setCanvasCommand);
3213
3388
  profileCommand.addCommand(getCanvasCommand);