@net-protocol/cli 0.1.40 → 0.1.42

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.
@@ -7,11 +7,11 @@ import chalk4 from 'chalk';
7
7
  import * as fs6 from 'fs';
8
8
  import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
9
9
  import { OPTIMAL_CHUNK_SIZE, StorageClient, detectFileTypeFromBase64, base64ToDataUri, shouldSuggestXmlStorage, getStorageKeyBytes, encodeStorageKeyForUrl, chunkDataForStorage, CHUNKED_STORAGE_CONTRACT, STORAGE_CONTRACT as STORAGE_CONTRACT$1 } from '@net-protocol/storage';
10
- import { stringToHex, createWalletClient, http, hexToString, parseEther, encodeFunctionData, publicActions, concat, defineChain, createPublicClient, formatEther } from 'viem';
10
+ import { stringToHex, createWalletClient, http, hexToString, parseEther, encodeFunctionData, publicActions, concat, defineChain, decodeEventLog, createPublicClient, formatEther } from 'viem';
11
11
  import { privateKeyToAccount } from 'viem/accounts';
12
12
  import { getNetContract, getChainName, getPublicClient, getChainRpcUrls, getBaseDataSuffix, NetClient, toBytes32, NULL_ADDRESS } from '@net-protocol/core';
13
13
  import { createRelayX402Client, createRelaySession, checkBackendWalletBalance, fundBackendWallet, batchTransactions, submitTransactionsViaRelay, waitForConfirmations, retryFailedTransactions as retryFailedTransactions$1 } from '@net-protocol/relay';
14
- import { FeedRegistryClient, FeedClient, AgentRegistryClient } from '@net-protocol/feeds';
14
+ import { isCommentTopic, parseCommentData, FeedRegistryClient, FeedClient, AgentRegistryClient, COMMENT_TOPIC_SUFFIX, FEED_TOPIC_PREFIX } from '@net-protocol/feeds';
15
15
  import '@net-protocol/chats';
16
16
  import { isNetrSupportedChain, NetrClient } from '@net-protocol/netr';
17
17
  import { PROFILE_PICTURE_STORAGE_KEY, PROFILE_METADATA_STORAGE_KEY, parseProfileMetadata, PROFILE_CANVAS_STORAGE_KEY, PROFILE_CSS_STORAGE_KEY, isValidUrl, getProfilePictureStorageArgs, STORAGE_CONTRACT, isValidXUsername, getProfileMetadataStorageArgs, isValidBio, isValidDisplayName, isValidTokenAddress, DEMO_THEMES, MAX_CSS_SIZE, isValidCSS, getProfileCSSStorageArgs, buildCSSPrompt } from '@net-protocol/profiles';
@@ -2369,6 +2369,7 @@ async function executeProfileGet(options) {
2369
2369
  }
2370
2370
  let xUsername;
2371
2371
  let bio;
2372
+ let displayName;
2372
2373
  let tokenAddress;
2373
2374
  try {
2374
2375
  const metadataResult = await client.readStorageData({
@@ -2379,6 +2380,7 @@ async function executeProfileGet(options) {
2379
2380
  const metadata = parseProfileMetadata(metadataResult.data);
2380
2381
  xUsername = metadata?.x_username;
2381
2382
  bio = metadata?.bio;
2383
+ displayName = metadata?.display_name;
2382
2384
  tokenAddress = metadata?.token_address;
2383
2385
  }
2384
2386
  } catch (error) {
@@ -2419,12 +2421,13 @@ async function executeProfileGet(options) {
2419
2421
  throw error;
2420
2422
  }
2421
2423
  }
2422
- const hasProfile = profilePicture || xUsername || bio || tokenAddress || canvasSize || cssSize;
2424
+ const hasProfile = profilePicture || xUsername || bio || displayName || tokenAddress || canvasSize || cssSize;
2423
2425
  if (options.json) {
2424
2426
  const output = {
2425
2427
  address: options.address,
2426
2428
  chainId: readOnlyOptions.chainId,
2427
2429
  profilePicture: profilePicture || null,
2430
+ displayName: displayName || null,
2428
2431
  xUsername: xUsername || null,
2429
2432
  bio: bio || null,
2430
2433
  tokenAddress: tokenAddress || null,
@@ -2438,6 +2441,9 @@ async function executeProfileGet(options) {
2438
2441
  console.log(chalk4.white.bold("\nProfile:\n"));
2439
2442
  console.log(` ${chalk4.cyan("Address:")} ${options.address}`);
2440
2443
  console.log(` ${chalk4.cyan("Chain ID:")} ${readOnlyOptions.chainId}`);
2444
+ console.log(
2445
+ ` ${chalk4.cyan("Display Name:")} ${displayName || chalk4.gray("(not set)")}`
2446
+ );
2441
2447
  console.log(
2442
2448
  ` ${chalk4.cyan("Profile Picture:")} ${profilePicture || chalk4.gray("(not set)")}`
2443
2449
  );
@@ -6169,6 +6175,9 @@ function registerFeedPostCommand(parent) {
6169
6175
  }
6170
6176
 
6171
6177
  // src/shared/postId.ts
6178
+ function createPostId(post) {
6179
+ return `${post.sender}:${post.timestamp}`;
6180
+ }
6172
6181
  function parsePostId(postId) {
6173
6182
  const parts = postId.split(":");
6174
6183
  if (parts.length !== 2) {
@@ -6993,6 +7002,143 @@ function registerListAgentsCommand(parent, commandName = "list-agents") {
6993
7002
  await executeListAgents(options);
6994
7003
  });
6995
7004
  }
7005
+ function extractFeedName(topic) {
7006
+ const baseTopic = isCommentTopic(topic) ? topic.split(COMMENT_TOPIC_SUFFIX)[0] : topic;
7007
+ return baseTopic.startsWith(FEED_TOPIC_PREFIX) ? baseTopic.slice(FEED_TOPIC_PREFIX.length) : baseTopic;
7008
+ }
7009
+ async function executeFeedVerifyClaim(txHash, options) {
7010
+ if (!txHash.startsWith("0x") || txHash.length !== 66) {
7011
+ exitWithError(
7012
+ "Invalid transaction hash format (must be 0x-prefixed, 66 characters)"
7013
+ );
7014
+ }
7015
+ const readOnlyOptions = parseReadOnlyOptionsWithDefault({
7016
+ chainId: options.chainId,
7017
+ rpcUrl: options.rpcUrl
7018
+ });
7019
+ const publicClient = getPublicClient({
7020
+ chainId: readOnlyOptions.chainId,
7021
+ rpcUrl: readOnlyOptions.rpcUrl
7022
+ });
7023
+ const netContract = getNetContract(readOnlyOptions.chainId);
7024
+ const netClient = createNetClient(readOnlyOptions);
7025
+ const existingHistory = getHistory();
7026
+ if (existingHistory.some((entry) => entry.txHash === txHash)) {
7027
+ console.log(
7028
+ chalk4.yellow("Transaction already recorded in history. Skipping.")
7029
+ );
7030
+ return;
7031
+ }
7032
+ const receipt = await publicClient.getTransactionReceipt({ hash: txHash }).catch(
7033
+ () => exitWithError(
7034
+ "Could not fetch transaction receipt. Make sure the transaction hash is correct and the transaction has been confirmed."
7035
+ )
7036
+ );
7037
+ const contractAddress = netContract.address.toLowerCase();
7038
+ const messageSentEvents = [];
7039
+ for (const log of receipt.logs) {
7040
+ if (log.address.toLowerCase() !== contractAddress) {
7041
+ continue;
7042
+ }
7043
+ try {
7044
+ const decoded = decodeEventLog({
7045
+ abi: netContract.abi,
7046
+ data: log.data,
7047
+ topics: log.topics
7048
+ });
7049
+ if (decoded.eventName === "MessageSent") {
7050
+ const args = decoded.args;
7051
+ messageSentEvents.push({
7052
+ sender: args.sender,
7053
+ messageIndex: args.messageIndex
7054
+ });
7055
+ }
7056
+ } catch {
7057
+ }
7058
+ }
7059
+ if (messageSentEvents.length === 0) {
7060
+ exitWithError(
7061
+ "Transaction does not contain any Net protocol messages."
7062
+ );
7063
+ }
7064
+ console.log(
7065
+ chalk4.blue(
7066
+ `Found ${messageSentEvents.length} message(s) in transaction. Fetching details...`
7067
+ )
7068
+ );
7069
+ const messages = await Promise.all(
7070
+ messageSentEvents.map(
7071
+ (event) => netClient.getMessageAtIndex({
7072
+ messageIndex: Number(event.messageIndex)
7073
+ })
7074
+ )
7075
+ );
7076
+ let recorded = 0;
7077
+ for (let i = 0; i < messages.length; i++) {
7078
+ const message = messages[i];
7079
+ if (!message) {
7080
+ console.log(
7081
+ chalk4.yellow(
7082
+ ` Could not fetch message at index ${messageSentEvents[i].messageIndex}. Skipping.`
7083
+ )
7084
+ );
7085
+ continue;
7086
+ }
7087
+ const feedName = extractFeedName(message.topic);
7088
+ const isComment = isCommentTopic(message.topic);
7089
+ let type;
7090
+ let postId;
7091
+ let label;
7092
+ if (isComment) {
7093
+ type = "comment";
7094
+ const commentData = parseCommentData(message.data);
7095
+ postId = commentData ? `${commentData.parentSender}:${commentData.parentTimestamp}` : void 0;
7096
+ label = `Verified comment:
7097
+ Feed: ${feedName}
7098
+ Sender: ${message.sender}
7099
+ Text: ${message.text}
7100
+ Parent post: ${postId ?? "unknown"}
7101
+ Tx: ${txHash}`;
7102
+ } else {
7103
+ type = "post";
7104
+ postId = createPostId(message);
7105
+ label = `Verified post:
7106
+ Feed: ${feedName}
7107
+ Sender: ${message.sender}
7108
+ Text: ${message.text}
7109
+ Post ID: ${postId}
7110
+ Tx: ${txHash}`;
7111
+ }
7112
+ addHistoryEntry({
7113
+ type,
7114
+ txHash,
7115
+ chainId: readOnlyOptions.chainId,
7116
+ feed: feedName,
7117
+ sender: message.sender,
7118
+ text: message.text,
7119
+ postId
7120
+ });
7121
+ console.log(chalk4.green(` ${label}`));
7122
+ recorded++;
7123
+ }
7124
+ if (recorded > 0) {
7125
+ console.log(
7126
+ chalk4.green(`
7127
+ Successfully recorded ${recorded} history entry(ies).`)
7128
+ );
7129
+ }
7130
+ }
7131
+ function registerFeedVerifyClaimCommand(parent) {
7132
+ parent.command("verify-claim <tx-hash>").description(
7133
+ "Verify a transaction and add it to history. Recovers post/comment details from on-chain data."
7134
+ ).option(
7135
+ "--chain-id <id>",
7136
+ "Chain ID (default: 8453 for Base)",
7137
+ (value) => parseInt(value, 10)
7138
+ ).option("--rpc-url <url>", "Custom RPC URL").action(async (txHash, options) => {
7139
+ await executeFeedVerifyClaim(txHash, options);
7140
+ });
7141
+ }
6996
7142
 
6997
7143
  // src/commands/feed/index.ts
6998
7144
  function registerFeedCommand(program2) {
@@ -7009,6 +7155,7 @@ function registerFeedCommand(program2) {
7009
7155
  registerFeedHistoryCommand(feedCommand);
7010
7156
  registerAgentRegisterCommand(feedCommand);
7011
7157
  registerListAgentsCommand(feedCommand);
7158
+ registerFeedVerifyClaimCommand(feedCommand);
7012
7159
  }
7013
7160
  async function executeUpvoteToken(options) {
7014
7161
  const count = parseInt(options.count, 10);