@btc-vision/cli 1.0.1 → 1.0.3

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/README.md +55 -23
  2. package/build/commands/AcceptCommand.js +62 -15
  3. package/build/commands/CompileCommand.js +9 -10
  4. package/build/commands/ConfigCommand.js +2 -27
  5. package/build/commands/DeprecateCommand.js +32 -11
  6. package/build/commands/InitCommand.js +1 -7
  7. package/build/commands/PublishCommand.js +82 -27
  8. package/build/commands/ScopeRegisterCommand.d.ts +7 -0
  9. package/build/commands/ScopeRegisterCommand.js +115 -0
  10. package/build/commands/SignCommand.js +6 -9
  11. package/build/commands/TransferCommand.js +118 -30
  12. package/build/commands/UndeprecateCommand.js +31 -10
  13. package/build/index.js +2 -0
  14. package/build/lib/binary.d.ts +5 -2
  15. package/build/lib/binary.js +11 -6
  16. package/build/lib/config.d.ts +1 -0
  17. package/build/lib/config.js +3 -2
  18. package/build/lib/ipfs.js +85 -76
  19. package/build/lib/manifest.js +1 -1
  20. package/build/lib/registry.d.ts +1 -1
  21. package/build/lib/registry.js +3 -3
  22. package/build/lib/transaction.d.ts +27 -0
  23. package/build/lib/transaction.js +91 -0
  24. package/build/lib/wallet.d.ts +7 -7
  25. package/build/lib/wallet.js +3 -6
  26. package/build/types/index.d.ts +1 -0
  27. package/package.json +2 -1
  28. package/src/commands/AcceptCommand.ts +89 -16
  29. package/src/commands/CompileCommand.ts +13 -14
  30. package/src/commands/ConfigCommand.ts +2 -29
  31. package/src/commands/DeprecateCommand.ts +48 -11
  32. package/src/commands/InitCommand.ts +1 -7
  33. package/src/commands/PublishCommand.ts +138 -28
  34. package/src/commands/ScopeRegisterCommand.ts +164 -0
  35. package/src/commands/SignCommand.ts +9 -21
  36. package/src/commands/TransferCommand.ts +159 -31
  37. package/src/commands/UndeprecateCommand.ts +43 -10
  38. package/src/index.ts +2 -0
  39. package/src/lib/binary.ts +24 -22
  40. package/src/lib/config.ts +3 -2
  41. package/src/lib/ipfs.ts +113 -99
  42. package/src/lib/manifest.ts +1 -1
  43. package/src/lib/registry.ts +5 -2
  44. package/src/lib/transaction.ts +205 -0
  45. package/src/lib/wallet.ts +10 -19
  46. package/src/types/index.ts +3 -1
@@ -8,8 +8,7 @@ import { Command } from 'commander';
8
8
  import * as os from 'os';
9
9
  import * as path from 'path';
10
10
  import { BaseCommand } from './BaseCommand.js';
11
- import { displayConfig, getConfigValue, saveConfig, setConfigValue } from '../lib/config.js';
12
- import { CLIConfig } from '../types/index.js';
11
+ import { DEFAULT_CONFIG, displayConfig, getConfigValue, saveConfig, setConfigValue, } from '../lib/config.js';
13
12
 
14
13
  export class ConfigCommand extends BaseCommand {
15
14
  constructor() {
@@ -106,33 +105,7 @@ export class ConfigCommand extends BaseCommand {
106
105
  return;
107
106
  }
108
107
 
109
- const defaultConfig: CLIConfig = {
110
- defaultNetwork: 'mainnet',
111
- rpcUrls: {
112
- mainnet: 'https://api.opnet.org',
113
- testnet: 'https://testnet.opnet.org',
114
- regtest: 'http://localhost:9001',
115
- },
116
- ipfsGateway: 'https://ipfs.opnet.org/ipfs/',
117
- ipfsGateways: [
118
- 'https://ipfs.opnet.org/ipfs/',
119
- 'https://ipfs.io/ipfs/',
120
- 'https://cloudflare-ipfs.com/ipfs/',
121
- 'https://dweb.link/ipfs/',
122
- ],
123
- ipfsPinningEndpoint: 'https://ipfs.opnet.org/api/v0/add',
124
- ipfsPinningApiKey: '',
125
- ipfsPinningAuthHeader: 'Authorization',
126
- registryAddresses: {
127
- mainnet: '',
128
- testnet: '',
129
- regtest: '',
130
- },
131
- defaultMldsaLevel: 44,
132
- indexerUrl: 'https://indexer.opnet.org',
133
- };
134
-
135
- saveConfig(defaultConfig);
108
+ saveConfig(DEFAULT_CONFIG);
136
109
  this.logger.success('Configuration reset to defaults.');
137
110
  }
138
111
 
@@ -6,9 +6,15 @@
6
6
 
7
7
  import { confirm, input } from '@inquirer/prompts';
8
8
  import { BaseCommand } from './BaseCommand.js';
9
- import { getPackage, getVersion, isVersionImmutable } from '../lib/registry.js';
9
+ import { getPackage, getRegistryContract, getVersion, isVersionImmutable } from '../lib/registry.js';
10
10
  import { canSign, loadCredentials } from '../lib/credentials.js';
11
11
  import { CLIWallet } from '../lib/wallet.js';
12
+ import {
13
+ buildTransactionParams,
14
+ checkBalance,
15
+ formatSats,
16
+ getWalletAddress,
17
+ } from '../lib/transaction.js';
12
18
  import { NetworkName } from '../types/index.js';
13
19
 
14
20
  interface DeprecateOptions {
@@ -48,7 +54,7 @@ export class DeprecateCommand extends BaseCommand {
48
54
  this.logger.warn('Run `opnet login` to configure your wallet.');
49
55
  process.exit(1);
50
56
  }
51
- CLIWallet.fromCredentials(credentials);
57
+ const wallet = CLIWallet.fromCredentials(credentials);
52
58
  this.logger.success('Wallet loaded');
53
59
 
54
60
  // Get package info
@@ -128,19 +134,50 @@ export class DeprecateCommand extends BaseCommand {
128
134
  }
129
135
  }
130
136
 
137
+ // Check wallet balance
138
+ this.logger.info('Checking wallet balance...');
139
+ const { sufficient, balance } = await checkBalance(wallet, network);
140
+ if (!sufficient) {
141
+ this.logger.fail('Insufficient balance');
142
+ this.logger.error(`Wallet balance: ${formatSats(balance)}`);
143
+ this.logger.error('Please fund your wallet before deprecating.');
144
+ process.exit(1);
145
+ }
146
+ this.logger.success(`Wallet balance: ${formatSats(balance)}`);
147
+
131
148
  // Execute deprecation
132
149
  this.logger.info('Deprecating version...');
133
- this.logger.warn('Deprecation transaction required.');
134
- this.logger.log('Transaction would call: deprecateVersion(');
135
- this.logger.log(` packageName: "${packageName}",`);
136
- this.logger.log(` version: "${targetVersion}",`);
137
- this.logger.log(` reason: "${message}"`);
138
- this.logger.log(')');
139
- this.logger.info('Deprecation (transaction pending)');
140
150
 
151
+ const sender = getWalletAddress(wallet);
152
+ const contract = getRegistryContract(network, sender);
153
+ const txParams = buildTransactionParams(wallet, network);
154
+
155
+ const deprecateResult = await contract.deprecateVersion(
156
+ packageName,
157
+ targetVersion,
158
+ message,
159
+ );
160
+
161
+ if (deprecateResult.revert) {
162
+ this.logger.fail('Deprecation would fail');
163
+ this.logger.error(`Reason: ${deprecateResult.revert}`);
164
+ process.exit(1);
165
+ }
166
+
167
+ if (deprecateResult.estimatedGas) {
168
+ this.logger.info(`Estimated gas: ${deprecateResult.estimatedGas} sats`);
169
+ }
170
+
171
+ const receipt = await deprecateResult.sendTransaction(txParams);
172
+
173
+ this.logger.log('');
174
+ this.logger.success('Version deprecated successfully!');
141
175
  this.logger.log('');
142
- this.logger.success('Deprecation submitted!');
143
- this.logger.warn('Note: Registry transaction support is coming soon.');
176
+ this.logger.log(`Package: ${packageName}`);
177
+ this.logger.log(`Version: ${targetVersion}`);
178
+ this.logger.log(`Reason: ${message}`);
179
+ this.logger.log(`Transaction ID: ${receipt.transactionId}`);
180
+ this.logger.log(`Fees paid: ${formatSats(receipt.estimatedFees)}`);
144
181
  this.logger.log('');
145
182
  } catch (error) {
146
183
  this.logger.fail('Deprecation failed');
@@ -185,7 +185,7 @@ export class InitCommand extends BaseCommand {
185
185
  const manifest: Record<string, unknown> = {
186
186
  name: config.pluginName,
187
187
  version: '1.0.0',
188
- opnetVersion: '^1.0.0',
188
+ opnetVersion: '>=0.0.1',
189
189
  main: 'dist/index.jsc',
190
190
  target: 'bytenode',
191
191
  type: 'plugin',
@@ -223,12 +223,6 @@ export class InitCommand extends BaseCommand {
223
223
  configDir: false,
224
224
  tempDir: false,
225
225
  },
226
- blockchain: {
227
- blocks: false,
228
- transactions: false,
229
- contracts: false,
230
- utxos: false,
231
- },
232
226
  },
233
227
  resources: {
234
228
  memory: {
@@ -17,12 +17,24 @@ import {
17
17
  computePermissionsHash,
18
18
  encodeDependencies,
19
19
  getPackage,
20
+ getRegistryContract,
20
21
  getScope,
21
22
  mldsaLevelToRegistry,
22
23
  parsePackageName,
23
24
  pluginTypeToRegistry,
24
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';
25
35
  import { CLIMldsaLevel, NetworkName } from '../types/index.js';
36
+ import { PsbtOutputExtended } from '@btc-vision/bitcoin';
37
+ import { StrippedTransactionOutput, TransactionOutputFlags } from 'opnet';
26
38
 
27
39
  interface PublishOptions {
28
40
  network: string;
@@ -116,12 +128,13 @@ export class PublishCommand extends BaseCommand {
116
128
 
117
129
  // Check registry status
118
130
  this.logger.info('Checking registry status...');
119
- const { scope, name } = parsePackageName(meta.name);
131
+ const { scope } = parsePackageName(meta.name);
120
132
  const network = (options?.network || 'mainnet') as NetworkName;
121
133
 
122
134
  // Check if scoped package
123
135
  if (scope) {
124
136
  const scopeInfo = await getScope(scope, network);
137
+
125
138
  if (!scopeInfo) {
126
139
  this.logger.fail(`Scope @${scope} is not registered`);
127
140
  this.logger.warn(
@@ -180,44 +193,141 @@ export class PublishCommand extends BaseCommand {
180
193
  const permissionsHash = computePermissionsHash(meta.permissions);
181
194
  const dependencies = encodeDependencies(meta.dependencies || {});
182
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
+
183
226
  // Register package if new
184
227
  if (isNewPackage) {
185
- this.logger.info('Registering package...');
186
- this.logger.warn('Package registration required.');
187
- this.logger.log(`Transaction would call: registerPackage("${meta.name}")`);
188
- this.logger.info('Package registration (transaction pending)');
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('');
189
282
  }
190
283
 
284
+ txParams = buildTransactionParams(
285
+ wallet,
286
+ network,
287
+ DEFAULT_MAX_SAT_TO_SPEND,
288
+ DEFAULT_FEE_RATE,
289
+ );
290
+
191
291
  // Publish version
192
292
  this.logger.info('Publishing version...');
193
- this.logger.warn('Version publishing required.');
194
- this.logger.log('Transaction would call: publishVersion(');
195
- this.logger.log(` packageName: "${meta.name}",`);
196
- this.logger.log(` version: "${meta.version}",`);
197
- this.logger.log(` ipfsCid: "${pinResult.cid}",`);
198
- this.logger.log(` checksum: <32 bytes>,`);
199
- this.logger.log(` signature: <${parsed.signature.length} bytes>,`);
200
- this.logger.log(` mldsaLevel: ${mldsaLevelToRegistry(mldsaLevel)},`);
201
- this.logger.log(` opnetVersionRange: "${meta.opnetVersion}",`);
202
- this.logger.log(` pluginType: ${pluginTypeToRegistry(meta.pluginType)},`);
203
- this.logger.log(` permissionsHash: <32 bytes>,`);
204
- this.logger.log(` dependencies: <${dependencies.length} bytes>`);
205
- this.logger.log(')');
206
- this.logger.info('Version publishing (transaction pending)');
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);
207
318
 
208
319
  this.logger.log('');
209
- this.logger.success('Plugin uploaded successfully!');
210
- this.logger.log('');
211
- this.logger.log(`IPFS CID: ${pinResult.cid}`);
212
- this.logger.log(`Gateway: https://ipfs.opnet.org/ipfs/${pinResult.cid}`);
320
+ this.logger.success('Plugin published successfully!');
213
321
  this.logger.log('');
214
- this.logger.warn('Note: Registry transaction support is coming soon.');
215
- this.logger.warn(
216
- 'The binary has been uploaded to IPFS and is ready for registry submission.',
217
- );
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}`);
218
328
  this.logger.log('');
219
329
  } catch (error) {
220
- this.logger.fail('Publishing failed');
330
+ this.logger.fail(`Publishing failed`);
221
331
  if (this.isUserCancelled(error)) {
222
332
  this.logger.warn('Publishing cancelled.');
223
333
  process.exit(0);
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Scope Register command - Register a new scope in the registry
3
+ *
4
+ * @module commands/ScopeRegisterCommand
5
+ */
6
+
7
+ import { confirm } from '@inquirer/prompts';
8
+ import { BaseCommand } from './BaseCommand.js';
9
+ import { getRegistryContract, getScope, getScopePrice } from '../lib/registry.js';
10
+ import { canSign, loadCredentials } from '../lib/credentials.js';
11
+ import { CLIWallet } from '../lib/wallet.js';
12
+ import {
13
+ buildTransactionParams,
14
+ checkBalance,
15
+ formatSats,
16
+ getWalletAddress,
17
+ } from '../lib/transaction.js';
18
+ import { NetworkName } from '../types/index.js';
19
+
20
+ interface ScopeRegisterOptions {
21
+ network: string;
22
+ yes?: boolean;
23
+ }
24
+
25
+ export class ScopeRegisterCommand extends BaseCommand {
26
+ constructor() {
27
+ super('scope:register', 'Register a new scope in the registry');
28
+ }
29
+
30
+ protected configure(): void {
31
+ this.command
32
+ .argument('<name>', 'Scope name (without @)')
33
+ .option('-n, --network <network>', 'Network', 'mainnet')
34
+ .option('-y, --yes', 'Skip confirmation')
35
+ .action((name: string, options?: ScopeRegisterOptions) =>
36
+ this.execute(name, options || { network: 'mainnet' }),
37
+ );
38
+ }
39
+
40
+ private async execute(name: string, options?: ScopeRegisterOptions): Promise<void> {
41
+ try {
42
+ // Remove @ prefix if provided
43
+ const scopeName = name.startsWith('@') ? name.substring(1) : name;
44
+
45
+ // Validate scope name
46
+ if (!/^[a-z][a-z0-9-]*[a-z0-9]$/.test(scopeName) && !/^[a-z]$/.test(scopeName)) {
47
+ this.logger.fail('Invalid scope name');
48
+ this.logger.error('Scope name must:');
49
+ this.logger.error(' - Start with a lowercase letter');
50
+ this.logger.error(' - Contain only lowercase letters, numbers, and hyphens');
51
+ this.logger.error(' - End with a letter or number');
52
+ process.exit(1);
53
+ }
54
+
55
+ // Load credentials
56
+ this.logger.info('Loading wallet...');
57
+ const credentials = loadCredentials();
58
+ if (!credentials || !canSign(credentials)) {
59
+ this.logger.fail('No credentials configured');
60
+ this.logger.warn('Run `opnet login` to configure your wallet.');
61
+ process.exit(1);
62
+ }
63
+ const wallet = CLIWallet.fromCredentials(credentials);
64
+ this.logger.success('Wallet loaded');
65
+
66
+ const network = (options?.network || 'mainnet') as NetworkName;
67
+
68
+ // Check if scope already exists
69
+ this.logger.info(`Checking if @${scopeName} is available...`);
70
+ const existingScope = await getScope(scopeName, network);
71
+ if (existingScope) {
72
+ this.logger.fail('Scope already registered');
73
+ this.logger.error(`Scope @${scopeName} is already registered.`);
74
+ this.logger.log(`Owner: ${existingScope.owner}`);
75
+ process.exit(1);
76
+ }
77
+ this.logger.success(`Scope @${scopeName} is available`);
78
+
79
+ // Get scope registration price
80
+ this.logger.info('Fetching registration price...');
81
+ const scopePrice = await getScopePrice(network);
82
+ this.logger.success(`Registration price: ${formatSats(scopePrice)}`);
83
+
84
+ // Check wallet balance
85
+ this.logger.info('Checking wallet balance...');
86
+ const minRequired = scopePrice + 50_000n; // Price + estimated fees
87
+ const { sufficient, balance } = await checkBalance(wallet, network, minRequired);
88
+ if (!sufficient) {
89
+ this.logger.fail('Insufficient balance');
90
+ this.logger.error(`Wallet balance: ${formatSats(balance)}`);
91
+ this.logger.error(`Required (approx): ${formatSats(minRequired)}`);
92
+ this.logger.error('Please fund your wallet before registering a scope.');
93
+ process.exit(1);
94
+ }
95
+ this.logger.success(`Wallet balance: ${formatSats(balance)}`);
96
+
97
+ // Display summary
98
+ this.logger.log('');
99
+ this.logger.info('Scope Registration Summary');
100
+ this.logger.log('─'.repeat(50));
101
+ this.logger.log(`Scope: @${scopeName}`);
102
+ this.logger.log(`Price: ${formatSats(scopePrice)}`);
103
+ this.logger.log(`Network: ${options?.network}`);
104
+ this.logger.log(`Address: ${wallet.p2trAddress}`);
105
+ this.logger.log('');
106
+
107
+ // Confirmation
108
+ if (!options?.yes) {
109
+ const confirmed = await confirm({
110
+ message: `Register scope @${scopeName}?`,
111
+ default: true,
112
+ });
113
+
114
+ if (!confirmed) {
115
+ this.logger.warn('Registration cancelled.');
116
+ return;
117
+ }
118
+ }
119
+
120
+ // Execute registration
121
+ this.logger.info('Registering scope...');
122
+
123
+ const sender = getWalletAddress(wallet);
124
+ const contract = getRegistryContract(network, sender);
125
+ const txParams = buildTransactionParams(wallet, network);
126
+
127
+ const registerResult = await contract.registerScope(scopeName);
128
+
129
+ if (registerResult.revert) {
130
+ this.logger.fail('Registration would fail');
131
+ this.logger.error(`Reason: ${registerResult.revert}`);
132
+ process.exit(1);
133
+ }
134
+
135
+ if (registerResult.estimatedGas) {
136
+ this.logger.info(`Estimated gas: ${registerResult.estimatedGas} sats`);
137
+ }
138
+
139
+ const receipt = await registerResult.sendTransaction(txParams);
140
+
141
+ this.logger.log('');
142
+ this.logger.success('Scope registered successfully!');
143
+ this.logger.log('');
144
+ this.logger.log(`Scope: @${scopeName}`);
145
+ this.logger.log(`Owner: ${wallet.p2trAddress}`);
146
+ this.logger.log(`Transaction ID: ${receipt.transactionId}`);
147
+ this.logger.log(`Fees paid: ${formatSats(receipt.estimatedFees)}`);
148
+ this.logger.log('');
149
+ this.logger.info(
150
+ 'You can now publish packages under this scope using: opnet publish',
151
+ );
152
+ this.logger.log('');
153
+ } catch (error) {
154
+ this.logger.fail('Scope registration failed');
155
+ if (this.isUserCancelled(error)) {
156
+ this.logger.warn('Registration cancelled.');
157
+ process.exit(0);
158
+ }
159
+ this.exitWithError(this.formatError(error));
160
+ }
161
+ }
162
+ }
163
+
164
+ export const scopeRegisterCommand = new ScopeRegisterCommand().getCommand();
@@ -7,12 +7,7 @@
7
7
  import * as fs from 'fs';
8
8
  import * as crypto from 'crypto';
9
9
  import { BaseCommand } from './BaseCommand.js';
10
- import {
11
- buildOpnetBinary,
12
- computeChecksum,
13
- formatFileSize,
14
- parseOpnetBinary,
15
- } from '../lib/binary.js';
10
+ import { buildOpnetBinary, formatFileSize, parseOpnetBinary } from '../lib/binary.js';
16
11
  import { CLIWallet } from '../lib/wallet.js';
17
12
  import { canSign, loadCredentials } from '../lib/credentials.js';
18
13
 
@@ -77,27 +72,20 @@ export class SignCommand extends BaseCommand {
77
72
  process.exit(1);
78
73
  }
79
74
 
80
- // Compute new signature
81
- this.logger.info('Signing...');
82
- const metadataBytes = Buffer.from(parsed.rawMetadata, 'utf-8');
83
- const checksum = computeChecksum(
84
- metadataBytes,
85
- parsed.bytecode,
86
- parsed.proto ?? Buffer.alloc(0),
87
- );
88
- const signature = wallet.signMLDSA(checksum);
89
- this.logger.success(`Signed (${formatFileSize(signature.length)} signature)`);
90
-
91
- // Rebuild binary
92
- this.logger.info('Rebuilding binary...');
93
- const newBinary = buildOpnetBinary({
75
+ // Rebuild binary with signing
76
+ this.logger.info('Signing and rebuilding binary...');
77
+ const signFn = (checksum: Buffer) => wallet.signMLDSA(checksum);
78
+ const { binary: newBinary, checksum } = buildOpnetBinary({
94
79
  mldsaLevel: wallet.securityLevel,
95
80
  publicKey: wallet.mldsaPublicKey,
96
- signature,
97
81
  metadata: parsed.metadata,
98
82
  bytecode: parsed.bytecode,
99
83
  proto: parsed.proto ?? Buffer.alloc(0),
84
+ signFn,
100
85
  });
86
+ this.logger.success(
87
+ `Signed (checksum: sha256:${checksum.toString('hex').substring(0, 16)}...)`,
88
+ );
101
89
  this.logger.success(`Binary rebuilt (${formatFileSize(newBinary.length)})`);
102
90
 
103
91
  // Write output