@btc-vision/cli 1.0.12 → 1.1.0

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.
@@ -4,7 +4,7 @@ import * as esbuild from 'esbuild';
4
4
  import bytenode from 'bytenode';
5
5
  import { BaseCommand } from './BaseCommand.js';
6
6
  import { getManifestPath, loadManifest } from '../lib/manifest.js';
7
- import { buildOpnetBinary, formatFileSize } from '../lib/binary.js';
7
+ import { buildOpnetBinary, formatFileSize, toHex } from '../lib/binary.js';
8
8
  import { CLIWallet } from '../lib/wallet.js';
9
9
  import { canSign, loadCredentials } from '../lib/credentials.js';
10
10
  export class CompileCommand extends BaseCommand {
@@ -63,7 +63,7 @@ export class CompileCommand extends BaseCommand {
63
63
  });
64
64
  const bytecode = fs.readFileSync(bytecodePath);
65
65
  this.logger.success(`V8 bytecode generated (${formatFileSize(bytecode.length)})`);
66
- let proto = Buffer.alloc(0);
66
+ let proto = new Uint8Array(0);
67
67
  const protoPath = path.join(projectDir, 'plugin.proto');
68
68
  if (fs.existsSync(protoPath)) {
69
69
  proto = fs.readFileSync(protoPath);
@@ -90,7 +90,7 @@ export class CompileCommand extends BaseCommand {
90
90
  else {
91
91
  this.logger.warn('Skipping signing (--no-sign)');
92
92
  mldsaLevel = 44;
93
- publicKey = Buffer.alloc(1312);
93
+ publicKey = new Uint8Array(1312);
94
94
  }
95
95
  this.logger.info('Assembling .opnet binary...');
96
96
  const { binary, checksum } = buildOpnetBinary({
@@ -102,7 +102,7 @@ export class CompileCommand extends BaseCommand {
102
102
  signFn,
103
103
  });
104
104
  if (options.sign) {
105
- this.logger.success(`Plugin signed (checksum: sha256:${checksum.toString('hex').substring(0, 16)}...)`);
105
+ this.logger.success(`Plugin signed (checksum: sha256:${toHex(checksum).substring(0, 16)}...)`);
106
106
  }
107
107
  this.logger.success(`Binary assembled (${formatFileSize(binary.length)})`);
108
108
  const outputPath = options.output ||
@@ -119,7 +119,7 @@ export class CompileCommand extends BaseCommand {
119
119
  this.logger.log(`Plugin: ${manifest.name}@${manifest.version}`);
120
120
  this.logger.log(`Type: ${manifest.pluginType}`);
121
121
  this.logger.log(`MLDSA Level: ${mldsaLevel}`);
122
- this.logger.log(`Checksum: sha256:${checksum.toString('hex')}`);
122
+ this.logger.log(`Checksum: sha256:${toHex(checksum)}`);
123
123
  this.logger.log(`Signed: ${options.sign ? 'Yes' : 'No'}`);
124
124
  this.logger.log('');
125
125
  if (!options.sign) {
@@ -2,6 +2,7 @@ import { Command } from 'commander';
2
2
  import { confirm } from '@inquirer/prompts';
3
3
  import { Logger } from '@btc-vision/logger';
4
4
  import { CLIWallet } from '../lib/wallet.js';
5
+ import { toHex } from '../lib/binary.js';
5
6
  import { canSign, loadCredentials } from '../lib/credentials.js';
6
7
  import { getContenthash, getContenthashTypeName, getDomain, getDomainPrice, getResolverContract, getTreasuryAddress, parseDomainName, validateDomainName, } from '../lib/resolver.js';
7
8
  import { DEFAULT_DOMAIN_PRICE_SATS, PREMIUM_TIER_0_PRICE_SATS, PREMIUM_TIER_1_PRICE_SATS, PREMIUM_TIER_2_PRICE_SATS, PREMIUM_TIER_3_PRICE_SATS, PREMIUM_TIER_4_PRICE_SATS, PREMIUM_TIER_5_PRICE_SATS, PREMIUM_TIER_6_PRICE_SATS, } from '../types/BtcResolver.js';
@@ -126,7 +127,7 @@ async function registerDomain(domain, options) {
126
127
  const contract = getResolverContract(network, sender);
127
128
  const extraUtxo = {
128
129
  address: treasuryAddr,
129
- value: Number(price),
130
+ value: price,
130
131
  };
131
132
  const outSimulation = [
132
133
  {
@@ -237,7 +238,7 @@ async function domainInfo(domain, options) {
237
238
  }
238
239
  }
239
240
  else {
240
- const hashHex = Buffer.from(contenthash.hashData).toString('hex');
241
+ const hashHex = toHex(new Uint8Array(contenthash.hashData));
241
242
  logger.log(`Value: ${hashHex}`);
242
243
  }
243
244
  }
@@ -2,6 +2,7 @@ import { Command } from 'commander';
2
2
  import * as fs from 'fs';
3
3
  import { BaseCommand } from './BaseCommand.js';
4
4
  import { computePublicKeyHash, generateMLDSAKeypair, generateMnemonic } from '../lib/wallet.js';
5
+ import { toHex } from '../lib/binary.js';
5
6
  import { isValidMldsaLevel } from '../lib/credentials.js';
6
7
  export class KeygenCommand extends BaseCommand {
7
8
  constructor() {
@@ -68,10 +69,10 @@ export class KeygenCommand extends BaseCommand {
68
69
  if (options.output) {
69
70
  const privateKeyPath = `${options.output}.private.key`;
70
71
  const publicKeyPath = `${options.output}.public.key`;
71
- fs.writeFileSync(privateKeyPath, keypair.privateKey.toString('hex') + '\n', {
72
+ fs.writeFileSync(privateKeyPath, toHex(keypair.privateKey) + '\n', {
72
73
  mode: 0o600,
73
74
  });
74
- fs.writeFileSync(publicKeyPath, keypair.publicKey.toString('hex') + '\n', {
75
+ fs.writeFileSync(publicKeyPath, toHex(keypair.publicKey) + '\n', {
75
76
  mode: 0o644,
76
77
  });
77
78
  this.logger.success('Keys generated successfully!');
@@ -85,8 +86,8 @@ export class KeygenCommand extends BaseCommand {
85
86
  else if (options.json) {
86
87
  const output = {
87
88
  level: levelNum,
88
- privateKey: keypair.privateKey.toString('hex'),
89
- publicKey: keypair.publicKey.toString('hex'),
89
+ privateKey: toHex(keypair.privateKey),
90
+ publicKey: toHex(keypair.publicKey),
90
91
  publicKeyHash,
91
92
  privateKeySize: keypair.privateKey.length,
92
93
  publicKeySize: keypair.publicKey.length,
@@ -100,10 +101,10 @@ export class KeygenCommand extends BaseCommand {
100
101
  this.logger.log(`Private Key Size: ${keypair.privateKey.length} bytes`);
101
102
  this.logger.log('');
102
103
  this.logger.log('Public Key (hex):');
103
- this.logger.log(keypair.publicKey.toString('hex'));
104
+ this.logger.log(toHex(keypair.publicKey));
104
105
  this.logger.log('');
105
106
  this.logger.log('Private Key (hex):');
106
- this.logger.log(keypair.privateKey.toString('hex'));
107
+ this.logger.log(toHex(keypair.privateKey));
107
108
  this.logger.log('');
108
109
  this.logger.warn('IMPORTANT: Store the private key securely!');
109
110
  this.logger.warn('Use --output <prefix> to save to files.');
@@ -17,6 +17,16 @@ export class LoginCommand extends BaseCommand {
17
17
  }
18
18
  async execute(options) {
19
19
  try {
20
+ if (options.mnemonic) {
21
+ this.logger.warn('WARNING: Mnemonic passed via CLI argument. It may be visible in shell history and process list.');
22
+ this.logger.warn('Consider using interactive mode instead: opnet login');
23
+ this.logger.log('');
24
+ }
25
+ if (options.wif || options.mldsa) {
26
+ this.logger.warn('WARNING: Private key passed via CLI argument. It may be visible in shell history and process list.');
27
+ this.logger.warn('Consider using interactive mode or environment variables instead.');
28
+ this.logger.log('');
29
+ }
20
30
  const credentials = await this.buildCredentials(options);
21
31
  this.logger.info('Deriving wallet...');
22
32
  const wallet = CLIWallet.fromCredentials(credentials);
@@ -135,7 +135,7 @@ export class PublishCommand extends BaseCommand {
135
135
  const treasuryAddress = await contract.getTreasuryAddress();
136
136
  const extraUtxo = {
137
137
  address: treasuryAddress.properties.treasuryAddress,
138
- value: 10_000,
138
+ value: 10000n,
139
139
  };
140
140
  let txParams = buildTransactionParams(wallet, network, DEFAULT_MAX_SAT_TO_SPEND, DEFAULT_FEE_RATE, extraUtxo);
141
141
  if (isNewPackage) {
@@ -184,7 +184,7 @@ export class PublishCommand extends BaseCommand {
184
184
  }
185
185
  txParams = buildTransactionParams(wallet, network, DEFAULT_MAX_SAT_TO_SPEND, DEFAULT_FEE_RATE);
186
186
  this.logger.info('Publishing version...');
187
- const publishResult = await contract.publishVersion(meta.name, meta.version, pinResult.cid, new Uint8Array(parsed.checksum), new Uint8Array(parsed.signature), mldsaLevelToRegistry(mldsaLevel), meta.opnetVersion, pluginTypeToRegistry(meta.pluginType), permissionsHash, dependencies);
187
+ const publishResult = await contract.publishVersion(meta.name, meta.version, pinResult.cid, parsed.checksum, parsed.signature, mldsaLevelToRegistry(mldsaLevel), meta.opnetVersion, pluginTypeToRegistry(meta.pluginType), permissionsHash, dependencies);
188
188
  if (publishResult.revert) {
189
189
  this.logger.fail('Version publishing would fail');
190
190
  this.logger.error(`Reason: ${publishResult.revert}`);
@@ -1,7 +1,7 @@
1
1
  import * as fs from 'fs';
2
2
  import * as crypto from 'crypto';
3
3
  import { BaseCommand } from './BaseCommand.js';
4
- import { buildOpnetBinary, formatFileSize, parseOpnetBinary } from '../lib/binary.js';
4
+ import { buildOpnetBinary, formatFileSize, parseOpnetBinary, toHex } from '../lib/binary.js';
5
5
  import { CLIWallet } from '../lib/wallet.js';
6
6
  import { canSign, loadCredentials } from '../lib/credentials.js';
7
7
  export class SignCommand extends BaseCommand {
@@ -55,10 +55,10 @@ export class SignCommand extends BaseCommand {
55
55
  publicKey: wallet.mldsaPublicKey,
56
56
  metadata: parsed.metadata,
57
57
  bytecode: parsed.bytecode,
58
- proto: parsed.proto ?? Buffer.alloc(0),
58
+ proto: parsed.proto,
59
59
  signFn,
60
60
  });
61
- this.logger.success(`Signed (checksum: sha256:${checksum.toString('hex').substring(0, 16)}...)`);
61
+ this.logger.success(`Signed (checksum: sha256:${toHex(checksum).substring(0, 16)}...)`);
62
62
  this.logger.success(`Binary rebuilt (${formatFileSize(newBinary.length)})`);
63
63
  const outputPath = options.output || file;
64
64
  fs.writeFileSync(outputPath, newBinary);
@@ -1,7 +1,7 @@
1
1
  import * as fs from 'fs';
2
2
  import * as crypto from 'crypto';
3
3
  import { BaseCommand } from './BaseCommand.js';
4
- import { formatFileSize, parseOpnetBinary, verifyChecksum } from '../lib/binary.js';
4
+ import { formatFileSize, parseOpnetBinary, toHex, verifyChecksum } from '../lib/binary.js';
5
5
  import { CLIWallet } from '../lib/wallet.js';
6
6
  export class VerifyCommand extends BaseCommand {
7
7
  constructor() {
@@ -136,7 +136,7 @@ export class VerifyCommand extends BaseCommand {
136
136
  this.logger.log(` Proto: ${formatFileSize(parsed.proto?.length ?? 0)}`);
137
137
  this.logger.log('');
138
138
  this.logger.log('Checksums:');
139
- this.logger.log(` Stored: ${parsed.checksum.toString('hex')}`);
139
+ this.logger.log(` Stored: ${toHex(parsed.checksum)}`);
140
140
  this.logger.log('');
141
141
  this.logger.log('Author:');
142
142
  this.logger.log(` Name: ${parsed.metadata.author.name}`);
@@ -1,6 +1,7 @@
1
1
  import { BaseCommand } from './BaseCommand.js';
2
2
  import { getCredentialSource, hasCredentials, loadCredentials, maskSensitive, } from '../lib/credentials.js';
3
3
  import { CLIWallet } from '../lib/wallet.js';
4
+ import { toHex } from '../lib/binary.js';
4
5
  export class WhoamiCommand extends BaseCommand {
5
6
  constructor() {
6
7
  super('whoami', 'Display current wallet identity and configuration');
@@ -37,7 +38,7 @@ export class WhoamiCommand extends BaseCommand {
37
38
  if (options.publicKey) {
38
39
  this.logger.log('');
39
40
  this.logger.log('MLDSA Public Key:');
40
- this.logger.log(wallet.mldsaPublicKey.toString('hex'));
41
+ this.logger.log(toHex(wallet.mldsaPublicKey));
41
42
  }
42
43
  if (options.verbose) {
43
44
  this.logger.log('');
@@ -1,19 +1,20 @@
1
1
  import { IParsedPluginFile, IPluginMetadata } from '@btc-vision/plugin-sdk';
2
2
  import { CLIMldsaLevel } from '../types/index.js';
3
- export declare function parseOpnetBinary(data: Buffer): IParsedPluginFile;
4
- export declare function computeChecksum(metadata: Buffer, bytecode: Buffer, proto: Buffer): Buffer;
3
+ export declare function toHex(data: Uint8Array): string;
4
+ export declare function parseOpnetBinary(data: Uint8Array): IParsedPluginFile;
5
+ export declare function computeChecksum(metadata: Uint8Array, bytecode: Uint8Array, proto: Uint8Array): Uint8Array;
5
6
  export declare function verifyChecksum(parsed: IParsedPluginFile): boolean;
6
7
  export declare function buildOpnetBinary(options: {
7
8
  mldsaLevel: CLIMldsaLevel;
8
- publicKey: Buffer;
9
+ publicKey: Uint8Array;
9
10
  metadata: IPluginMetadata;
10
- bytecode: Buffer;
11
- proto?: Buffer;
12
- signFn?: (checksum: Buffer) => Buffer;
11
+ bytecode: Uint8Array;
12
+ proto?: Uint8Array;
13
+ signFn?: (checksum: Uint8Array) => Uint8Array;
13
14
  }): {
14
- binary: Buffer;
15
- checksum: Buffer;
15
+ binary: Uint8Array;
16
+ checksum: Uint8Array;
16
17
  };
17
- export declare function extractMetadata(data: Buffer): IPluginMetadata | null;
18
+ export declare function extractMetadata(data: Uint8Array): IPluginMetadata | null;
18
19
  export declare function getParsedMldsaLevel(parsed: IParsedPluginFile): CLIMldsaLevel;
19
20
  export declare function formatFileSize(bytes: number): string;
@@ -1,22 +1,31 @@
1
1
  import * as crypto from 'crypto';
2
2
  import { MLDSA_PUBLIC_KEY_SIZES, MLDSA_SIGNATURE_SIZES, PLUGIN_FORMAT_VERSION, PLUGIN_MAGIC_BYTES, } from '@btc-vision/plugin-sdk';
3
3
  import { cliLevelToMLDSALevel, mldsaLevelToCLI } from '../types/index.js';
4
+ const HEX_CHARS = '0123456789abcdef';
5
+ export function toHex(data) {
6
+ let hex = '';
7
+ for (let i = 0; i < data.length; i++) {
8
+ hex += HEX_CHARS[data[i] >> 4] + HEX_CHARS[data[i] & 0xf];
9
+ }
10
+ return hex;
11
+ }
4
12
  export function parseOpnetBinary(data) {
13
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
5
14
  let offset = 0;
6
15
  if (data.length < 8 + 4 + 1) {
7
16
  throw new Error('Binary too small: missing header');
8
17
  }
9
18
  const magic = data.subarray(offset, offset + 8);
10
19
  offset += 8;
11
- if (!magic.equals(PLUGIN_MAGIC_BYTES)) {
12
- throw new Error(`Invalid magic bytes: expected ${PLUGIN_MAGIC_BYTES.toString('hex')}, got ${magic.toString('hex')}`);
20
+ if (!PLUGIN_MAGIC_BYTES.every((b, i) => magic[i] === b)) {
21
+ throw new Error(`Invalid magic bytes: expected ${toHex(PLUGIN_MAGIC_BYTES)}, got ${toHex(magic)}`);
13
22
  }
14
- const formatVersion = data.readUInt32LE(offset);
23
+ const formatVersion = view.getUint32(offset, true);
15
24
  offset += 4;
16
25
  if (formatVersion !== PLUGIN_FORMAT_VERSION) {
17
26
  throw new Error(`Unsupported format version: ${formatVersion} (expected ${PLUGIN_FORMAT_VERSION})`);
18
27
  }
19
- const mldsaLevelValue = data.readUInt8(offset);
28
+ const mldsaLevelValue = view.getUint8(offset);
20
29
  offset += 1;
21
30
  if (mldsaLevelValue > 2) {
22
31
  throw new Error(`Invalid MLDSA level: ${mldsaLevelValue} (must be 0, 1, or 2)`);
@@ -28,44 +37,45 @@ export function parseOpnetBinary(data) {
28
37
  if (data.length < minSize) {
29
38
  throw new Error(`Binary truncated: expected at least ${minSize} bytes, got ${data.length}`);
30
39
  }
31
- const publicKey = Buffer.from(data.subarray(offset, offset + publicKeySize));
40
+ const publicKey = data.slice(offset, offset + publicKeySize);
32
41
  offset += publicKeySize;
33
- const signature = Buffer.from(data.subarray(offset, offset + signatureSize));
42
+ const signature = data.slice(offset, offset + signatureSize);
34
43
  offset += signatureSize;
35
- const metadataLength = data.readUInt32LE(offset);
44
+ const metadataLength = view.getUint32(offset, true);
36
45
  offset += 4;
37
46
  if (offset + metadataLength > data.length) {
38
47
  throw new Error(`Metadata section truncated at offset ${offset}`);
39
48
  }
40
49
  const metadataBytes = data.subarray(offset, offset + metadataLength);
41
50
  offset += metadataLength;
51
+ const decoder = new TextDecoder();
42
52
  let rawMetadata;
43
53
  let metadata;
44
54
  try {
45
- rawMetadata = metadataBytes.toString('utf-8');
55
+ rawMetadata = decoder.decode(metadataBytes);
46
56
  metadata = JSON.parse(rawMetadata);
47
57
  }
48
58
  catch {
49
59
  throw new Error('Malformed JSON metadata');
50
60
  }
51
- const bytecodeLength = data.readUInt32LE(offset);
61
+ const bytecodeLength = view.getUint32(offset, true);
52
62
  offset += 4;
53
63
  if (offset + bytecodeLength > data.length) {
54
64
  throw new Error(`Bytecode section truncated at offset ${offset}`);
55
65
  }
56
- const bytecode = Buffer.from(data.subarray(offset, offset + bytecodeLength));
66
+ const bytecode = data.slice(offset, offset + bytecodeLength);
57
67
  offset += bytecodeLength;
58
- const protoLength = data.readUInt32LE(offset);
68
+ const protoLength = view.getUint32(offset, true);
59
69
  offset += 4;
60
70
  if (offset + protoLength > data.length) {
61
71
  throw new Error(`Proto section truncated at offset ${offset}`);
62
72
  }
63
- const proto = protoLength > 0 ? Buffer.from(data.subarray(offset, offset + protoLength)) : undefined;
73
+ const proto = protoLength > 0 ? data.slice(offset, offset + protoLength) : undefined;
64
74
  offset += protoLength;
65
75
  if (offset + 32 > data.length) {
66
76
  throw new Error('Checksum truncated');
67
77
  }
68
- const checksum = Buffer.from(data.subarray(offset, offset + 32));
78
+ const checksum = data.slice(offset, offset + 32);
69
79
  return {
70
80
  formatVersion,
71
81
  mldsaLevel,
@@ -86,26 +96,31 @@ export function computeChecksum(metadata, bytecode, proto) {
86
96
  return hash.digest();
87
97
  }
88
98
  export function verifyChecksum(parsed) {
89
- const metadataBytes = Buffer.from(parsed.rawMetadata, 'utf-8');
90
- const computed = computeChecksum(metadataBytes, parsed.bytecode, parsed.proto ?? Buffer.alloc(0));
91
- return computed.equals(parsed.checksum);
99
+ const encoder = new TextEncoder();
100
+ const metadataBytes = encoder.encode(parsed.rawMetadata);
101
+ const computed = computeChecksum(metadataBytes, parsed.bytecode, parsed.proto ?? new Uint8Array(0));
102
+ if (computed.length !== parsed.checksum.length) {
103
+ return false;
104
+ }
105
+ return crypto.timingSafeEqual(computed, parsed.checksum);
92
106
  }
93
107
  export function buildOpnetBinary(options) {
94
- const { mldsaLevel, publicKey, metadata, bytecode, proto = Buffer.alloc(0), signFn } = options;
108
+ const { mldsaLevel, publicKey, metadata, bytecode, proto = new Uint8Array(0), signFn, } = options;
95
109
  const sdkLevel = cliLevelToMLDSALevel(mldsaLevel);
96
110
  const expectedPkSize = MLDSA_PUBLIC_KEY_SIZES[sdkLevel];
97
111
  const expectedSigSize = MLDSA_SIGNATURE_SIZES[sdkLevel];
98
112
  if (publicKey.length !== expectedPkSize) {
99
113
  throw new Error(`Public key size mismatch: expected ${expectedPkSize}, got ${publicKey.length}`);
100
114
  }
115
+ const encoder = new TextEncoder();
101
116
  const tempMetadata = { ...metadata, checksum: '' };
102
- const tempMetadataBytes = Buffer.from(JSON.stringify(tempMetadata), 'utf-8');
117
+ const tempMetadataBytes = encoder.encode(JSON.stringify(tempMetadata));
103
118
  const checksum = computeChecksum(tempMetadataBytes, bytecode, proto);
104
- const checksumHex = `sha256:${checksum.toString('hex')}`;
119
+ const checksumHex = `sha256:${toHex(checksum)}`;
105
120
  const finalMetadata = { ...metadata, checksum: checksumHex };
106
- const metadataBytes = Buffer.from(JSON.stringify(finalMetadata), 'utf-8');
121
+ const metadataBytes = encoder.encode(JSON.stringify(finalMetadata));
107
122
  const finalChecksum = computeChecksum(metadataBytes, bytecode, proto);
108
- const signature = signFn ? signFn(finalChecksum) : Buffer.alloc(expectedSigSize);
123
+ const signature = signFn ? signFn(finalChecksum) : new Uint8Array(expectedSigSize);
109
124
  if (signature.length !== expectedSigSize) {
110
125
  throw new Error(`Signature size mismatch: expected ${expectedSigSize}, got ${signature.length}`);
111
126
  }
@@ -121,31 +136,32 @@ export function buildOpnetBinary(options) {
121
136
  4 +
122
137
  proto.length +
123
138
  32;
124
- const buffer = Buffer.alloc(totalSize);
139
+ const buffer = new Uint8Array(totalSize);
140
+ const view = new DataView(buffer.buffer);
125
141
  let offset = 0;
126
- PLUGIN_MAGIC_BYTES.copy(buffer, offset);
142
+ buffer.set(PLUGIN_MAGIC_BYTES, offset);
127
143
  offset += 8;
128
- buffer.writeUInt32LE(PLUGIN_FORMAT_VERSION, offset);
144
+ view.setUint32(offset, PLUGIN_FORMAT_VERSION, true);
129
145
  offset += 4;
130
- buffer.writeUInt8(sdkLevel, offset);
146
+ view.setUint8(offset, sdkLevel);
131
147
  offset += 1;
132
- publicKey.copy(buffer, offset);
148
+ buffer.set(publicKey, offset);
133
149
  offset += publicKey.length;
134
- signature.copy(buffer, offset);
150
+ buffer.set(signature, offset);
135
151
  offset += signature.length;
136
- buffer.writeUInt32LE(metadataBytes.length, offset);
152
+ view.setUint32(offset, metadataBytes.length, true);
137
153
  offset += 4;
138
- metadataBytes.copy(buffer, offset);
154
+ buffer.set(metadataBytes, offset);
139
155
  offset += metadataBytes.length;
140
- buffer.writeUInt32LE(bytecode.length, offset);
156
+ view.setUint32(offset, bytecode.length, true);
141
157
  offset += 4;
142
- bytecode.copy(buffer, offset);
158
+ buffer.set(bytecode, offset);
143
159
  offset += bytecode.length;
144
- buffer.writeUInt32LE(proto.length, offset);
160
+ view.setUint32(offset, proto.length, true);
145
161
  offset += 4;
146
- proto.copy(buffer, offset);
162
+ buffer.set(proto, offset);
147
163
  offset += proto.length;
148
- finalChecksum.copy(buffer, offset);
164
+ buffer.set(finalChecksum, offset);
149
165
  return { binary: buffer, checksum: finalChecksum };
150
166
  }
151
167
  export function extractMetadata(data) {
@@ -24,7 +24,7 @@ export const DEFAULT_CONFIG = {
24
24
  resolverAddresses: {
25
25
  mainnet: '',
26
26
  testnet: '',
27
- regtest: '0x69e1d910686c7e3d5d44b29f6d5aa4afc4bcbd65a5d8e8a6bf601b209f0c4781',
27
+ regtest: '0x271ea47b91797e5900a3c9bdd39b87a79919eac7c9ec2c860f494704fb0dcaea',
28
28
  },
29
29
  defaultMldsaLevel: 44,
30
30
  indexerUrl: 'https://indexer.opnet.org',
@@ -3,11 +3,22 @@ import * as path from 'path';
3
3
  import * as os from 'os';
4
4
  import { ensureConfigDir } from './config.js';
5
5
  const CREDENTIALS_FILE = path.join(os.homedir(), '.opnet', 'credentials.json');
6
+ const VALID_MLDSA_LEVELS = [44, 65, 87];
7
+ function parseEnvMldsaLevel() {
8
+ const raw = process.env.OPNET_MLDSA_LEVEL;
9
+ if (!raw)
10
+ return 44;
11
+ const parsed = parseInt(raw, 10);
12
+ if (!VALID_MLDSA_LEVELS.includes(parsed)) {
13
+ throw new Error(`Invalid OPNET_MLDSA_LEVEL="${raw}". Must be one of: ${VALID_MLDSA_LEVELS.join(', ')}`);
14
+ }
15
+ return parsed;
16
+ }
6
17
  export function loadCredentials() {
7
18
  if (process.env.OPNET_MNEMONIC) {
8
19
  return {
9
20
  mnemonic: process.env.OPNET_MNEMONIC,
10
- mldsaLevel: parseInt(process.env.OPNET_MLDSA_LEVEL || '44', 10) || 44,
21
+ mldsaLevel: parseEnvMldsaLevel(),
11
22
  network: process.env.OPNET_NETWORK || 'mainnet',
12
23
  };
13
24
  }
@@ -15,18 +26,29 @@ export function loadCredentials() {
15
26
  return {
16
27
  wif: process.env.OPNET_PRIVATE_KEY,
17
28
  mldsaPrivateKey: process.env.OPNET_MLDSA_KEY,
18
- mldsaLevel: parseInt(process.env.OPNET_MLDSA_LEVEL || '44', 10) || 44,
29
+ mldsaLevel: parseEnvMldsaLevel(),
19
30
  network: process.env.OPNET_NETWORK || 'mainnet',
20
31
  };
21
32
  }
22
33
  if (!fs.existsSync(CREDENTIALS_FILE)) {
23
34
  return null;
24
35
  }
36
+ try {
37
+ const stat = fs.statSync(CREDENTIALS_FILE);
38
+ const mode = stat.mode & 0o777;
39
+ if (mode !== 0o600 && mode !== 0o400) {
40
+ process.stderr.write(`WARNING: Credentials file ${CREDENTIALS_FILE} has permissions ${mode.toString(8)}. Expected 600 or 400.\n` +
41
+ `Run: chmod 600 ${CREDENTIALS_FILE}\n`);
42
+ }
43
+ }
44
+ catch {
45
+ }
25
46
  try {
26
47
  const content = fs.readFileSync(CREDENTIALS_FILE, 'utf-8');
27
48
  return JSON.parse(content);
28
49
  }
29
- catch {
50
+ catch (error) {
51
+ process.stderr.write(`WARNING: Failed to parse credentials file: ${error instanceof Error ? error.message : String(error)}\n`);
30
52
  return null;
31
53
  }
32
54
  }