@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 +37 -0
- package/dist/cli/index.mjs +184 -9
- package/dist/cli/index.mjs.map +1 -1
- package/dist/profile/index.mjs +182 -7
- package/dist/profile/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/profile/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import chalk3 from 'chalk';
|
|
3
3
|
import { StorageClient, chunkDataForStorage, CHUNKED_STORAGE_CONTRACT } from '@net-protocol/storage';
|
|
4
|
-
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';
|
|
4
|
+
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';
|
|
5
5
|
import { createWalletClient, http, publicActions, encodeFunctionData } from 'viem';
|
|
6
6
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
7
7
|
import { base } from 'viem/chains';
|
|
@@ -301,8 +301,19 @@ async function executeProfileSetUsername(options) {
|
|
|
301
301
|
chainId: options.chainId,
|
|
302
302
|
rpcUrl: options.rpcUrl
|
|
303
303
|
});
|
|
304
|
+
let existing = {};
|
|
305
|
+
if (options.address) {
|
|
306
|
+
const storageClient = new StorageClient({
|
|
307
|
+
chainId: readOnlyOptions.chainId,
|
|
308
|
+
overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
|
|
309
|
+
});
|
|
310
|
+
existing = await readExistingMetadata(options.address, storageClient);
|
|
311
|
+
}
|
|
304
312
|
const storageArgs = getProfileMetadataStorageArgs({
|
|
305
|
-
x_username: usernameForStorage
|
|
313
|
+
x_username: usernameForStorage,
|
|
314
|
+
bio: existing.bio,
|
|
315
|
+
display_name: existing.display_name,
|
|
316
|
+
token_address: existing.token_address
|
|
306
317
|
});
|
|
307
318
|
const encoded = encodeTransaction(
|
|
308
319
|
{
|
|
@@ -391,7 +402,20 @@ async function executeProfileSetBio(options) {
|
|
|
391
402
|
chainId: options.chainId,
|
|
392
403
|
rpcUrl: options.rpcUrl
|
|
393
404
|
});
|
|
394
|
-
|
|
405
|
+
let existing = {};
|
|
406
|
+
if (options.address) {
|
|
407
|
+
const storageClient = new StorageClient({
|
|
408
|
+
chainId: readOnlyOptions.chainId,
|
|
409
|
+
overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
|
|
410
|
+
});
|
|
411
|
+
existing = await readExistingMetadata(options.address, storageClient);
|
|
412
|
+
}
|
|
413
|
+
const storageArgs = getProfileMetadataStorageArgs({
|
|
414
|
+
bio: options.bio,
|
|
415
|
+
x_username: existing.x_username,
|
|
416
|
+
display_name: existing.display_name,
|
|
417
|
+
token_address: existing.token_address
|
|
418
|
+
});
|
|
395
419
|
const encoded = encodeTransaction(
|
|
396
420
|
{
|
|
397
421
|
to: STORAGE_CONTRACT.address,
|
|
@@ -468,6 +492,107 @@ Bio updated successfully!
|
|
|
468
492
|
);
|
|
469
493
|
}
|
|
470
494
|
}
|
|
495
|
+
async function executeProfileSetDisplayName(options) {
|
|
496
|
+
if (!isValidDisplayName(options.name)) {
|
|
497
|
+
exitWithError(
|
|
498
|
+
`Invalid display name: "${options.name}". Display name must be 1-25 characters and cannot contain control characters.`
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
if (options.encodeOnly) {
|
|
502
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
503
|
+
chainId: options.chainId,
|
|
504
|
+
rpcUrl: options.rpcUrl
|
|
505
|
+
});
|
|
506
|
+
let existing = {};
|
|
507
|
+
if (options.address) {
|
|
508
|
+
const storageClient = new StorageClient({
|
|
509
|
+
chainId: readOnlyOptions.chainId,
|
|
510
|
+
overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
|
|
511
|
+
});
|
|
512
|
+
existing = await readExistingMetadata(options.address, storageClient);
|
|
513
|
+
}
|
|
514
|
+
const storageArgs = getProfileMetadataStorageArgs({
|
|
515
|
+
display_name: options.name,
|
|
516
|
+
bio: existing.bio,
|
|
517
|
+
x_username: existing.x_username,
|
|
518
|
+
token_address: existing.token_address
|
|
519
|
+
});
|
|
520
|
+
const encoded = encodeTransaction(
|
|
521
|
+
{
|
|
522
|
+
to: STORAGE_CONTRACT.address,
|
|
523
|
+
abi: STORAGE_CONTRACT.abi,
|
|
524
|
+
functionName: "put",
|
|
525
|
+
args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
|
|
526
|
+
},
|
|
527
|
+
readOnlyOptions.chainId
|
|
528
|
+
);
|
|
529
|
+
console.log(JSON.stringify(encoded, null, 2));
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
const commonOptions = parseCommonOptions(
|
|
533
|
+
{
|
|
534
|
+
privateKey: options.privateKey,
|
|
535
|
+
chainId: options.chainId,
|
|
536
|
+
rpcUrl: options.rpcUrl
|
|
537
|
+
},
|
|
538
|
+
true
|
|
539
|
+
// supports --encode-only
|
|
540
|
+
);
|
|
541
|
+
try {
|
|
542
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
543
|
+
const rpcUrls = getChainRpcUrls({
|
|
544
|
+
chainId: commonOptions.chainId,
|
|
545
|
+
rpcUrl: commonOptions.rpcUrl
|
|
546
|
+
});
|
|
547
|
+
const client = createWalletClient({
|
|
548
|
+
account,
|
|
549
|
+
chain: base,
|
|
550
|
+
// TODO: Support other chains
|
|
551
|
+
transport: http(rpcUrls[0])
|
|
552
|
+
}).extend(publicActions);
|
|
553
|
+
console.log(chalk3.blue(`Setting display name...`));
|
|
554
|
+
console.log(chalk3.gray(` Name: ${options.name}`));
|
|
555
|
+
console.log(chalk3.gray(` Address: ${account.address}`));
|
|
556
|
+
const storageClient = new StorageClient({
|
|
557
|
+
chainId: commonOptions.chainId,
|
|
558
|
+
overrides: commonOptions.rpcUrl ? { rpcUrls: [commonOptions.rpcUrl] } : void 0
|
|
559
|
+
});
|
|
560
|
+
const existing = await readExistingMetadata(
|
|
561
|
+
account.address,
|
|
562
|
+
storageClient
|
|
563
|
+
);
|
|
564
|
+
const storageArgs = getProfileMetadataStorageArgs({
|
|
565
|
+
display_name: options.name,
|
|
566
|
+
bio: existing.bio,
|
|
567
|
+
x_username: existing.x_username,
|
|
568
|
+
token_address: existing.token_address
|
|
569
|
+
});
|
|
570
|
+
const hash = await client.writeContract({
|
|
571
|
+
address: STORAGE_CONTRACT.address,
|
|
572
|
+
abi: STORAGE_CONTRACT.abi,
|
|
573
|
+
functionName: "put",
|
|
574
|
+
args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
|
|
575
|
+
});
|
|
576
|
+
console.log(chalk3.blue(`Waiting for confirmation...`));
|
|
577
|
+
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
578
|
+
if (receipt.status === "success") {
|
|
579
|
+
console.log(
|
|
580
|
+
chalk3.green(
|
|
581
|
+
`
|
|
582
|
+
Display name updated successfully!
|
|
583
|
+
Transaction: ${hash}
|
|
584
|
+
Name: ${options.name}`
|
|
585
|
+
)
|
|
586
|
+
);
|
|
587
|
+
} else {
|
|
588
|
+
exitWithError(`Transaction failed: ${hash}`);
|
|
589
|
+
}
|
|
590
|
+
} catch (error) {
|
|
591
|
+
exitWithError(
|
|
592
|
+
`Failed to set display name: ${error instanceof Error ? error.message : String(error)}`
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
471
596
|
async function executeProfileSetTokenAddress(options) {
|
|
472
597
|
if (!isValidTokenAddress(options.tokenAddress)) {
|
|
473
598
|
exitWithError(
|
|
@@ -480,8 +605,19 @@ async function executeProfileSetTokenAddress(options) {
|
|
|
480
605
|
chainId: options.chainId,
|
|
481
606
|
rpcUrl: options.rpcUrl
|
|
482
607
|
});
|
|
608
|
+
let existing = {};
|
|
609
|
+
if (options.address) {
|
|
610
|
+
const storageClient = new StorageClient({
|
|
611
|
+
chainId: readOnlyOptions.chainId,
|
|
612
|
+
overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
|
|
613
|
+
});
|
|
614
|
+
existing = await readExistingMetadata(options.address, storageClient);
|
|
615
|
+
}
|
|
483
616
|
const storageArgs = getProfileMetadataStorageArgs({
|
|
484
|
-
token_address: normalizedAddress
|
|
617
|
+
token_address: normalizedAddress,
|
|
618
|
+
x_username: existing.x_username,
|
|
619
|
+
bio: existing.bio,
|
|
620
|
+
display_name: existing.display_name
|
|
485
621
|
});
|
|
486
622
|
const encoded = encodeTransaction(
|
|
487
623
|
{
|
|
@@ -861,13 +997,17 @@ function registerProfileCommand(program) {
|
|
|
861
997
|
).option(
|
|
862
998
|
"--encode-only",
|
|
863
999
|
"Output transaction data as JSON instead of executing"
|
|
1000
|
+
).option(
|
|
1001
|
+
"--address <address>",
|
|
1002
|
+
"Wallet address to preserve existing metadata for (used with --encode-only)"
|
|
864
1003
|
).action(async (options) => {
|
|
865
1004
|
await executeProfileSetUsername({
|
|
866
1005
|
username: options.username,
|
|
867
1006
|
privateKey: options.privateKey,
|
|
868
1007
|
chainId: options.chainId,
|
|
869
1008
|
rpcUrl: options.rpcUrl,
|
|
870
|
-
encodeOnly: options.encodeOnly
|
|
1009
|
+
encodeOnly: options.encodeOnly,
|
|
1010
|
+
address: options.address
|
|
871
1011
|
});
|
|
872
1012
|
});
|
|
873
1013
|
const setBioCommand = new Command("set-bio").description("Set your profile bio").requiredOption("--bio <bio>", "Your profile bio (max 280 characters)").option(
|
|
@@ -883,13 +1023,43 @@ function registerProfileCommand(program) {
|
|
|
883
1023
|
).option(
|
|
884
1024
|
"--encode-only",
|
|
885
1025
|
"Output transaction data as JSON instead of executing"
|
|
1026
|
+
).option(
|
|
1027
|
+
"--address <address>",
|
|
1028
|
+
"Wallet address to preserve existing metadata for (used with --encode-only)"
|
|
886
1029
|
).action(async (options) => {
|
|
887
1030
|
await executeProfileSetBio({
|
|
888
1031
|
bio: options.bio,
|
|
889
1032
|
privateKey: options.privateKey,
|
|
890
1033
|
chainId: options.chainId,
|
|
891
1034
|
rpcUrl: options.rpcUrl,
|
|
892
|
-
encodeOnly: options.encodeOnly
|
|
1035
|
+
encodeOnly: options.encodeOnly,
|
|
1036
|
+
address: options.address
|
|
1037
|
+
});
|
|
1038
|
+
});
|
|
1039
|
+
const setDisplayNameCommand = new Command("set-display-name").description("Set your profile display name").requiredOption("--name <name>", "Your display name (max 25 characters)").option(
|
|
1040
|
+
"--private-key <key>",
|
|
1041
|
+
"Private key (0x-prefixed hex, 66 characters). Can also be set via NET_PRIVATE_KEY env var"
|
|
1042
|
+
).option(
|
|
1043
|
+
"--chain-id <id>",
|
|
1044
|
+
"Chain ID. Can also be set via NET_CHAIN_ID env var",
|
|
1045
|
+
(value) => parseInt(value, 10)
|
|
1046
|
+
).option(
|
|
1047
|
+
"--rpc-url <url>",
|
|
1048
|
+
"Custom RPC URL. Can also be set via NET_RPC_URL env var"
|
|
1049
|
+
).option(
|
|
1050
|
+
"--encode-only",
|
|
1051
|
+
"Output transaction data as JSON instead of executing"
|
|
1052
|
+
).option(
|
|
1053
|
+
"--address <address>",
|
|
1054
|
+
"Wallet address to preserve existing metadata for (used with --encode-only)"
|
|
1055
|
+
).action(async (options) => {
|
|
1056
|
+
await executeProfileSetDisplayName({
|
|
1057
|
+
name: options.name,
|
|
1058
|
+
privateKey: options.privateKey,
|
|
1059
|
+
chainId: options.chainId,
|
|
1060
|
+
rpcUrl: options.rpcUrl,
|
|
1061
|
+
encodeOnly: options.encodeOnly,
|
|
1062
|
+
address: options.address
|
|
893
1063
|
});
|
|
894
1064
|
});
|
|
895
1065
|
const setTokenAddressCommand = new Command("set-token-address").description("Set your profile token address (ERC-20 token that represents you)").requiredOption(
|
|
@@ -908,13 +1078,17 @@ function registerProfileCommand(program) {
|
|
|
908
1078
|
).option(
|
|
909
1079
|
"--encode-only",
|
|
910
1080
|
"Output transaction data as JSON instead of executing"
|
|
1081
|
+
).option(
|
|
1082
|
+
"--address <address>",
|
|
1083
|
+
"Wallet address to preserve existing metadata for (used with --encode-only)"
|
|
911
1084
|
).action(async (options) => {
|
|
912
1085
|
await executeProfileSetTokenAddress({
|
|
913
1086
|
tokenAddress: options.tokenAddress,
|
|
914
1087
|
privateKey: options.privateKey,
|
|
915
1088
|
chainId: options.chainId,
|
|
916
1089
|
rpcUrl: options.rpcUrl,
|
|
917
|
-
encodeOnly: options.encodeOnly
|
|
1090
|
+
encodeOnly: options.encodeOnly,
|
|
1091
|
+
address: options.address
|
|
918
1092
|
});
|
|
919
1093
|
});
|
|
920
1094
|
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(
|
|
@@ -960,6 +1134,7 @@ function registerProfileCommand(program) {
|
|
|
960
1134
|
profileCommand.addCommand(setPictureCommand);
|
|
961
1135
|
profileCommand.addCommand(setUsernameCommand);
|
|
962
1136
|
profileCommand.addCommand(setBioCommand);
|
|
1137
|
+
profileCommand.addCommand(setDisplayNameCommand);
|
|
963
1138
|
profileCommand.addCommand(setTokenAddressCommand);
|
|
964
1139
|
profileCommand.addCommand(setCanvasCommand);
|
|
965
1140
|
profileCommand.addCommand(getCanvasCommand);
|