@btc-vision/cli 1.0.5 → 1.0.6

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.
Files changed (46) hide show
  1. package/package.json +4 -1
  2. package/.gitattributes +0 -2
  3. package/.github/dependabot.yml +0 -9
  4. package/.github/workflows/ci.yml +0 -48
  5. package/.prettierrc.json +0 -12
  6. package/CONTRIBUTING.md +0 -56
  7. package/NOTICE +0 -17
  8. package/SECURITY.md +0 -35
  9. package/eslint.config.js +0 -41
  10. package/gulpfile.js +0 -41
  11. package/src/commands/AcceptCommand.ts +0 -224
  12. package/src/commands/BaseCommand.ts +0 -59
  13. package/src/commands/CompileCommand.ts +0 -195
  14. package/src/commands/ConfigCommand.ts +0 -117
  15. package/src/commands/DeprecateCommand.ts +0 -193
  16. package/src/commands/InfoCommand.ts +0 -293
  17. package/src/commands/InitCommand.ts +0 -541
  18. package/src/commands/InstallCommand.ts +0 -179
  19. package/src/commands/KeygenCommand.ts +0 -157
  20. package/src/commands/ListCommand.ts +0 -169
  21. package/src/commands/LoginCommand.ts +0 -197
  22. package/src/commands/LogoutCommand.ts +0 -76
  23. package/src/commands/PublishCommand.ts +0 -340
  24. package/src/commands/ScopeRegisterCommand.ts +0 -164
  25. package/src/commands/SearchCommand.ts +0 -140
  26. package/src/commands/SignCommand.ts +0 -110
  27. package/src/commands/TransferCommand.ts +0 -363
  28. package/src/commands/UndeprecateCommand.ts +0 -167
  29. package/src/commands/UpdateCommand.ts +0 -200
  30. package/src/commands/VerifyCommand.ts +0 -228
  31. package/src/commands/WhoamiCommand.ts +0 -113
  32. package/src/index.ts +0 -88
  33. package/src/lib/PackageRegistry.abi.json +0 -765
  34. package/src/lib/PackageRegistry.abi.ts +0 -365
  35. package/src/lib/binary.ts +0 -338
  36. package/src/lib/config.ts +0 -265
  37. package/src/lib/credentials.ts +0 -176
  38. package/src/lib/ipfs.ts +0 -382
  39. package/src/lib/manifest.ts +0 -195
  40. package/src/lib/provider.ts +0 -121
  41. package/src/lib/registry.ts +0 -467
  42. package/src/lib/transaction.ts +0 -205
  43. package/src/lib/wallet.ts +0 -262
  44. package/src/types/PackageRegistry.ts +0 -344
  45. package/src/types/index.ts +0 -147
  46. package/tsconfig.json +0 -25
@@ -1,197 +0,0 @@
1
- /**
2
- * Login command - Configure wallet credentials
3
- *
4
- * @module commands/LoginCommand
5
- */
6
-
7
- import { confirm, password, select } from '@inquirer/prompts';
8
- import { BaseCommand } from './BaseCommand.js';
9
- import { isValidMldsaLevel, isValidNetwork, saveCredentials } from '../lib/credentials.js';
10
- import { CLIWallet, validateMnemonic } from '../lib/wallet.js';
11
- import { CLICredentials, CLIMldsaLevel, NetworkName } from '../types/index.js';
12
-
13
- interface LoginOptions {
14
- mnemonic?: string;
15
- wif?: string;
16
- mldsa?: string;
17
- mldsaLevel: string;
18
- network: string;
19
- }
20
-
21
- export class LoginCommand extends BaseCommand {
22
- constructor() {
23
- super('login', 'Configure wallet credentials for signing and publishing');
24
- }
25
-
26
- protected configure(): void {
27
- this.command
28
- .option('-m, --mnemonic <phrase>', 'BIP-39 mnemonic phrase (12 or 24 words)')
29
- .option('--wif <key>', 'Bitcoin WIF private key (advanced)')
30
- .option('--mldsa <key>', 'MLDSA private key hex (advanced, requires --wif)')
31
- .option('-l, --mldsa-level <level>', 'MLDSA security level (44, 65, 87)', '44')
32
- .option('-n, --network <network>', 'Network (mainnet, testnet, regtest)', 'mainnet')
33
- .action((options: LoginOptions) => this.execute(options));
34
- }
35
-
36
- private async execute(options: LoginOptions): Promise<void> {
37
- try {
38
- const credentials = await this.buildCredentials(options);
39
-
40
- // Load wallet to display identity info
41
- this.logger.info('Deriving wallet...');
42
- const wallet = CLIWallet.fromCredentials(credentials);
43
-
44
- // Display wallet identity for user verification
45
- this.logger.log('');
46
- this.logger.info('Wallet Identity');
47
- this.logger.log('─'.repeat(50));
48
- this.logger.log(`Network: ${credentials.network}`);
49
- this.logger.log(`MLDSA Level: MLDSA-${credentials.mldsaLevel}`);
50
- this.logger.log(`P2TR Address: ${wallet.p2trAddress}`);
51
- this.logger.log(`MLDSA PubKey Hash: ${wallet.mldsaPublicKeyHash.substring(0, 32)}...`);
52
- this.logger.log('─'.repeat(50));
53
- this.logger.log('');
54
-
55
- // Always require confirmation
56
- this.logger.warn('Credentials will be stored at ~/.opnet/credentials.json');
57
- this.logger.warn('with restricted permissions (owner read/write only).');
58
- this.logger.log('');
59
-
60
- const confirmed = await confirm({
61
- message: 'Is this the correct wallet? Save credentials?',
62
- default: true,
63
- });
64
-
65
- if (!confirmed) {
66
- this.logger.warn('Login cancelled.');
67
- return;
68
- }
69
-
70
- saveCredentials(credentials);
71
-
72
- this.logger.log('');
73
- this.logger.success('Credentials saved successfully!');
74
- } catch (error) {
75
- if (this.isUserCancelled(error)) {
76
- this.logger.warn('Login cancelled.');
77
- process.exit(0);
78
- }
79
- this.exitWithError(this.formatError(error));
80
- }
81
- }
82
-
83
- private async buildCredentials(options: LoginOptions): Promise<CLICredentials> {
84
- if (!isValidNetwork(options.network)) {
85
- this.exitWithError(
86
- `Invalid network: ${options.network}. Valid: mainnet, testnet, regtest`,
87
- );
88
- throw new Error('Unreachable'); // Helps TypeScript
89
- }
90
-
91
- const mldsaLevelNum = parseInt(options.mldsaLevel, 10);
92
- if (!isValidMldsaLevel(mldsaLevelNum)) {
93
- this.exitWithError(`Invalid MLDSA level: ${options.mldsaLevel}. Valid: 44, 65, 87`);
94
- }
95
- const mldsaLevel: CLIMldsaLevel = mldsaLevelNum;
96
-
97
- if (options.mnemonic) {
98
- if (!validateMnemonic(options.mnemonic)) {
99
- this.exitWithError('Invalid mnemonic phrase');
100
- }
101
- return { mnemonic: options.mnemonic, mldsaLevel, network: options.network };
102
- }
103
-
104
- if (options.wif && options.mldsa) {
105
- return {
106
- wif: options.wif,
107
- mldsaPrivateKey: options.mldsa,
108
- mldsaLevel,
109
- network: options.network,
110
- };
111
- }
112
-
113
- return this.interactiveLogin(options.network, mldsaLevel);
114
- }
115
-
116
- private async interactiveLogin(
117
- defaultNetwork: NetworkName,
118
- defaultLevel: CLIMldsaLevel,
119
- ): Promise<CLICredentials> {
120
- this.logger.info('OPNet Wallet Configuration\n');
121
-
122
- const loginMethod = await select({
123
- message: 'How would you like to authenticate?',
124
- choices: [
125
- {
126
- name: 'Mnemonic phrase (recommended)',
127
- value: 'mnemonic',
128
- description: '12 or 24-word BIP-39 phrase for full key derivation',
129
- },
130
- {
131
- name: 'WIF + MLDSA keys (advanced)',
132
- value: 'advanced',
133
- description: 'Separate Bitcoin WIF and MLDSA private keys',
134
- },
135
- ],
136
- });
137
-
138
- const selectedNetwork = (await select({
139
- message: 'Select network:',
140
- choices: [
141
- { name: 'Mainnet', value: 'mainnet' },
142
- { name: 'Testnet', value: 'testnet' },
143
- { name: 'Regtest', value: 'regtest' },
144
- ],
145
- default: defaultNetwork,
146
- })) as NetworkName;
147
-
148
- const selectedLevel = (await select({
149
- message: 'Select MLDSA security level:',
150
- choices: [
151
- {
152
- name: 'MLDSA-44 (Level 2, fastest)',
153
- value: 44,
154
- description: '1312 byte public key',
155
- },
156
- {
157
- name: 'MLDSA-65 (Level 3, balanced)',
158
- value: 65,
159
- description: '1952 byte public key',
160
- },
161
- {
162
- name: 'MLDSA-87 (Level 5, most secure)',
163
- value: 87,
164
- description: '2592 byte public key',
165
- },
166
- ],
167
- default: defaultLevel,
168
- })) as CLIMldsaLevel;
169
-
170
- if (loginMethod === 'mnemonic') {
171
- const mnemonic = await password({
172
- message: 'Enter your mnemonic phrase (12 or 24 words):',
173
- mask: '*',
174
- validate: (value) => {
175
- if (!validateMnemonic(value)) {
176
- return 'Invalid mnemonic phrase. Please enter a valid 12 or 24-word BIP-39 phrase.';
177
- }
178
- return true;
179
- },
180
- });
181
-
182
- return { mnemonic, mldsaLevel: selectedLevel, network: selectedNetwork };
183
- }
184
-
185
- const wif = await password({ message: 'Enter Bitcoin WIF private key:', mask: '*' });
186
- const mldsaKey = await password({ message: 'Enter MLDSA private key (hex):', mask: '*' });
187
-
188
- return {
189
- wif,
190
- mldsaPrivateKey: mldsaKey,
191
- mldsaLevel: selectedLevel,
192
- network: selectedNetwork,
193
- };
194
- }
195
- }
196
-
197
- export const loginCommand = new LoginCommand().getCommand();
@@ -1,76 +0,0 @@
1
- /**
2
- * Logout command - Remove stored credentials
3
- *
4
- * @module commands/LogoutCommand
5
- */
6
-
7
- import { confirm } from '@inquirer/prompts';
8
- import { BaseCommand } from './BaseCommand.js';
9
- import { deleteCredentials, getCredentialSource, hasCredentials } from '../lib/credentials.js';
10
-
11
- interface LogoutOptions {
12
- yes?: boolean;
13
- }
14
-
15
- export class LogoutCommand extends BaseCommand {
16
- constructor() {
17
- super('logout', 'Remove stored wallet credentials');
18
- }
19
-
20
- protected configure(): void {
21
- this.command
22
- .option('-y, --yes', 'Skip confirmation prompt')
23
- .action((options: LogoutOptions) => this.execute(options));
24
- }
25
-
26
- private async execute(options: LogoutOptions): Promise<void> {
27
- try {
28
- if (!hasCredentials()) {
29
- this.logger.warn('No credentials found.');
30
- return;
31
- }
32
-
33
- const source = getCredentialSource();
34
-
35
- if (source.startsWith('environment')) {
36
- this.logger.warn(`Credentials are set via ${source}.`);
37
- this.logger.info('To remove them, unset the environment variables:');
38
- this.logger.info(' unset OPNET_MNEMONIC');
39
- this.logger.info(' unset OPNET_PRIVATE_KEY');
40
- this.logger.info(' unset OPNET_MLDSA_KEY');
41
- return;
42
- }
43
-
44
- if (!options.yes) {
45
- this.logger.warn('This will remove your stored credentials from:');
46
- this.logger.info(` ${source}`);
47
-
48
- const confirmed = await confirm({
49
- message: 'Are you sure you want to logout?',
50
- default: false,
51
- });
52
-
53
- if (!confirmed) {
54
- this.logger.warn('Logout cancelled.');
55
- return;
56
- }
57
- }
58
-
59
- const deleted = deleteCredentials();
60
-
61
- if (deleted) {
62
- this.logger.success('Credentials removed successfully.');
63
- } else {
64
- this.logger.warn('No credentials file found to remove.');
65
- }
66
- } catch (error) {
67
- if (this.isUserCancelled(error)) {
68
- this.logger.warn('Logout cancelled.');
69
- process.exit(0);
70
- }
71
- this.exitWithError(this.formatError(error));
72
- }
73
- }
74
- }
75
-
76
- export const logoutCommand = new LogoutCommand().getCommand();
@@ -1,340 +0,0 @@
1
- /**
2
- * Publish command - Publish plugin to the OPNet registry
3
- *
4
- * @module commands/PublishCommand
5
- */
6
-
7
- import * as fs from 'fs';
8
- import * as path from 'path';
9
- import * as crypto from 'crypto';
10
- import { confirm } from '@inquirer/prompts';
11
- import { BaseCommand } from './BaseCommand.js';
12
- import { formatFileSize, parseOpnetBinary, verifyChecksum } from '../lib/binary.js';
13
- import { CLIWallet } from '../lib/wallet.js';
14
- import { canSign, loadCredentials } from '../lib/credentials.js';
15
- import { uploadPlugin } from '../lib/ipfs.js';
16
- import {
17
- computePermissionsHash,
18
- encodeDependencies,
19
- getPackage,
20
- getRegistryContract,
21
- getScope,
22
- mldsaLevelToRegistry,
23
- parsePackageName,
24
- pluginTypeToRegistry,
25
- } from '../lib/registry.js';
26
- import {
27
- buildTransactionParams,
28
- checkBalance,
29
- DEFAULT_FEE_RATE,
30
- DEFAULT_MAX_SAT_TO_SPEND,
31
- formatSats,
32
- getWalletAddress,
33
- waitForTransactionConfirmation,
34
- } from '../lib/transaction.js';
35
- import { CLIMldsaLevel, NetworkName } from '../types/index.js';
36
- import { PsbtOutputExtended } from '@btc-vision/bitcoin';
37
- import { StrippedTransactionOutput, TransactionOutputFlags } from 'opnet';
38
-
39
- interface PublishOptions {
40
- network: string;
41
- dryRun?: boolean;
42
- yes?: boolean;
43
- }
44
-
45
- export class PublishCommand extends BaseCommand {
46
- constructor() {
47
- super('publish', 'Publish a plugin to the OPNet registry');
48
- }
49
-
50
- protected configure(): void {
51
- this.command
52
- .argument('[file]', 'Path to .opnet file (default: ./build/<name>.opnet)')
53
- .option('-n, --network <network>', 'Network to publish to', 'mainnet')
54
- .option('--dry-run', 'Show what would be published without publishing')
55
- .option('-y, --yes', 'Skip confirmation prompts')
56
- .action((file?: string, options?: PublishOptions) =>
57
- this.execute(file, options || { network: 'mainnet' }),
58
- );
59
- }
60
-
61
- private async execute(file?: string, options?: PublishOptions): Promise<void> {
62
- try {
63
- // Find the .opnet file
64
- let binaryPath = file;
65
- if (!binaryPath) {
66
- const manifestPath = path.join(process.cwd(), 'plugin.json');
67
- if (fs.existsSync(manifestPath)) {
68
- const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) as {
69
- name: string;
70
- };
71
- const name = manifest.name.replace(/^@/, '').replace(/\//g, '-');
72
- binaryPath = path.join(process.cwd(), 'build', `${name}.opnet`);
73
- }
74
- }
75
-
76
- if (!binaryPath || !fs.existsSync(binaryPath)) {
77
- this.logger.fail('No .opnet file found.');
78
- this.logger.info('Run `opnet compile` first or specify the file path.');
79
- process.exit(1);
80
- }
81
-
82
- // Parse and validate binary
83
- this.logger.info('Parsing plugin binary...');
84
- const data = fs.readFileSync(binaryPath);
85
- const parsed = parseOpnetBinary(data);
86
-
87
- // Verify checksum
88
- if (!verifyChecksum(parsed)) {
89
- this.logger.fail('Checksum verification failed');
90
- this.logger.error('The binary appears to be corrupted.');
91
- process.exit(1);
92
- }
93
-
94
- // Check if signed
95
- const isUnsigned = parsed.publicKey.every((b) => b === 0);
96
- if (isUnsigned) {
97
- this.logger.fail('Binary is unsigned');
98
- this.logger.error('Cannot publish unsigned binaries.');
99
- this.logger.info('Run `opnet sign` to sign the binary.');
100
- process.exit(1);
101
- }
102
-
103
- const meta = parsed.metadata;
104
- const mldsaLevel = ([44, 65, 87] as const)[parsed.mldsaLevel] as CLIMldsaLevel;
105
- this.logger.success(`Parsed: ${meta.name}@${meta.version}`);
106
-
107
- // Load wallet and verify ownership
108
- this.logger.info('Loading wallet...');
109
- const credentials = loadCredentials();
110
- if (!credentials || !canSign(credentials)) {
111
- this.logger.fail('No credentials configured');
112
- this.logger.warn('Run `opnet login` to configure your wallet.');
113
- process.exit(1);
114
- }
115
-
116
- const wallet = CLIWallet.fromCredentials(credentials);
117
- const walletPkHash = wallet.mldsaPublicKeyHash;
118
- const binaryPkHash = crypto.createHash('sha256').update(parsed.publicKey).digest('hex');
119
-
120
- if (walletPkHash !== binaryPkHash) {
121
- this.logger.fail('Wallet mismatch');
122
- this.logger.error('The binary was signed with a different key.');
123
- this.logger.log(`Binary signer: ${binaryPkHash.substring(0, 32)}...`);
124
- this.logger.log(`Your key: ${walletPkHash.substring(0, 32)}...`);
125
- process.exit(1);
126
- }
127
- this.logger.success('Wallet verified');
128
-
129
- // Check registry status
130
- this.logger.info('Checking registry status...');
131
- const { scope } = parsePackageName(meta.name);
132
- const network = (options?.network || 'mainnet') as NetworkName;
133
-
134
- // Check if scoped package
135
- if (scope) {
136
- const scopeInfo = await getScope(scope, network);
137
-
138
- if (!scopeInfo) {
139
- this.logger.fail(`Scope @${scope} is not registered`);
140
- this.logger.warn(
141
- `Register the scope first with: opnet scope register ${scope}`,
142
- );
143
- process.exit(1);
144
- }
145
- }
146
-
147
- const packageInfo = await getPackage(meta.name, network);
148
- const isNewPackage = !packageInfo;
149
- this.logger.success(
150
- isNewPackage
151
- ? 'New package registration'
152
- : `Existing package (${packageInfo.versionCount} versions)`,
153
- );
154
-
155
- // Display summary
156
- this.logger.log('');
157
- this.logger.info('Publishing Summary');
158
- this.logger.log('─'.repeat(50));
159
- this.logger.log(`Package: ${meta.name}`);
160
- this.logger.log(`Version: ${meta.version}`);
161
- this.logger.log(`Type: ${meta.pluginType}`);
162
- this.logger.log(`OPNet: ${meta.opnetVersion}`);
163
- this.logger.log(`Size: ${formatFileSize(data.length)}`);
164
- this.logger.log(`MLDSA Level: ${mldsaLevel}`);
165
- this.logger.log(`Network: ${options?.network}`);
166
- this.logger.log(`Status: ${isNewPackage ? 'New package' : 'New version'}`);
167
- this.logger.log('');
168
-
169
- if (options?.dryRun) {
170
- this.logger.warn('Dry run - no changes made.');
171
- return;
172
- }
173
-
174
- // Confirmation
175
- if (!options?.yes) {
176
- const confirmed = await confirm({
177
- message: 'Publish this plugin?',
178
- default: true,
179
- });
180
-
181
- if (!confirmed) {
182
- this.logger.warn('Publishing cancelled.');
183
- return;
184
- }
185
- }
186
-
187
- // Upload to IPFS
188
- this.logger.info('Uploading to IPFS...');
189
- const pinResult = await uploadPlugin(binaryPath);
190
- this.logger.success(`Uploaded to IPFS: ${pinResult.cid}`);
191
-
192
- // Prepare registry data
193
- const permissionsHash = computePermissionsHash(meta.permissions);
194
- const dependencies = encodeDependencies(meta.dependencies || {});
195
-
196
- // Check wallet balance
197
- this.logger.info('Checking wallet balance...');
198
- const { sufficient, balance } = await checkBalance(wallet, network);
199
- if (!sufficient) {
200
- this.logger.fail('Insufficient balance');
201
- this.logger.error(`Wallet balance: ${formatSats(balance)}`);
202
- this.logger.error('Please fund your wallet before publishing.');
203
- process.exit(1);
204
- }
205
- this.logger.success(`Wallet balance: ${formatSats(balance)}`);
206
-
207
- // Get contract with sender for write operations
208
- const sender = getWalletAddress(wallet);
209
- const contract = getRegistryContract(network, sender);
210
-
211
- const treasuryAddress = await contract.getTreasuryAddress();
212
-
213
- const extraUtxo: PsbtOutputExtended = {
214
- address: treasuryAddress.properties.treasuryAddress,
215
- value: 10_000,
216
- };
217
-
218
- let txParams = buildTransactionParams(
219
- wallet,
220
- network,
221
- DEFAULT_MAX_SAT_TO_SPEND,
222
- DEFAULT_FEE_RATE,
223
- extraUtxo,
224
- );
225
-
226
- // Register package if new
227
- if (isNewPackage) {
228
- this.logger.info('Registering new package...');
229
-
230
- const outSimulation: StrippedTransactionOutput[] = [
231
- {
232
- index: 1,
233
- to: treasuryAddress.properties.treasuryAddress,
234
- value: 10_000n,
235
- flags: TransactionOutputFlags.hasTo,
236
- scriptPubKey: undefined,
237
- },
238
- ];
239
-
240
- contract.setTransactionDetails({
241
- inputs: [],
242
- outputs: outSimulation,
243
- });
244
-
245
- const registerResult = await contract.registerPackage(meta.name);
246
- if (registerResult.revert) {
247
- this.logger.fail('Package registration would fail');
248
- this.logger.error(`Reason: ${registerResult.revert}`);
249
- process.exit(1);
250
- }
251
-
252
- if (registerResult.estimatedGas) {
253
- this.logger.info(`Estimated gas: ${registerResult.estimatedGas} sats`);
254
- }
255
-
256
- const registerReceipt = await registerResult.sendTransaction(txParams);
257
- this.logger.success('Package registration transaction sent');
258
- this.logger.log(`Transaction ID: ${registerReceipt.transactionId}`);
259
- this.logger.log('');
260
-
261
- // Wait for registration transaction to be confirmed
262
- const confirmationResult = await waitForTransactionConfirmation(
263
- registerReceipt.transactionId,
264
- network,
265
- {
266
- message: 'Waiting for package registration to confirm',
267
- },
268
- );
269
-
270
- if (!confirmationResult.confirmed) {
271
- if (confirmationResult.revert) {
272
- this.logger.fail('Package registration failed');
273
- this.logger.error(`Reason: ${confirmationResult.revert}`);
274
- } else if (confirmationResult.error) {
275
- this.logger.fail('Package registration not confirmed');
276
- this.logger.error(confirmationResult.error);
277
- }
278
- process.exit(1);
279
- }
280
-
281
- this.logger.log('');
282
- }
283
-
284
- txParams = buildTransactionParams(
285
- wallet,
286
- network,
287
- DEFAULT_MAX_SAT_TO_SPEND,
288
- DEFAULT_FEE_RATE,
289
- );
290
-
291
- // Publish version
292
- this.logger.info('Publishing version...');
293
-
294
- const publishResult = await contract.publishVersion(
295
- meta.name,
296
- meta.version,
297
- pinResult.cid,
298
- new Uint8Array(parsed.checksum),
299
- new Uint8Array(parsed.signature),
300
- mldsaLevelToRegistry(mldsaLevel),
301
- meta.opnetVersion,
302
- pluginTypeToRegistry(meta.pluginType),
303
- permissionsHash,
304
- dependencies,
305
- );
306
-
307
- if (publishResult.revert) {
308
- this.logger.fail('Version publishing would fail');
309
- this.logger.error(`Reason: ${publishResult.revert}`);
310
- process.exit(1);
311
- }
312
-
313
- if (publishResult.estimatedGas) {
314
- this.logger.info(`Estimated gas: ${publishResult.estimatedGas} sats`);
315
- }
316
-
317
- const publishReceipt = await publishResult.sendTransaction(txParams);
318
-
319
- this.logger.log('');
320
- this.logger.success('Plugin published successfully!');
321
- this.logger.log('');
322
- this.logger.log(`Package: ${meta.name}`);
323
- this.logger.log(`Version: ${meta.version}`);
324
- this.logger.log(`IPFS CID: ${pinResult.cid}`);
325
- this.logger.log(`Transaction ID: ${publishReceipt.transactionId}`);
326
- this.logger.log(`Fees paid: ${formatSats(publishReceipt.estimatedFees)}`);
327
- this.logger.log(`Gateway: https://ipfs.opnet.org/ipfs/${pinResult.cid}`);
328
- this.logger.log('');
329
- } catch (error) {
330
- this.logger.fail(`Publishing failed`);
331
- if (this.isUserCancelled(error)) {
332
- this.logger.warn('Publishing cancelled.');
333
- process.exit(0);
334
- }
335
- this.exitWithError(this.formatError(error));
336
- }
337
- }
338
- }
339
-
340
- export const publishCommand = new PublishCommand().getCommand();