@net-protocol/cli 0.1.0 → 0.1.1

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.
@@ -1,19 +1,36 @@
1
1
  #!/usr/bin/env node
2
2
  import 'dotenv/config';
3
3
  import { Command } from 'commander';
4
- import chalk2 from 'chalk';
4
+ import chalk4 from 'chalk';
5
+ import * as fs from 'fs';
5
6
  import { readFileSync } from 'fs';
6
- import { detectFileTypeFromBase64, base64ToDataUri, StorageClient, shouldSuggestXmlStorage, getStorageKeyBytes, encodeStorageKeyForUrl, STORAGE_CONTRACT, CHUNKED_STORAGE_CONTRACT } from '@net-protocol/storage';
7
- import { stringToHex, createWalletClient, http, hexToString, defineChain } from 'viem';
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
9
  import { privateKeyToAccount } from 'viem/accounts';
9
- import { getPublicClient, getChainRpcUrls } from '@net-protocol/core';
10
+ import { getNetContract, getChainName, getPublicClient, getChainRpcUrls, NetClient } from '@net-protocol/core';
10
11
  import { createRelayX402Client, createRelaySession, checkBackendWalletBalance, fundBackendWallet, batchTransactions, submitTransactionsViaRelay, waitForConfirmations, retryFailedTransactions as retryFailedTransactions$1 } from '@net-protocol/relay';
12
+ import { isNetrSupportedChain, NetrClient } from '@net-protocol/netr';
11
13
 
14
+ function getRequiredChainId(optionValue) {
15
+ const chainId = optionValue || (process.env.NET_CHAIN_ID ? parseInt(process.env.NET_CHAIN_ID, 10) : void 0);
16
+ if (!chainId) {
17
+ console.error(
18
+ chalk4.red(
19
+ "Error: Chain ID is required. Provide via --chain-id flag or NET_CHAIN_ID environment variable"
20
+ )
21
+ );
22
+ process.exit(1);
23
+ }
24
+ return chainId;
25
+ }
26
+ function getRpcUrl(optionValue) {
27
+ return optionValue || process.env.NET_RPC_URL;
28
+ }
12
29
  function parseCommonOptions(options) {
13
30
  const privateKey = options.privateKey || process.env.NET_PRIVATE_KEY || process.env.PRIVATE_KEY;
14
31
  if (!privateKey) {
15
32
  console.error(
16
- chalk2.red(
33
+ chalk4.red(
17
34
  "Error: Private key is required. Provide via --private-key flag or NET_PRIVATE_KEY/PRIVATE_KEY environment variable"
18
35
  )
19
36
  );
@@ -21,7 +38,7 @@ function parseCommonOptions(options) {
21
38
  }
22
39
  if (!privateKey.startsWith("0x") || privateKey.length !== 66) {
23
40
  console.error(
24
- chalk2.red(
41
+ chalk4.red(
25
42
  "Error: Invalid private key format (must be 0x-prefixed, 66 characters)"
26
43
  )
27
44
  );
@@ -29,25 +46,21 @@ function parseCommonOptions(options) {
29
46
  }
30
47
  if (options.privateKey) {
31
48
  console.warn(
32
- chalk2.yellow(
33
- "\u26A0\uFE0F Warning: Private key provided via command line. Consider using NET_PRIVATE_KEY environment variable instead."
49
+ chalk4.yellow(
50
+ "Warning: Private key provided via command line. Consider using NET_PRIVATE_KEY environment variable instead."
34
51
  )
35
52
  );
36
53
  }
37
- const chainId = options.chainId || (process.env.NET_CHAIN_ID ? parseInt(process.env.NET_CHAIN_ID, 10) : void 0);
38
- if (!chainId) {
39
- console.error(
40
- chalk2.red(
41
- "Error: Chain ID is required. Provide via --chain-id flag or NET_CHAIN_ID environment variable"
42
- )
43
- );
44
- process.exit(1);
45
- }
46
- const rpcUrl = options.rpcUrl || process.env.NET_RPC_URL;
47
54
  return {
48
55
  privateKey,
49
- chainId,
50
- rpcUrl
56
+ chainId: getRequiredChainId(options.chainId),
57
+ rpcUrl: getRpcUrl(options.rpcUrl)
58
+ };
59
+ }
60
+ function parseReadOnlyOptions(options) {
61
+ return {
62
+ chainId: getRequiredChainId(options.chainId),
63
+ rpcUrl: getRpcUrl(options.rpcUrl)
51
64
  };
52
65
  }
53
66
  async function checkNormalStorageExists(params) {
@@ -1019,6 +1032,202 @@ async function previewFile(options) {
1019
1032
  };
1020
1033
  }
1021
1034
  }
1035
+ function formatMessage(message, index) {
1036
+ const timestamp = new Date(Number(message.timestamp) * 1e3).toISOString();
1037
+ const lines = [
1038
+ chalk4.cyan(`[${index}]`) + ` ${chalk4.gray(timestamp)}`,
1039
+ ` ${chalk4.white("Sender:")} ${message.sender}`,
1040
+ ` ${chalk4.white("App:")} ${message.app}`
1041
+ ];
1042
+ if (message.topic) {
1043
+ lines.push(` ${chalk4.white("Topic:")} ${message.topic}`);
1044
+ }
1045
+ lines.push(` ${chalk4.white("Text:")} ${message.text}`);
1046
+ if (message.data && message.data !== "0x") {
1047
+ lines.push(` ${chalk4.white("Data:")} ${message.data}`);
1048
+ }
1049
+ return lines.join("\n");
1050
+ }
1051
+ function messageToJson(message, index) {
1052
+ return {
1053
+ index,
1054
+ sender: message.sender,
1055
+ app: message.app,
1056
+ timestamp: Number(message.timestamp),
1057
+ text: message.text,
1058
+ topic: message.topic,
1059
+ data: message.data
1060
+ };
1061
+ }
1062
+ function printMessages(messages, startIndex, json) {
1063
+ if (json) {
1064
+ const output = messages.map((msg, i) => messageToJson(msg, startIndex + i));
1065
+ console.log(JSON.stringify(output, null, 2));
1066
+ } else {
1067
+ if (messages.length === 0) {
1068
+ console.log(chalk4.yellow("No messages found"));
1069
+ return;
1070
+ }
1071
+ messages.forEach((msg, i) => {
1072
+ console.log(formatMessage(msg, startIndex + i));
1073
+ if (i < messages.length - 1) {
1074
+ console.log();
1075
+ }
1076
+ });
1077
+ }
1078
+ }
1079
+ function printCount(count, label, json) {
1080
+ if (json) {
1081
+ console.log(JSON.stringify({ count }, null, 2));
1082
+ } else {
1083
+ console.log(`${chalk4.white(label)} ${chalk4.cyan(count)}`);
1084
+ }
1085
+ }
1086
+ function exitWithError(message) {
1087
+ console.error(chalk4.red(`Error: ${message}`));
1088
+ process.exit(1);
1089
+ }
1090
+
1091
+ // src/commands/storage/core/read.ts
1092
+ async function executeStorageRead(options) {
1093
+ const readOnlyOptions = parseReadOnlyOptions({
1094
+ chainId: options.chainId,
1095
+ rpcUrl: options.rpcUrl
1096
+ });
1097
+ const client = new StorageClient({
1098
+ chainId: readOnlyOptions.chainId,
1099
+ overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
1100
+ });
1101
+ try {
1102
+ const result = await client.readStorageData({
1103
+ key: options.key,
1104
+ operator: options.operator,
1105
+ index: options.index
1106
+ });
1107
+ if (options.json) {
1108
+ const output = {
1109
+ key: options.key,
1110
+ operator: options.operator,
1111
+ chainId: readOnlyOptions.chainId,
1112
+ text: result.text,
1113
+ data: options.raw ? result.data : result.data,
1114
+ isXml: result.isXml,
1115
+ ...options.index !== void 0 && { index: options.index }
1116
+ };
1117
+ console.log(JSON.stringify(output, null, 2));
1118
+ return;
1119
+ }
1120
+ console.log(chalk4.white.bold("\nStorage Value:\n"));
1121
+ console.log(` ${chalk4.cyan("Key:")} ${options.key}`);
1122
+ console.log(` ${chalk4.cyan("Operator:")} ${options.operator}`);
1123
+ console.log(` ${chalk4.cyan("Chain ID:")} ${readOnlyOptions.chainId}`);
1124
+ if (options.index !== void 0) {
1125
+ console.log(` ${chalk4.cyan("Index:")} ${options.index}`);
1126
+ }
1127
+ console.log(` ${chalk4.cyan("Text:")} ${result.text || "(empty)"}`);
1128
+ console.log(` ${chalk4.cyan("Is XML:")} ${result.isXml ? "Yes" : "No"}`);
1129
+ const dataPreview = result.data.length > 500 ? result.data.substring(0, 500) + "... (truncated)" : result.data;
1130
+ console.log(` ${chalk4.cyan("Data:")}`);
1131
+ if (result.data) {
1132
+ console.log(chalk4.gray(` ${dataPreview.split("\n").join("\n ")}`));
1133
+ } else {
1134
+ console.log(chalk4.gray(" (empty)"));
1135
+ }
1136
+ console.log();
1137
+ } catch (error) {
1138
+ const errorMessage = error instanceof Error ? error.message : String(error);
1139
+ if (errorMessage === "StoredDataNotFound") {
1140
+ if (options.json) {
1141
+ console.log(
1142
+ JSON.stringify(
1143
+ {
1144
+ key: options.key,
1145
+ operator: options.operator,
1146
+ chainId: readOnlyOptions.chainId,
1147
+ error: "Not found"
1148
+ },
1149
+ null,
1150
+ 2
1151
+ )
1152
+ );
1153
+ process.exit(1);
1154
+ }
1155
+ exitWithError(
1156
+ `No data found for key "${options.key}" and operator "${options.operator}"`
1157
+ );
1158
+ }
1159
+ exitWithError(`Failed to read storage: ${errorMessage}`);
1160
+ }
1161
+ }
1162
+ function encodeTransaction(config, chainId) {
1163
+ const calldata = encodeFunctionData({
1164
+ abi: config.abi,
1165
+ functionName: config.functionName,
1166
+ args: config.args
1167
+ });
1168
+ return {
1169
+ to: config.to,
1170
+ data: calldata,
1171
+ chainId,
1172
+ value: config.value?.toString() ?? "0"
1173
+ };
1174
+ }
1175
+
1176
+ // src/commands/storage/core/encode.ts
1177
+ var XML_STORAGE_THRESHOLD = 20 * 1024;
1178
+ async function encodeStorageUpload(options) {
1179
+ const readOnlyOptions = parseReadOnlyOptions({
1180
+ chainId: options.chainId,
1181
+ rpcUrl: options.rpcUrl
1182
+ });
1183
+ let operatorAddress;
1184
+ if (options.privateKey) {
1185
+ const account = privateKeyToAccount(options.privateKey);
1186
+ operatorAddress = account.address;
1187
+ } else {
1188
+ operatorAddress = "0x0000000000000000000000000000000000000000";
1189
+ }
1190
+ const fileContent = fs.readFileSync(options.filePath, "utf-8");
1191
+ const fileSize = Buffer.byteLength(fileContent, "utf-8");
1192
+ const client = new StorageClient({
1193
+ chainId: readOnlyOptions.chainId
1194
+ });
1195
+ const useXmlStorage = fileSize > XML_STORAGE_THRESHOLD;
1196
+ if (useXmlStorage) {
1197
+ const { transactionConfigs, topLevelHash, metadata } = client.prepareXmlStorage({
1198
+ data: fileContent,
1199
+ operatorAddress,
1200
+ storageKey: options.storageKey,
1201
+ filename: options.text
1202
+ });
1203
+ const encodedTransactions = transactionConfigs.map(
1204
+ (config) => encodeTransaction(config, readOnlyOptions.chainId)
1205
+ );
1206
+ return {
1207
+ storageKey: options.storageKey,
1208
+ storageType: "xml",
1209
+ operatorAddress,
1210
+ transactions: encodedTransactions,
1211
+ topLevelHash
1212
+ };
1213
+ } else {
1214
+ const config = client.preparePut({
1215
+ key: options.storageKey,
1216
+ text: options.text,
1217
+ value: fileContent
1218
+ });
1219
+ const encodedTransaction = encodeTransaction(
1220
+ config,
1221
+ readOnlyOptions.chainId
1222
+ );
1223
+ return {
1224
+ storageKey: options.storageKey,
1225
+ storageType: "normal",
1226
+ operatorAddress,
1227
+ transactions: [encodedTransaction]
1228
+ };
1229
+ }
1230
+ }
1022
1231
 
1023
1232
  // src/commands/storage/index.ts
1024
1233
  function registerStorageCommand(program2) {
@@ -1033,7 +1242,32 @@ function registerStorageCommand(program2) {
1033
1242
  ).option(
1034
1243
  "--rpc-url <url>",
1035
1244
  "Custom RPC URL (can also be set via NET_RPC_URL env var)"
1245
+ ).option(
1246
+ "--encode-only",
1247
+ "Output transaction data as JSON instead of executing"
1036
1248
  ).action(async (options) => {
1249
+ if (options.encodeOnly) {
1250
+ try {
1251
+ const result = await encodeStorageUpload({
1252
+ filePath: options.file,
1253
+ storageKey: options.key,
1254
+ text: options.text,
1255
+ privateKey: options.privateKey,
1256
+ chainId: options.chainId,
1257
+ rpcUrl: options.rpcUrl
1258
+ });
1259
+ console.log(JSON.stringify(result, null, 2));
1260
+ process.exit(0);
1261
+ } catch (error) {
1262
+ console.error(
1263
+ chalk4.red(
1264
+ `Encode failed: ${error instanceof Error ? error.message : String(error)}`
1265
+ )
1266
+ );
1267
+ process.exit(1);
1268
+ }
1269
+ return;
1270
+ }
1037
1271
  const commonOptions = parseCommonOptions({
1038
1272
  privateKey: options.privateKey,
1039
1273
  chainId: options.chainId,
@@ -1048,7 +1282,7 @@ function registerStorageCommand(program2) {
1048
1282
  rpcUrl: commonOptions.rpcUrl
1049
1283
  };
1050
1284
  try {
1051
- console.log(chalk2.blue(`\u{1F4C1} Reading file: ${options.file}`));
1285
+ console.log(chalk4.blue(`\u{1F4C1} Reading file: ${options.file}`));
1052
1286
  const result = await uploadFile(uploadOptions);
1053
1287
  const storageUrl = generateStorageUrl(
1054
1288
  result.operatorAddress,
@@ -1057,31 +1291,31 @@ function registerStorageCommand(program2) {
1057
1291
  );
1058
1292
  if (result.skipped && result.transactionsSent === 0) {
1059
1293
  console.log(
1060
- chalk2.green(
1294
+ chalk4.green(
1061
1295
  `\u2713 All data already stored - skipping upload
1062
1296
  Storage Key: ${options.key}
1063
1297
  Skipped: ${result.transactionsSkipped} transaction(s)${storageUrl ? `
1064
- Storage URL: ${chalk2.cyan(storageUrl)}` : ""}`
1298
+ Storage URL: ${chalk4.cyan(storageUrl)}` : ""}`
1065
1299
  )
1066
1300
  );
1067
1301
  process.exit(0);
1068
1302
  }
1069
1303
  if (result.success) {
1070
1304
  console.log(
1071
- chalk2.green(
1305
+ chalk4.green(
1072
1306
  `\u2713 File uploaded successfully!
1073
1307
  Storage Key: ${options.key}
1074
1308
  Storage Type: ${result.storageType === "xml" ? "XML" : "Normal"}
1075
1309
  Transactions Sent: ${result.transactionsSent}
1076
1310
  Transactions Skipped: ${result.transactionsSkipped}
1077
1311
  Final Transaction Hash: ${result.finalHash || "N/A"}${storageUrl ? `
1078
- Storage URL: ${chalk2.cyan(storageUrl)}` : ""}`
1312
+ Storage URL: ${chalk4.cyan(storageUrl)}` : ""}`
1079
1313
  )
1080
1314
  );
1081
1315
  process.exit(0);
1082
1316
  } else {
1083
1317
  console.error(
1084
- chalk2.red(
1318
+ chalk4.red(
1085
1319
  `\u2717 Upload completed with errors
1086
1320
  Transactions Sent: ${result.transactionsSent}
1087
1321
  Transactions Skipped: ${result.transactionsSkipped}
@@ -1093,7 +1327,7 @@ function registerStorageCommand(program2) {
1093
1327
  }
1094
1328
  } catch (error) {
1095
1329
  console.error(
1096
- chalk2.red(
1330
+ chalk4.red(
1097
1331
  `Upload failed: ${error instanceof Error ? error.message : String(error)}`
1098
1332
  )
1099
1333
  );
@@ -1125,54 +1359,54 @@ function registerStorageCommand(program2) {
1125
1359
  rpcUrl: commonOptions.rpcUrl
1126
1360
  };
1127
1361
  try {
1128
- console.log(chalk2.blue(`\u{1F4C1} Reading file: ${options.file}`));
1362
+ console.log(chalk4.blue(`\u{1F4C1} Reading file: ${options.file}`));
1129
1363
  const result = await previewFile(previewOptions);
1130
1364
  const storageUrl = generateStorageUrl(
1131
1365
  result.operatorAddress,
1132
1366
  commonOptions.chainId,
1133
1367
  options.key
1134
1368
  );
1135
- console.log(chalk2.cyan("\n\u{1F4CA} Storage Preview:"));
1136
- console.log(` Storage Key: ${chalk2.white(result.storageKey)}`);
1369
+ console.log(chalk4.cyan("\n\u{1F4CA} Storage Preview:"));
1370
+ console.log(` Storage Key: ${chalk4.white(result.storageKey)}`);
1137
1371
  console.log(
1138
- ` Storage Type: ${chalk2.white(
1372
+ ` Storage Type: ${chalk4.white(
1139
1373
  result.storageType === "xml" ? "XML" : "Normal"
1140
1374
  )}`
1141
1375
  );
1142
- console.log(` Total Chunks: ${chalk2.white(result.totalChunks)}`);
1376
+ console.log(` Total Chunks: ${chalk4.white(result.totalChunks)}`);
1143
1377
  console.log(
1144
- ` Already Stored: ${chalk2.green(result.alreadyStoredChunks)}`
1378
+ ` Already Stored: ${chalk4.green(result.alreadyStoredChunks)}`
1145
1379
  );
1146
1380
  console.log(
1147
- ` Need to Store: ${chalk2.yellow(result.needToStoreChunks)}`
1381
+ ` Need to Store: ${chalk4.yellow(result.needToStoreChunks)}`
1148
1382
  );
1149
1383
  if (result.storageType === "xml" && result.metadataNeedsStorage) {
1150
- console.log(` Metadata: ${chalk2.yellow("Needs Storage")}`);
1384
+ console.log(` Metadata: ${chalk4.yellow("Needs Storage")}`);
1151
1385
  } else if (result.storageType === "xml") {
1152
- console.log(` Metadata: ${chalk2.green("Already Stored")}`);
1386
+ console.log(` Metadata: ${chalk4.green("Already Stored")}`);
1153
1387
  }
1154
1388
  console.log(
1155
- ` Total Transactions: ${chalk2.white(result.totalTransactions)}`
1389
+ ` Total Transactions: ${chalk4.white(result.totalTransactions)}`
1156
1390
  );
1157
1391
  console.log(
1158
- ` Transactions to Send: ${chalk2.yellow(result.transactionsToSend)}`
1392
+ ` Transactions to Send: ${chalk4.yellow(result.transactionsToSend)}`
1159
1393
  );
1160
1394
  console.log(
1161
- ` Transactions Skipped: ${chalk2.green(result.transactionsSkipped)}`
1395
+ ` Transactions Skipped: ${chalk4.green(result.transactionsSkipped)}`
1162
1396
  );
1163
1397
  console.log(
1164
- ` Operator Address: ${chalk2.gray(result.operatorAddress)}`
1398
+ ` Operator Address: ${chalk4.gray(result.operatorAddress)}`
1165
1399
  );
1166
1400
  if (storageUrl) {
1167
- console.log(` Storage URL: ${chalk2.cyan(storageUrl)}`);
1401
+ console.log(` Storage URL: ${chalk4.cyan(storageUrl)}`);
1168
1402
  }
1169
1403
  if (result.needToStoreChunks === 0 && !result.metadataNeedsStorage) {
1170
1404
  console.log(
1171
- chalk2.green("\n\u2713 All data is already stored - no upload needed")
1405
+ chalk4.green("\n\u2713 All data is already stored - no upload needed")
1172
1406
  );
1173
1407
  } else {
1174
1408
  console.log(
1175
- chalk2.yellow(
1409
+ chalk4.yellow(
1176
1410
  `
1177
1411
  \u26A0 ${result.transactionsToSend} transaction(s) would be sent`
1178
1412
  )
@@ -1181,7 +1415,7 @@ function registerStorageCommand(program2) {
1181
1415
  process.exit(0);
1182
1416
  } catch (error) {
1183
1417
  console.error(
1184
- chalk2.red(
1418
+ chalk4.red(
1185
1419
  `Preview failed: ${error instanceof Error ? error.message : String(error)}`
1186
1420
  )
1187
1421
  );
@@ -1213,7 +1447,7 @@ function registerStorageCommand(program2) {
1213
1447
  const secretKey = options.secretKey || process.env.X402_SECRET_KEY;
1214
1448
  if (!secretKey) {
1215
1449
  console.error(
1216
- chalk2.red(
1450
+ chalk4.red(
1217
1451
  "Error: --secret-key is required or set X402_SECRET_KEY environment variable"
1218
1452
  )
1219
1453
  );
@@ -1230,11 +1464,11 @@ function registerStorageCommand(program2) {
1230
1464
  secretKey
1231
1465
  };
1232
1466
  try {
1233
- console.log(chalk2.blue(`\u{1F4C1} Reading file: ${options.file}`));
1234
- console.log(chalk2.blue(`\u{1F517} Using relay API: ${options.apiUrl}`));
1467
+ console.log(chalk4.blue(`\u{1F4C1} Reading file: ${options.file}`));
1468
+ console.log(chalk4.blue(`\u{1F517} Using relay API: ${options.apiUrl}`));
1235
1469
  const result = await uploadFileWithRelay(uploadRelayOptions);
1236
- const { privateKeyToAccount: privateKeyToAccount3 } = await import('viem/accounts');
1237
- const userAccount = privateKeyToAccount3(commonOptions.privateKey);
1470
+ const { privateKeyToAccount: privateKeyToAccount6 } = await import('viem/accounts');
1471
+ const userAccount = privateKeyToAccount6(commonOptions.privateKey);
1238
1472
  const storageUrl = generateStorageUrl(
1239
1473
  userAccount.address,
1240
1474
  commonOptions.chainId,
@@ -1242,7 +1476,7 @@ function registerStorageCommand(program2) {
1242
1476
  );
1243
1477
  if (result.success) {
1244
1478
  console.log(
1245
- chalk2.green(
1479
+ chalk4.green(
1246
1480
  `\u2713 File uploaded successfully via relay!
1247
1481
  Storage Key: ${options.key}
1248
1482
  Top-Level Hash: ${result.topLevelHash}
@@ -1252,13 +1486,13 @@ function registerStorageCommand(program2) {
1252
1486
  Backend Wallet: ${result.backendWalletAddress}
1253
1487
  Chunk Transaction Hashes: ${result.chunkTransactionHashes.length > 0 ? result.chunkTransactionHashes.join(", ") : "None"}${result.metadataTransactionHash ? `
1254
1488
  Metadata Transaction Hash: ${result.metadataTransactionHash}` : ""}${storageUrl ? `
1255
- Storage URL: ${chalk2.cyan(storageUrl)}` : ""}`
1489
+ Storage URL: ${chalk4.cyan(storageUrl)}` : ""}`
1256
1490
  )
1257
1491
  );
1258
1492
  process.exit(0);
1259
1493
  } else {
1260
1494
  console.error(
1261
- chalk2.red(
1495
+ chalk4.red(
1262
1496
  `\u2717 Upload completed with errors
1263
1497
  Chunks Sent: ${result.chunksSent}
1264
1498
  Chunks Skipped: ${result.chunksSkipped}
@@ -1270,22 +1504,726 @@ function registerStorageCommand(program2) {
1270
1504
  }
1271
1505
  } catch (error) {
1272
1506
  console.error(
1273
- chalk2.red(
1507
+ chalk4.red(
1274
1508
  `Upload via relay failed: ${error instanceof Error ? error.message : String(error)}`
1275
1509
  )
1276
1510
  );
1277
1511
  process.exit(1);
1278
1512
  }
1279
1513
  });
1514
+ const readCommand = new Command("read").description("Read data from Net Storage").requiredOption("--key <key>", "Storage key to read").requiredOption("--operator <address>", "Operator address (wallet that stored the data)").option(
1515
+ "--chain-id <id>",
1516
+ "Chain ID. Can also be set via NET_CHAIN_ID env var",
1517
+ (value) => parseInt(value, 10)
1518
+ ).option(
1519
+ "--rpc-url <url>",
1520
+ "Custom RPC URL. Can also be set via NET_RPC_URL env var"
1521
+ ).option(
1522
+ "--index <n>",
1523
+ "Historical version index (0 = oldest). Omit for latest.",
1524
+ (value) => parseInt(value, 10)
1525
+ ).option("--json", "Output in JSON format").option("--raw", "Output raw data without truncation (use with --json)").action(async (options) => {
1526
+ await executeStorageRead({
1527
+ key: options.key,
1528
+ operator: options.operator,
1529
+ chainId: options.chainId,
1530
+ rpcUrl: options.rpcUrl,
1531
+ index: options.index,
1532
+ json: options.json,
1533
+ raw: options.raw
1534
+ });
1535
+ });
1280
1536
  storageCommand.addCommand(uploadCommand);
1281
1537
  storageCommand.addCommand(previewCommand);
1282
1538
  storageCommand.addCommand(uploadRelayCommand);
1539
+ storageCommand.addCommand(readCommand);
1540
+ }
1541
+ function createNetClient(options) {
1542
+ return new NetClient({
1543
+ chainId: options.chainId,
1544
+ overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
1545
+ });
1546
+ }
1547
+
1548
+ // src/commands/message/send.ts
1549
+ function prepareMessageConfig(client, options) {
1550
+ return client.prepareSendMessage({
1551
+ text: options.text,
1552
+ topic: options.topic ?? "",
1553
+ data: options.data
1554
+ });
1555
+ }
1556
+ async function executeSend(options) {
1557
+ if (options.encodeOnly) {
1558
+ executeEncodeOnly(options);
1559
+ return;
1560
+ }
1561
+ const commonOptions = parseCommonOptions({
1562
+ privateKey: options.privateKey,
1563
+ chainId: options.chainId,
1564
+ rpcUrl: options.rpcUrl
1565
+ });
1566
+ const client = createNetClient(commonOptions);
1567
+ const txConfig = prepareMessageConfig(client, options);
1568
+ const account = privateKeyToAccount(commonOptions.privateKey);
1569
+ const rpcUrls = getChainRpcUrls({
1570
+ chainId: commonOptions.chainId,
1571
+ rpcUrl: commonOptions.rpcUrl
1572
+ });
1573
+ const walletClient = createWalletClient({
1574
+ account,
1575
+ transport: http(rpcUrls[0])
1576
+ });
1577
+ console.log(chalk4.blue("Sending message..."));
1578
+ try {
1579
+ const hash = await walletClient.writeContract({
1580
+ address: txConfig.to,
1581
+ abi: txConfig.abi,
1582
+ functionName: txConfig.functionName,
1583
+ args: txConfig.args,
1584
+ chain: null
1585
+ });
1586
+ const topicLine = options.topic ? `
1587
+ Topic: ${options.topic}` : "";
1588
+ console.log(
1589
+ chalk4.green(
1590
+ `Message sent successfully!
1591
+ Transaction: ${hash}
1592
+ Text: ${options.text}${topicLine}`
1593
+ )
1594
+ );
1595
+ } catch (error) {
1596
+ exitWithError(
1597
+ `Failed to send message: ${error instanceof Error ? error.message : String(error)}`
1598
+ );
1599
+ }
1600
+ }
1601
+ function executeEncodeOnly(options) {
1602
+ const readOnlyOptions = parseReadOnlyOptions({
1603
+ chainId: options.chainId,
1604
+ rpcUrl: options.rpcUrl
1605
+ });
1606
+ const client = new NetClient({ chainId: readOnlyOptions.chainId });
1607
+ const txConfig = prepareMessageConfig(client, options);
1608
+ const encoded = encodeTransaction(txConfig, readOnlyOptions.chainId);
1609
+ console.log(JSON.stringify(encoded, null, 2));
1610
+ }
1611
+ function buildFilter(options) {
1612
+ if (!options.app) {
1613
+ return void 0;
1614
+ }
1615
+ return {
1616
+ appAddress: options.app,
1617
+ topic: options.topic,
1618
+ maker: options.sender
1619
+ };
1620
+ }
1621
+ function warnIgnoredFilters(options) {
1622
+ if (options.app || !options.topic && !options.sender) {
1623
+ return;
1624
+ }
1625
+ const ignored = [];
1626
+ if (options.topic) ignored.push("--topic");
1627
+ if (options.sender) ignored.push("--sender");
1628
+ console.warn(
1629
+ chalk4.yellow(
1630
+ `Warning: ${ignored.join(" and ")} ignored because --app is required for filtering`
1631
+ )
1632
+ );
1633
+ }
1634
+
1635
+ // src/commands/message/read.ts
1636
+ function printEmptyResult(message, json) {
1637
+ if (json) {
1638
+ console.log(JSON.stringify([], null, 2));
1639
+ } else {
1640
+ console.log(chalk4.yellow(message));
1641
+ }
1642
+ }
1643
+ async function executeRead(options) {
1644
+ const readOnlyOptions = parseReadOnlyOptions({
1645
+ chainId: options.chainId,
1646
+ rpcUrl: options.rpcUrl
1647
+ });
1648
+ const client = createNetClient(readOnlyOptions);
1649
+ const filter = buildFilter(options);
1650
+ const json = options.json ?? false;
1651
+ warnIgnoredFilters(options);
1652
+ try {
1653
+ if (options.index !== void 0) {
1654
+ const message = await client.getMessageAtIndex({
1655
+ messageIndex: options.index,
1656
+ appAddress: filter?.appAddress,
1657
+ topic: filter?.topic,
1658
+ maker: filter?.maker
1659
+ });
1660
+ if (!message) {
1661
+ exitWithError(`No message found at index ${options.index}`);
1662
+ }
1663
+ printMessages([message], options.index, json);
1664
+ return;
1665
+ }
1666
+ const count = await client.getMessageCount({ filter });
1667
+ if (count === 0) {
1668
+ printEmptyResult("No messages found", json);
1669
+ return;
1670
+ }
1671
+ const hasExplicitRange = options.start !== void 0 || options.end !== void 0;
1672
+ let startIndex;
1673
+ let endIndex;
1674
+ if (hasExplicitRange) {
1675
+ startIndex = options.start ?? 0;
1676
+ endIndex = options.end ?? count;
1677
+ } else {
1678
+ const limit = options.limit ?? 10;
1679
+ startIndex = Math.max(0, count - limit);
1680
+ endIndex = count;
1681
+ }
1682
+ startIndex = Math.max(0, startIndex);
1683
+ endIndex = Math.min(endIndex, count);
1684
+ if (startIndex >= endIndex) {
1685
+ printEmptyResult("No messages in specified range", json);
1686
+ return;
1687
+ }
1688
+ const messages = await client.getMessagesBatch({
1689
+ filter,
1690
+ startIndex,
1691
+ endIndex
1692
+ });
1693
+ printMessages(messages, startIndex, json);
1694
+ } catch (error) {
1695
+ exitWithError(
1696
+ `Failed to read messages: ${error instanceof Error ? error.message : String(error)}`
1697
+ );
1698
+ }
1699
+ }
1700
+
1701
+ // src/commands/message/count.ts
1702
+ function buildCountLabel(filter) {
1703
+ if (!filter) {
1704
+ return "Total messages:";
1705
+ }
1706
+ const parts = [];
1707
+ if (filter.appAddress) parts.push(`app=${filter.appAddress}`);
1708
+ if (filter.topic) parts.push(`topic="${filter.topic}"`);
1709
+ if (filter.maker) parts.push(`sender=${filter.maker}`);
1710
+ return `Messages (${parts.join(", ")}):`;
1711
+ }
1712
+ async function executeCount(options) {
1713
+ const readOnlyOptions = parseReadOnlyOptions({
1714
+ chainId: options.chainId,
1715
+ rpcUrl: options.rpcUrl
1716
+ });
1717
+ const client = createNetClient(readOnlyOptions);
1718
+ const filter = buildFilter(options);
1719
+ warnIgnoredFilters(options);
1720
+ try {
1721
+ const count = await client.getMessageCount({ filter });
1722
+ printCount(count, buildCountLabel(filter), options.json ?? false);
1723
+ } catch (error) {
1724
+ exitWithError(
1725
+ `Failed to get message count: ${error instanceof Error ? error.message : String(error)}`
1726
+ );
1727
+ }
1728
+ }
1729
+
1730
+ // src/commands/message/index.ts
1731
+ function registerMessageCommand(program2) {
1732
+ const messageCommand = program2.command("message").description("Message operations");
1733
+ const sendCommand = new Command("send").description("Send a message to Net Protocol").requiredOption("--text <text>", "Message text").option("--topic <topic>", "Message topic", "").option("--data <hex>", "Additional hex data").option(
1734
+ "--private-key <key>",
1735
+ "Private key (0x-prefixed hex). Can also be set via NET_PRIVATE_KEY env var"
1736
+ ).option(
1737
+ "--chain-id <id>",
1738
+ "Chain ID. Can also be set via NET_CHAIN_ID env var",
1739
+ (value) => parseInt(value, 10)
1740
+ ).option(
1741
+ "--rpc-url <url>",
1742
+ "Custom RPC URL. Can also be set via NET_RPC_URL env var"
1743
+ ).option(
1744
+ "--encode-only",
1745
+ "Output transaction data as JSON instead of executing"
1746
+ ).action(async (options) => {
1747
+ await executeSend({
1748
+ text: options.text,
1749
+ topic: options.topic,
1750
+ data: options.data,
1751
+ privateKey: options.privateKey,
1752
+ chainId: options.chainId,
1753
+ rpcUrl: options.rpcUrl,
1754
+ encodeOnly: options.encodeOnly
1755
+ });
1756
+ });
1757
+ const readCommand = new Command("read").description("Read messages from Net Protocol").option("--app <address>", "Filter by app address").option("--topic <topic>", "Filter by topic").option("--sender <address>", "Filter by sender address").option(
1758
+ "--start <n>",
1759
+ "Start index (inclusive)",
1760
+ (value) => parseInt(value, 10)
1761
+ ).option(
1762
+ "--end <n>",
1763
+ "End index (exclusive)",
1764
+ (value) => parseInt(value, 10)
1765
+ ).option(
1766
+ "--index <n>",
1767
+ "Single message at index",
1768
+ (value) => parseInt(value, 10)
1769
+ ).option(
1770
+ "--limit <n>",
1771
+ "Number of latest messages (default: 10)",
1772
+ (value) => parseInt(value, 10)
1773
+ ).option(
1774
+ "--chain-id <id>",
1775
+ "Chain ID. Can also be set via NET_CHAIN_ID env var",
1776
+ (value) => parseInt(value, 10)
1777
+ ).option(
1778
+ "--rpc-url <url>",
1779
+ "Custom RPC URL. Can also be set via NET_RPC_URL env var"
1780
+ ).option("--json", "Output in JSON format").action(async (options) => {
1781
+ await executeRead({
1782
+ app: options.app,
1783
+ topic: options.topic,
1784
+ sender: options.sender,
1785
+ start: options.start,
1786
+ end: options.end,
1787
+ index: options.index,
1788
+ limit: options.limit,
1789
+ chainId: options.chainId,
1790
+ rpcUrl: options.rpcUrl,
1791
+ json: options.json
1792
+ });
1793
+ });
1794
+ const countCommand = new Command("count").description("Get message count from Net Protocol").option("--app <address>", "Filter by app address").option("--topic <topic>", "Filter by topic").option("--sender <address>", "Filter by sender address").option(
1795
+ "--chain-id <id>",
1796
+ "Chain ID. Can also be set via NET_CHAIN_ID env var",
1797
+ (value) => parseInt(value, 10)
1798
+ ).option(
1799
+ "--rpc-url <url>",
1800
+ "Custom RPC URL. Can also be set via NET_RPC_URL env var"
1801
+ ).option("--json", "Output in JSON format").action(async (options) => {
1802
+ await executeCount({
1803
+ app: options.app,
1804
+ topic: options.topic,
1805
+ sender: options.sender,
1806
+ chainId: options.chainId,
1807
+ rpcUrl: options.rpcUrl,
1808
+ json: options.json
1809
+ });
1810
+ });
1811
+ messageCommand.addCommand(sendCommand);
1812
+ messageCommand.addCommand(readCommand);
1813
+ messageCommand.addCommand(countCommand);
1814
+ }
1815
+ var SUPPORTED_CHAINS = [
1816
+ { id: 8453, name: "Base", type: "mainnet" },
1817
+ { id: 1, name: "Ethereum", type: "mainnet" },
1818
+ { id: 666666666, name: "Degen", type: "mainnet" },
1819
+ { id: 5112, name: "Ham", type: "mainnet" },
1820
+ { id: 57073, name: "Ink", type: "mainnet" },
1821
+ { id: 130, name: "Unichain", type: "mainnet" },
1822
+ { id: 999, name: "HyperEVM", type: "mainnet" },
1823
+ { id: 9745, name: "Plasma", type: "mainnet" },
1824
+ { id: 143, name: "Monad", type: "mainnet" },
1825
+ { id: 84532, name: "Base Sepolia", type: "testnet" },
1826
+ { id: 11155111, name: "Sepolia", type: "testnet" }
1827
+ ];
1828
+ function registerChainsCommand(program2) {
1829
+ program2.command("chains").description("List supported chains").option("--json", "Output in JSON format").action((options) => {
1830
+ if (options.json) {
1831
+ console.log(JSON.stringify(SUPPORTED_CHAINS, null, 2));
1832
+ return;
1833
+ }
1834
+ console.log(chalk4.white.bold("Supported Chains:\n"));
1835
+ console.log(chalk4.cyan("Mainnets:"));
1836
+ SUPPORTED_CHAINS.filter((c) => c.type === "mainnet").forEach((chain) => {
1837
+ console.log(` ${chalk4.white(chain.name)} ${chalk4.gray(`(${chain.id})`)}`);
1838
+ });
1839
+ console.log(chalk4.cyan("\nTestnets:"));
1840
+ SUPPORTED_CHAINS.filter((c) => c.type === "testnet").forEach((chain) => {
1841
+ console.log(` ${chalk4.white(chain.name)} ${chalk4.gray(`(${chain.id})`)}`);
1842
+ });
1843
+ });
1844
+ }
1845
+ function registerInfoCommand(program2) {
1846
+ program2.command("info").description("Show contract info and stats").option(
1847
+ "--chain-id <id>",
1848
+ "Chain ID. Can also be set via NET_CHAIN_ID env var",
1849
+ (value) => parseInt(value, 10)
1850
+ ).option(
1851
+ "--rpc-url <url>",
1852
+ "Custom RPC URL. Can also be set via NET_RPC_URL env var"
1853
+ ).option("--json", "Output in JSON format").action(async (options) => {
1854
+ const readOnlyOptions = parseReadOnlyOptions({
1855
+ chainId: options.chainId,
1856
+ rpcUrl: options.rpcUrl
1857
+ });
1858
+ try {
1859
+ const client = createNetClient(readOnlyOptions);
1860
+ const contract = getNetContract(readOnlyOptions.chainId);
1861
+ const chainName = getChainName({ chainId: readOnlyOptions.chainId });
1862
+ const totalMessages = await client.getMessageCount({});
1863
+ const info = {
1864
+ chain: {
1865
+ id: readOnlyOptions.chainId,
1866
+ name: chainName || "Unknown"
1867
+ },
1868
+ contract: {
1869
+ address: contract.address
1870
+ },
1871
+ stats: {
1872
+ totalMessages
1873
+ }
1874
+ };
1875
+ if (options.json) {
1876
+ console.log(JSON.stringify(info, null, 2));
1877
+ return;
1878
+ }
1879
+ console.log(chalk4.white.bold("Net Protocol Info\n"));
1880
+ console.log(chalk4.cyan("Chain:"));
1881
+ console.log(` Name: ${chalk4.white(info.chain.name)}`);
1882
+ console.log(` ID: ${chalk4.white(info.chain.id)}`);
1883
+ console.log(chalk4.cyan("\nContract:"));
1884
+ console.log(` Address: ${chalk4.white(info.contract.address)}`);
1885
+ console.log(chalk4.cyan("\nStats:"));
1886
+ console.log(` Total Messages: ${chalk4.white(info.stats.totalMessages)}`);
1887
+ } catch (error) {
1888
+ exitWithError(
1889
+ `Failed to get info: ${error instanceof Error ? error.message : String(error)}`
1890
+ );
1891
+ }
1892
+ });
1893
+ }
1894
+ async function executeEncodeOnly2(options) {
1895
+ const readOnlyOptions = parseReadOnlyOptions({
1896
+ chainId: options.chainId,
1897
+ rpcUrl: options.rpcUrl
1898
+ });
1899
+ if (!isNetrSupportedChain(readOnlyOptions.chainId)) {
1900
+ exitWithError(
1901
+ `Chain ${readOnlyOptions.chainId} is not supported for token deployment`
1902
+ );
1903
+ }
1904
+ let deployerAddress;
1905
+ if (options.privateKey) {
1906
+ const account = privateKeyToAccount(options.privateKey);
1907
+ deployerAddress = account.address;
1908
+ } else {
1909
+ deployerAddress = "0x0000000000000000000000000000000000000000";
1910
+ }
1911
+ const client = new NetrClient({
1912
+ chainId: readOnlyOptions.chainId,
1913
+ overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
1914
+ });
1915
+ const saltResult = await client.generateSalt({
1916
+ name: options.name,
1917
+ symbol: options.symbol,
1918
+ image: options.image,
1919
+ animation: options.animation,
1920
+ deployer: deployerAddress,
1921
+ fid: options.fid ? BigInt(options.fid) : void 0,
1922
+ metadataAddress: options.metadataAddress,
1923
+ extraStringData: options.extraStringData
1924
+ });
1925
+ if (!saltResult) {
1926
+ exitWithError("Failed to generate salt for token deployment");
1927
+ return;
1928
+ }
1929
+ const txConfig = client.buildDeployConfig(
1930
+ {
1931
+ name: options.name,
1932
+ symbol: options.symbol,
1933
+ image: options.image,
1934
+ animation: options.animation,
1935
+ deployer: deployerAddress,
1936
+ fid: options.fid ? BigInt(options.fid) : void 0,
1937
+ mintPrice: options.mintPrice ? BigInt(options.mintPrice) : void 0,
1938
+ mintEndTimestamp: options.mintEndTimestamp ? BigInt(options.mintEndTimestamp) : void 0,
1939
+ maxMintSupply: options.maxMintSupply ? BigInt(options.maxMintSupply) : void 0,
1940
+ metadataAddress: options.metadataAddress,
1941
+ extraStringData: options.extraStringData,
1942
+ initialBuy: options.initialBuy ? parseEther(options.initialBuy) : void 0
1943
+ },
1944
+ saltResult.salt
1945
+ );
1946
+ const calldata = encodeFunctionData({
1947
+ abi: txConfig.abi,
1948
+ functionName: txConfig.functionName,
1949
+ args: txConfig.args
1950
+ });
1951
+ const result = {
1952
+ predictedAddress: saltResult.predictedAddress,
1953
+ salt: saltResult.salt,
1954
+ transaction: {
1955
+ to: txConfig.address,
1956
+ data: calldata,
1957
+ chainId: readOnlyOptions.chainId,
1958
+ value: txConfig.value?.toString() ?? "0"
1959
+ },
1960
+ config: {
1961
+ name: options.name,
1962
+ symbol: options.symbol,
1963
+ image: options.image,
1964
+ deployer: deployerAddress,
1965
+ ...options.initialBuy && { initialBuy: options.initialBuy }
1966
+ }
1967
+ };
1968
+ console.log(JSON.stringify(result, null, 2));
1969
+ }
1970
+ async function executeTokenDeploy(options) {
1971
+ if (options.encodeOnly) {
1972
+ await executeEncodeOnly2(options);
1973
+ return;
1974
+ }
1975
+ const commonOptions = parseCommonOptions({
1976
+ privateKey: options.privateKey,
1977
+ chainId: options.chainId,
1978
+ rpcUrl: options.rpcUrl
1979
+ });
1980
+ if (!isNetrSupportedChain(commonOptions.chainId)) {
1981
+ exitWithError(
1982
+ `Chain ${commonOptions.chainId} is not supported for token deployment. Supported: Base (8453), Plasma (9745), Monad (143), HyperEVM (999)`
1983
+ );
1984
+ }
1985
+ const account = privateKeyToAccount(commonOptions.privateKey);
1986
+ const client = new NetrClient({
1987
+ chainId: commonOptions.chainId,
1988
+ overrides: commonOptions.rpcUrl ? { rpcUrls: [commonOptions.rpcUrl] } : void 0
1989
+ });
1990
+ console.log(chalk4.blue("Generating salt and predicting token address..."));
1991
+ const saltResult = await client.generateSalt({
1992
+ name: options.name,
1993
+ symbol: options.symbol,
1994
+ image: options.image,
1995
+ animation: options.animation,
1996
+ deployer: account.address,
1997
+ fid: options.fid ? BigInt(options.fid) : void 0,
1998
+ metadataAddress: options.metadataAddress,
1999
+ extraStringData: options.extraStringData
2000
+ });
2001
+ if (!saltResult) {
2002
+ exitWithError("Failed to generate salt for token deployment");
2003
+ return;
2004
+ }
2005
+ console.log(
2006
+ chalk4.cyan(`Predicted token address: ${saltResult.predictedAddress}`)
2007
+ );
2008
+ const txConfig = client.buildDeployConfig(
2009
+ {
2010
+ name: options.name,
2011
+ symbol: options.symbol,
2012
+ image: options.image,
2013
+ animation: options.animation,
2014
+ deployer: account.address,
2015
+ fid: options.fid ? BigInt(options.fid) : void 0,
2016
+ mintPrice: options.mintPrice ? BigInt(options.mintPrice) : void 0,
2017
+ mintEndTimestamp: options.mintEndTimestamp ? BigInt(options.mintEndTimestamp) : void 0,
2018
+ maxMintSupply: options.maxMintSupply ? BigInt(options.maxMintSupply) : void 0,
2019
+ metadataAddress: options.metadataAddress,
2020
+ extraStringData: options.extraStringData,
2021
+ initialBuy: options.initialBuy ? parseEther(options.initialBuy) : void 0
2022
+ },
2023
+ saltResult.salt
2024
+ );
2025
+ const rpcUrls = getChainRpcUrls({
2026
+ chainId: commonOptions.chainId,
2027
+ rpcUrl: commonOptions.rpcUrl
2028
+ });
2029
+ const walletClient = createWalletClient({
2030
+ account,
2031
+ transport: http(rpcUrls[0])
2032
+ });
2033
+ if (options.initialBuy) {
2034
+ console.log(chalk4.blue(`Deploying token with ${options.initialBuy} ETH initial buy...`));
2035
+ } else {
2036
+ console.log(chalk4.blue("Deploying token..."));
2037
+ }
2038
+ try {
2039
+ const calldata = encodeFunctionData({
2040
+ abi: txConfig.abi,
2041
+ functionName: txConfig.functionName,
2042
+ args: txConfig.args
2043
+ });
2044
+ const hash = await walletClient.sendTransaction({
2045
+ to: txConfig.address,
2046
+ data: calldata,
2047
+ chain: null,
2048
+ value: txConfig.value
2049
+ });
2050
+ const initialBuyLine = options.initialBuy ? `
2051
+ Initial Buy: ${options.initialBuy} ETH` : "";
2052
+ console.log(
2053
+ chalk4.green(
2054
+ `Token deployed successfully!
2055
+ Transaction: ${hash}
2056
+ Token Address: ${saltResult.predictedAddress}
2057
+ Name: ${options.name}
2058
+ Symbol: ${options.symbol}${initialBuyLine}`
2059
+ )
2060
+ );
2061
+ } catch (error) {
2062
+ exitWithError(
2063
+ `Failed to deploy token: ${error instanceof Error ? error.message : String(error)}`
2064
+ );
2065
+ }
2066
+ }
2067
+ async function executeTokenInfo(options) {
2068
+ const readOnlyOptions = parseReadOnlyOptions({
2069
+ chainId: options.chainId,
2070
+ rpcUrl: options.rpcUrl
2071
+ });
2072
+ if (!isNetrSupportedChain(readOnlyOptions.chainId)) {
2073
+ exitWithError(
2074
+ `Chain ${readOnlyOptions.chainId} is not supported for Netr tokens`
2075
+ );
2076
+ }
2077
+ const client = new NetrClient({
2078
+ chainId: readOnlyOptions.chainId,
2079
+ overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
2080
+ });
2081
+ const tokenAddress = options.address;
2082
+ try {
2083
+ const [token, storageData, price] = await Promise.all([
2084
+ client.getToken(tokenAddress),
2085
+ client.getStorageData(tokenAddress),
2086
+ client.getPrice(tokenAddress)
2087
+ ]);
2088
+ if (!token) {
2089
+ exitWithError(`Token not found at address ${tokenAddress}`);
2090
+ return;
2091
+ }
2092
+ let locker = null;
2093
+ if (storageData?.lockerAddress) {
2094
+ locker = await client.getLocker(storageData.lockerAddress);
2095
+ }
2096
+ if (options.json) {
2097
+ const output = {
2098
+ address: tokenAddress,
2099
+ chainId: readOnlyOptions.chainId,
2100
+ token: {
2101
+ name: token.name,
2102
+ symbol: token.symbol,
2103
+ deployer: token.deployer,
2104
+ image: token.image,
2105
+ animation: token.animation || null,
2106
+ fid: token.fid.toString(),
2107
+ totalSupply: token.totalSupply.toString(),
2108
+ decimals: token.decimals,
2109
+ extraStringData: token.extraStringData || null
2110
+ },
2111
+ pool: storageData?.poolAddress || null,
2112
+ locker: storageData?.lockerAddress || null,
2113
+ price: price ? {
2114
+ priceInEth: price.priceInEth,
2115
+ priceInWeth: price.priceInWeth,
2116
+ tick: price.tick
2117
+ } : null,
2118
+ lockerInfo: locker ? {
2119
+ owner: locker.owner,
2120
+ duration: locker.duration.toString(),
2121
+ endTimestamp: locker.endTimestamp.toString(),
2122
+ version: locker.version
2123
+ } : null
2124
+ };
2125
+ console.log(JSON.stringify(output, null, 2));
2126
+ return;
2127
+ }
2128
+ console.log(chalk4.white.bold("\nToken Info:\n"));
2129
+ console.log(` ${chalk4.cyan("Address:")} ${tokenAddress}`);
2130
+ console.log(` ${chalk4.cyan("Chain ID:")} ${readOnlyOptions.chainId}`);
2131
+ console.log(` ${chalk4.cyan("Name:")} ${token.name}`);
2132
+ console.log(` ${chalk4.cyan("Symbol:")} ${token.symbol}`);
2133
+ console.log(` ${chalk4.cyan("Deployer:")} ${token.deployer}`);
2134
+ console.log(` ${chalk4.cyan("FID:")} ${token.fid.toString()}`);
2135
+ console.log(` ${chalk4.cyan("Image:")} ${token.image}`);
2136
+ if (token.animation) {
2137
+ console.log(` ${chalk4.cyan("Animation:")} ${token.animation}`);
2138
+ }
2139
+ if (token.extraStringData) {
2140
+ console.log(` ${chalk4.cyan("Extra Data:")} ${token.extraStringData}`);
2141
+ }
2142
+ if (storageData?.poolAddress) {
2143
+ console.log(` ${chalk4.cyan("Pool:")} ${storageData.poolAddress}`);
2144
+ }
2145
+ if (storageData?.lockerAddress) {
2146
+ console.log(` ${chalk4.cyan("Locker:")} ${storageData.lockerAddress}`);
2147
+ }
2148
+ if (price) {
2149
+ console.log(` ${chalk4.cyan("Price:")} ${price.priceInEth} ETH`);
2150
+ }
2151
+ if (locker) {
2152
+ const endDate = new Date(Number(locker.endTimestamp) * 1e3);
2153
+ console.log(
2154
+ ` ${chalk4.cyan("Lock Ends:")} ${endDate.toLocaleDateString()}`
2155
+ );
2156
+ }
2157
+ console.log();
2158
+ } catch (error) {
2159
+ exitWithError(
2160
+ `Failed to get token info: ${error instanceof Error ? error.message : String(error)}`
2161
+ );
2162
+ }
2163
+ }
2164
+
2165
+ // src/commands/token/index.ts
2166
+ function registerTokenCommand(program2) {
2167
+ const tokenCommand = program2.command("token").description("Token operations (Netr/Banger)");
2168
+ const deployCommand = new Command("deploy").description("Deploy a new Netr token").requiredOption("--name <name>", "Token name").requiredOption("--symbol <symbol>", "Token symbol").requiredOption("--image <url>", "Token image URL").option("--animation <url>", "Token animation URL").option("--fid <number>", "Farcaster ID").option(
2169
+ "--private-key <key>",
2170
+ "Private key (0x-prefixed hex). Can also be set via NET_PRIVATE_KEY env var"
2171
+ ).option(
2172
+ "--chain-id <id>",
2173
+ "Chain ID. Can also be set via NET_CHAIN_ID env var",
2174
+ (value) => parseInt(value, 10)
2175
+ ).option(
2176
+ "--rpc-url <url>",
2177
+ "Custom RPC URL. Can also be set via NET_RPC_URL env var"
2178
+ ).option(
2179
+ "--encode-only",
2180
+ "Output transaction data as JSON instead of executing"
2181
+ ).option("--mint-price <wei>", "Mint price in wei for NFT drop").option("--mint-end-timestamp <timestamp>", "Unix timestamp when minting ends").option("--max-mint-supply <amount>", "Maximum mint supply for NFT drop").option("--metadata-address <address>", "Dynamic metadata contract address").option("--extra-string-data <data>", "Extra string data to store with token").option("--initial-buy <eth>", "ETH amount to swap for tokens on deploy (e.g., '0.001')").action(async (options) => {
2182
+ await executeTokenDeploy({
2183
+ name: options.name,
2184
+ symbol: options.symbol,
2185
+ image: options.image,
2186
+ animation: options.animation,
2187
+ fid: options.fid,
2188
+ privateKey: options.privateKey,
2189
+ chainId: options.chainId,
2190
+ rpcUrl: options.rpcUrl,
2191
+ encodeOnly: options.encodeOnly,
2192
+ mintPrice: options.mintPrice,
2193
+ mintEndTimestamp: options.mintEndTimestamp,
2194
+ maxMintSupply: options.maxMintSupply,
2195
+ metadataAddress: options.metadataAddress,
2196
+ extraStringData: options.extraStringData,
2197
+ initialBuy: options.initialBuy
2198
+ });
2199
+ });
2200
+ const infoCommand = new Command("info").description("Get information about a Netr token").requiredOption("--address <address>", "Token address").option(
2201
+ "--chain-id <id>",
2202
+ "Chain ID. Can also be set via NET_CHAIN_ID env var",
2203
+ (value) => parseInt(value, 10)
2204
+ ).option(
2205
+ "--rpc-url <url>",
2206
+ "Custom RPC URL. Can also be set via NET_RPC_URL env var"
2207
+ ).option("--json", "Output in JSON format").action(async (options) => {
2208
+ await executeTokenInfo({
2209
+ address: options.address,
2210
+ chainId: options.chainId,
2211
+ rpcUrl: options.rpcUrl,
2212
+ json: options.json
2213
+ });
2214
+ });
2215
+ tokenCommand.addCommand(deployCommand);
2216
+ tokenCommand.addCommand(infoCommand);
1283
2217
  }
1284
2218
 
1285
2219
  // src/cli/index.ts
1286
2220
  var program = new Command();
1287
2221
  program.name("netp").description("CLI tool for Net Protocol").version("0.1.0");
1288
2222
  registerStorageCommand(program);
2223
+ registerMessageCommand(program);
2224
+ registerChainsCommand(program);
2225
+ registerInfoCommand(program);
2226
+ registerTokenCommand(program);
1289
2227
  program.parse();
1290
2228
  //# sourceMappingURL=index.mjs.map
1291
2229
  //# sourceMappingURL=index.mjs.map