@btc-vision/cli 1.0.0 → 1.0.2
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.
- package/build/commands/AcceptCommand.js +2 -2
- package/build/commands/CompileCommand.js +11 -12
- package/build/commands/ConfigCommand.js +3 -7
- package/build/commands/DeprecateCommand.js +2 -2
- package/build/commands/InfoCommand.js +2 -2
- package/build/commands/InitCommand.d.ts +2 -0
- package/build/commands/InitCommand.js +114 -20
- package/build/commands/InstallCommand.js +1 -1
- package/build/commands/KeygenCommand.js +1 -1
- package/build/commands/ListCommand.js +6 -2
- package/build/commands/LoginCommand.js +22 -10
- package/build/commands/LogoutCommand.js +1 -1
- package/build/commands/PublishCommand.js +3 -3
- package/build/commands/SearchCommand.js +1 -1
- package/build/commands/SignCommand.js +11 -11
- package/build/commands/TransferCommand.js +3 -3
- package/build/commands/UndeprecateCommand.js +1 -1
- package/build/commands/VerifyCommand.js +5 -2
- package/build/commands/WhoamiCommand.js +1 -1
- package/build/lib/PackageRegistry.abi.js +1 -1
- package/build/lib/binary.d.ts +5 -2
- package/build/lib/binary.js +18 -10
- package/build/lib/config.d.ts +1 -1
- package/build/lib/credentials.d.ts +1 -1
- package/build/lib/ipfs.js +3 -2
- package/build/lib/manifest.d.ts +1 -1
- package/build/lib/manifest.js +23 -12
- package/build/lib/provider.js +1 -1
- package/build/lib/registry.d.ts +1 -1
- package/build/lib/wallet.d.ts +5 -5
- package/build/lib/wallet.js +31 -31
- package/build/types/PackageRegistry.d.ts +1 -1
- package/build/types/index.js +1 -1
- package/package.json +3 -3
- package/src/commands/CompileCommand.ts +13 -14
- package/src/commands/InitCommand.ts +87 -5
- package/src/commands/SignCommand.ts +9 -21
- package/src/lib/binary.ts +24 -22
- package/src/lib/config.ts +3 -4
- package/src/lib/ipfs.ts +0 -1
- package/src/lib/manifest.ts +31 -8
package/build/lib/binary.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as crypto from 'crypto';
|
|
2
|
-
import {
|
|
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
4
|
export function parseOpnetBinary(data) {
|
|
5
5
|
let offset = 0;
|
|
@@ -91,27 +91,35 @@ export function verifyChecksum(parsed) {
|
|
|
91
91
|
return computed.equals(parsed.checksum);
|
|
92
92
|
}
|
|
93
93
|
export function buildOpnetBinary(options) {
|
|
94
|
-
const { mldsaLevel, publicKey,
|
|
94
|
+
const { mldsaLevel, publicKey, metadata, bytecode, proto = Buffer.alloc(0), signFn } = options;
|
|
95
95
|
const sdkLevel = cliLevelToMLDSALevel(mldsaLevel);
|
|
96
96
|
const expectedPkSize = MLDSA_PUBLIC_KEY_SIZES[sdkLevel];
|
|
97
97
|
const expectedSigSize = MLDSA_SIGNATURE_SIZES[sdkLevel];
|
|
98
98
|
if (publicKey.length !== expectedPkSize) {
|
|
99
99
|
throw new Error(`Public key size mismatch: expected ${expectedPkSize}, got ${publicKey.length}`);
|
|
100
100
|
}
|
|
101
|
+
const tempMetadata = { ...metadata, checksum: '' };
|
|
102
|
+
const tempMetadataBytes = Buffer.from(JSON.stringify(tempMetadata), 'utf-8');
|
|
103
|
+
const checksum = computeChecksum(tempMetadataBytes, bytecode, proto);
|
|
104
|
+
const checksumHex = `sha256:${checksum.toString('hex')}`;
|
|
105
|
+
const finalMetadata = { ...metadata, checksum: checksumHex };
|
|
106
|
+
const metadataBytes = Buffer.from(JSON.stringify(finalMetadata), 'utf-8');
|
|
107
|
+
const finalChecksum = computeChecksum(metadataBytes, bytecode, proto);
|
|
108
|
+
const signature = signFn ? signFn(finalChecksum) : Buffer.alloc(expectedSigSize);
|
|
101
109
|
if (signature.length !== expectedSigSize) {
|
|
102
110
|
throw new Error(`Signature size mismatch: expected ${expectedSigSize}, got ${signature.length}`);
|
|
103
111
|
}
|
|
104
|
-
const metadataStr = JSON.stringify(metadata);
|
|
105
|
-
const metadataBytes = Buffer.from(metadataStr, 'utf-8');
|
|
106
|
-
const checksum = computeChecksum(metadataBytes, bytecode, proto);
|
|
107
112
|
const totalSize = 8 +
|
|
108
113
|
4 +
|
|
109
114
|
1 +
|
|
110
115
|
publicKey.length +
|
|
111
116
|
signature.length +
|
|
112
|
-
4 +
|
|
113
|
-
|
|
114
|
-
4 +
|
|
117
|
+
4 +
|
|
118
|
+
metadataBytes.length +
|
|
119
|
+
4 +
|
|
120
|
+
bytecode.length +
|
|
121
|
+
4 +
|
|
122
|
+
proto.length +
|
|
115
123
|
32;
|
|
116
124
|
const buffer = Buffer.alloc(totalSize);
|
|
117
125
|
let offset = 0;
|
|
@@ -137,8 +145,8 @@ export function buildOpnetBinary(options) {
|
|
|
137
145
|
offset += 4;
|
|
138
146
|
proto.copy(buffer, offset);
|
|
139
147
|
offset += proto.length;
|
|
140
|
-
|
|
141
|
-
return buffer;
|
|
148
|
+
finalChecksum.copy(buffer, offset);
|
|
149
|
+
return { binary: buffer, checksum: finalChecksum };
|
|
142
150
|
}
|
|
143
151
|
export function extractMetadata(data) {
|
|
144
152
|
try {
|
package/build/lib/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CLIConfig,
|
|
1
|
+
import { CLIConfig, CLIMldsaLevel, NetworkName } from '../types/index.js';
|
|
2
2
|
export declare function ensureConfigDir(): void;
|
|
3
3
|
export declare function loadConfig(): CLIConfig;
|
|
4
4
|
export declare function saveConfig(config: CLIConfig): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CLICredentials,
|
|
1
|
+
import { CLICredentials, CLIMldsaLevel, NetworkName } from '../types/index.js';
|
|
2
2
|
export declare function loadCredentials(): CLICredentials | null;
|
|
3
3
|
export declare function saveCredentials(credentials: CLICredentials): void;
|
|
4
4
|
export declare function deleteCredentials(): boolean;
|
package/build/lib/ipfs.js
CHANGED
|
@@ -62,7 +62,9 @@ export async function pinToIPFS(data, name) {
|
|
|
62
62
|
'Content-Length': body.length.toString(),
|
|
63
63
|
};
|
|
64
64
|
if (config.ipfsPinningAuthHeader) {
|
|
65
|
-
const [headerName, headerValue] = config.ipfsPinningAuthHeader
|
|
65
|
+
const [headerName, headerValue] = config.ipfsPinningAuthHeader
|
|
66
|
+
.split(':')
|
|
67
|
+
.map((s) => s.trim());
|
|
66
68
|
if (headerName && headerValue) {
|
|
67
69
|
headers[headerName] = headerValue;
|
|
68
70
|
}
|
|
@@ -139,7 +141,6 @@ export async function fetchFromIPFS(cid) {
|
|
|
139
141
|
}
|
|
140
142
|
catch (error) {
|
|
141
143
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
142
|
-
continue;
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
146
|
throw new Error(`Failed to fetch from all gateways: ${lastError?.message}`);
|
package/build/lib/manifest.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ export declare function createManifest(options: {
|
|
|
10
10
|
email?: string;
|
|
11
11
|
description?: string;
|
|
12
12
|
pluginType: 'standalone' | 'library';
|
|
13
|
-
}): IPluginMetadata
|
|
13
|
+
}): Omit<IPluginMetadata, 'checksum'>;
|
|
14
14
|
export declare function getManifestPath(dir?: string): string;
|
package/build/lib/manifest.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import { DEFAULT_LIFECYCLE, DEFAULT_PERMISSIONS, DEFAULT_RESOURCES, PLUGIN_MANIFEST_FILENAME, PLUGIN_NAME_REGEX, validateManifest as sdkValidateManifest, } from '@btc-vision/plugin-sdk';
|
|
4
4
|
const SCOPED_NAME_PATTERN = /^@[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/;
|
|
5
5
|
export function validatePluginName(name) {
|
|
6
6
|
const errors = [];
|
|
@@ -29,8 +29,7 @@ export function validateManifest(manifest) {
|
|
|
29
29
|
export function validatePermissions(permissions) {
|
|
30
30
|
const errors = [];
|
|
31
31
|
if (permissions.database?.enabled) {
|
|
32
|
-
if (!permissions.database.collections ||
|
|
33
|
-
!Array.isArray(permissions.database.collections)) {
|
|
32
|
+
if (!permissions.database.collections || !Array.isArray(permissions.database.collections)) {
|
|
34
33
|
errors.push('database.collections must be an array when database is enabled');
|
|
35
34
|
}
|
|
36
35
|
}
|
|
@@ -49,14 +48,27 @@ export function loadManifest(manifestPath) {
|
|
|
49
48
|
catch (e) {
|
|
50
49
|
throw new Error(`Failed to parse manifest: ${e instanceof Error ? e.message : String(e)}`);
|
|
51
50
|
}
|
|
52
|
-
const
|
|
53
|
-
if (!
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
const errors = [];
|
|
52
|
+
if (!manifest.name || typeof manifest.name !== 'string') {
|
|
53
|
+
errors.push('name is required');
|
|
54
|
+
}
|
|
55
|
+
if (!manifest.version || typeof manifest.version !== 'string') {
|
|
56
|
+
errors.push('version is required');
|
|
57
|
+
}
|
|
58
|
+
if (!manifest.author || typeof manifest.author !== 'object') {
|
|
59
|
+
errors.push('author is required');
|
|
60
|
+
}
|
|
61
|
+
if (!manifest.pluginType || !['standalone', 'library'].includes(manifest.pluginType)) {
|
|
62
|
+
errors.push('pluginType must be "standalone" or "library"');
|
|
63
|
+
}
|
|
64
|
+
if (errors.length > 0) {
|
|
65
|
+
throw new Error(`Invalid manifest:\n${errors.map((e) => ` - ${e}`).join('\n')}`);
|
|
66
|
+
}
|
|
67
|
+
const result = manifest;
|
|
68
|
+
if (!result.checksum) {
|
|
69
|
+
result.checksum = '';
|
|
58
70
|
}
|
|
59
|
-
return
|
|
71
|
+
return result;
|
|
60
72
|
}
|
|
61
73
|
export function saveManifest(manifestPath, manifest) {
|
|
62
74
|
const content = JSON.stringify(manifest, null, 4);
|
|
@@ -66,11 +78,10 @@ export function createManifest(options) {
|
|
|
66
78
|
return {
|
|
67
79
|
name: options.name,
|
|
68
80
|
version: '1.0.0',
|
|
69
|
-
opnetVersion: '
|
|
81
|
+
opnetVersion: '>=0.0.1',
|
|
70
82
|
main: 'dist/index.jsc',
|
|
71
83
|
target: 'bytenode',
|
|
72
84
|
type: 'plugin',
|
|
73
|
-
checksum: '',
|
|
74
85
|
author: {
|
|
75
86
|
name: options.author,
|
|
76
87
|
email: options.email,
|
package/build/lib/provider.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JSONRpcProvider } from 'opnet';
|
|
2
|
-
import {
|
|
2
|
+
import { getRegistryAddress, getRpcUrl, loadConfig } from './config.js';
|
|
3
3
|
import { getNetwork } from './wallet.js';
|
|
4
4
|
const DEFAULT_TIMEOUT = 30000;
|
|
5
5
|
const providerCache = new Map();
|
package/build/lib/registry.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Address } from '@btc-vision/transaction';
|
|
2
|
-
import {
|
|
2
|
+
import { CLIMldsaLevel, NetworkName, RegistryPluginType } from '../types/index.js';
|
|
3
3
|
import { IPluginPermissions } from '@btc-vision/plugin-sdk';
|
|
4
4
|
import { IPackageRegistry } from '../types/PackageRegistry.js';
|
|
5
5
|
export interface ScopeInfo {
|
package/build/lib/wallet.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Network } from '@btc-vision/bitcoin';
|
|
2
2
|
import { MLDSASecurityLevel } from '@btc-vision/bip32';
|
|
3
|
-
import {
|
|
4
|
-
import { CLICredentials,
|
|
3
|
+
import { EcKeyPair, Wallet } from '@btc-vision/transaction';
|
|
4
|
+
import { CLICredentials, CLIMldsaLevel, NetworkName } from '../types/index.js';
|
|
5
5
|
export declare function getNetwork(networkName: NetworkName): Network;
|
|
6
6
|
export declare function getMLDSASecurityLevel(level: CLIMldsaLevel): MLDSASecurityLevel;
|
|
7
7
|
export declare class CLIWallet {
|
|
@@ -9,8 +9,6 @@ export declare class CLIWallet {
|
|
|
9
9
|
private readonly network;
|
|
10
10
|
private readonly mldsaLevel;
|
|
11
11
|
private constructor();
|
|
12
|
-
static fromCredentials(credentials: CLICredentials): CLIWallet;
|
|
13
|
-
static load(): CLIWallet;
|
|
14
12
|
get p2trAddress(): string;
|
|
15
13
|
get underlyingWallet(): Wallet;
|
|
16
14
|
get keypair(): EcKeyPair;
|
|
@@ -19,9 +17,11 @@ export declare class CLIWallet {
|
|
|
19
17
|
get mldsaPublicKeyHash(): string;
|
|
20
18
|
get securityLevel(): CLIMldsaLevel;
|
|
21
19
|
get walletNetwork(): Network;
|
|
20
|
+
static fromCredentials(credentials: CLICredentials): CLIWallet;
|
|
21
|
+
static load(): CLIWallet;
|
|
22
|
+
static verifyMLDSA(data: Buffer, signature: Buffer, publicKey: Buffer, level: CLIMldsaLevel): boolean;
|
|
22
23
|
signMLDSA(data: Buffer): Buffer;
|
|
23
24
|
verifyMLDSA(data: Buffer, signature: Buffer): boolean;
|
|
24
|
-
static verifyMLDSA(data: Buffer, signature: Buffer, publicKey: Buffer, level: CLIMldsaLevel): boolean;
|
|
25
25
|
}
|
|
26
26
|
export declare function generateMLDSAKeypair(level: CLIMldsaLevel): {
|
|
27
27
|
privateKey: Buffer;
|
package/build/lib/wallet.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { networks } from '@btc-vision/bitcoin';
|
|
2
2
|
import { MLDSASecurityLevel, QuantumBIP32Factory } from '@btc-vision/bip32';
|
|
3
|
-
import {
|
|
3
|
+
import { EcKeyPair, MessageSigner, Mnemonic, Wallet } from '@btc-vision/transaction';
|
|
4
4
|
import * as crypto from 'crypto';
|
|
5
|
-
import {
|
|
5
|
+
import { canSign, loadCredentials } from './credentials.js';
|
|
6
6
|
export function getNetwork(networkName) {
|
|
7
7
|
switch (networkName) {
|
|
8
8
|
case 'mainnet':
|
|
@@ -32,30 +32,6 @@ export class CLIWallet {
|
|
|
32
32
|
this.network = network;
|
|
33
33
|
this.mldsaLevel = mldsaLevel;
|
|
34
34
|
}
|
|
35
|
-
static fromCredentials(credentials) {
|
|
36
|
-
const network = getNetwork(credentials.network);
|
|
37
|
-
const securityLevel = getMLDSASecurityLevel(credentials.mldsaLevel);
|
|
38
|
-
if (credentials.mnemonic) {
|
|
39
|
-
const mnemonic = new Mnemonic(credentials.mnemonic, '', network, securityLevel);
|
|
40
|
-
const wallet = mnemonic.deriveUnisat();
|
|
41
|
-
return new CLIWallet(wallet, network, credentials.mldsaLevel);
|
|
42
|
-
}
|
|
43
|
-
if (credentials.wif && credentials.mldsaPrivateKey) {
|
|
44
|
-
const wallet = Wallet.fromWif(credentials.wif, credentials.mldsaPrivateKey, network, securityLevel);
|
|
45
|
-
return new CLIWallet(wallet, network, credentials.mldsaLevel);
|
|
46
|
-
}
|
|
47
|
-
throw new Error('Invalid credentials: requires either mnemonic or both WIF and MLDSA key');
|
|
48
|
-
}
|
|
49
|
-
static load() {
|
|
50
|
-
const credentials = loadCredentials();
|
|
51
|
-
if (!credentials) {
|
|
52
|
-
throw new Error('No credentials found. Run `opnet login` to configure your wallet.');
|
|
53
|
-
}
|
|
54
|
-
if (!canSign(credentials)) {
|
|
55
|
-
throw new Error('Credentials incomplete for signing. Run `opnet login` to reconfigure.');
|
|
56
|
-
}
|
|
57
|
-
return CLIWallet.fromCredentials(credentials);
|
|
58
|
-
}
|
|
59
35
|
get p2trAddress() {
|
|
60
36
|
return this.wallet.p2tr;
|
|
61
37
|
}
|
|
@@ -81,12 +57,29 @@ export class CLIWallet {
|
|
|
81
57
|
get walletNetwork() {
|
|
82
58
|
return this.network;
|
|
83
59
|
}
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
60
|
+
static fromCredentials(credentials) {
|
|
61
|
+
const network = getNetwork(credentials.network);
|
|
62
|
+
const securityLevel = getMLDSASecurityLevel(credentials.mldsaLevel);
|
|
63
|
+
if (credentials.mnemonic) {
|
|
64
|
+
const mnemonic = new Mnemonic(credentials.mnemonic, '', network, securityLevel);
|
|
65
|
+
const wallet = mnemonic.deriveUnisat();
|
|
66
|
+
return new CLIWallet(wallet, network, credentials.mldsaLevel);
|
|
67
|
+
}
|
|
68
|
+
if (credentials.wif && credentials.mldsaPrivateKey) {
|
|
69
|
+
const wallet = Wallet.fromWif(credentials.wif, credentials.mldsaPrivateKey, network, securityLevel);
|
|
70
|
+
return new CLIWallet(wallet, network, credentials.mldsaLevel);
|
|
71
|
+
}
|
|
72
|
+
throw new Error('Invalid credentials: requires either mnemonic or both WIF and MLDSA key');
|
|
87
73
|
}
|
|
88
|
-
|
|
89
|
-
|
|
74
|
+
static load() {
|
|
75
|
+
const credentials = loadCredentials();
|
|
76
|
+
if (!credentials) {
|
|
77
|
+
throw new Error('No credentials found. Run `opnet login` to configure your wallet.');
|
|
78
|
+
}
|
|
79
|
+
if (!canSign(credentials)) {
|
|
80
|
+
throw new Error('Credentials incomplete for signing. Run `opnet login` to reconfigure.');
|
|
81
|
+
}
|
|
82
|
+
return CLIWallet.fromCredentials(credentials);
|
|
90
83
|
}
|
|
91
84
|
static verifyMLDSA(data, signature, publicKey, level) {
|
|
92
85
|
const securityLevel = getMLDSASecurityLevel(level);
|
|
@@ -94,6 +87,13 @@ export class CLIWallet {
|
|
|
94
87
|
const keypair = QuantumBIP32Factory.fromPublicKey(publicKey, dummyChainCode, networks.bitcoin, securityLevel);
|
|
95
88
|
return keypair.verify(data, signature);
|
|
96
89
|
}
|
|
90
|
+
signMLDSA(data) {
|
|
91
|
+
const result = MessageSigner.signMLDSAMessage(this.wallet.mldsaKeypair, data);
|
|
92
|
+
return Buffer.from(result.signature);
|
|
93
|
+
}
|
|
94
|
+
verifyMLDSA(data, signature) {
|
|
95
|
+
return MessageSigner.verifyMLDSASignature(this.wallet.mldsaKeypair, data, signature);
|
|
96
|
+
}
|
|
97
97
|
}
|
|
98
98
|
export function generateMLDSAKeypair(level) {
|
|
99
99
|
const securityLevel = getMLDSASecurityLevel(level);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Address } from '@btc-vision/transaction';
|
|
2
|
-
import { CallResult,
|
|
2
|
+
import { CallResult, IOP_NETContract, OPNetEvent } from 'opnet';
|
|
3
3
|
export type TreasuryAddressChangedEvent = {
|
|
4
4
|
readonly previousAddressHash: bigint;
|
|
5
5
|
readonly newAddressHash: bigint;
|
package/build/types/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MLDSA_PUBLIC_KEY_SIZES, MLDSA_SIGNATURE_SIZES, MLDSALevel } from '@btc-vision/plugin-sdk';
|
|
2
2
|
export function cliLevelToMLDSALevel(level) {
|
|
3
3
|
switch (level) {
|
|
4
4
|
case 44:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for the OPNet plugin ecosystem - scaffolding, compilation, signing, and registry interaction",
|
|
6
6
|
"author": "OP_NET",
|
|
@@ -53,12 +53,12 @@
|
|
|
53
53
|
"bytenode": "^1.5.7",
|
|
54
54
|
"commander": "^14.0.0",
|
|
55
55
|
"esbuild": "^0.25.5",
|
|
56
|
-
"opnet": "^1.7.
|
|
56
|
+
"opnet": "^1.7.18",
|
|
57
57
|
"ora": "^8.2.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@eslint/js": "^9.39.1",
|
|
61
|
-
"@types/node": "^
|
|
61
|
+
"@types/node": "^25.0.2",
|
|
62
62
|
"eslint": "^9.39.1",
|
|
63
63
|
"gulp": "^5.0.1",
|
|
64
64
|
"gulp-cached": "^1.1.1",
|
|
@@ -10,7 +10,7 @@ import * as esbuild from 'esbuild';
|
|
|
10
10
|
import bytenode from 'bytenode';
|
|
11
11
|
import { BaseCommand } from './BaseCommand.js';
|
|
12
12
|
import { getManifestPath, loadManifest } from '../lib/manifest.js';
|
|
13
|
-
import { buildOpnetBinary,
|
|
13
|
+
import { buildOpnetBinary, formatFileSize } from '../lib/binary.js';
|
|
14
14
|
import { CLIWallet } from '../lib/wallet.js';
|
|
15
15
|
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
16
16
|
import { CLIMldsaLevel } from '../types/index.js';
|
|
@@ -105,8 +105,8 @@ export class CompileCommand extends BaseCommand {
|
|
|
105
105
|
|
|
106
106
|
// Prepare signing
|
|
107
107
|
let publicKey: Buffer;
|
|
108
|
-
let signature: Buffer;
|
|
109
108
|
let mldsaLevel: CLIMldsaLevel;
|
|
109
|
+
let signFn: ((checksum: Buffer) => Buffer) | undefined;
|
|
110
110
|
|
|
111
111
|
if (options.sign) {
|
|
112
112
|
this.logger.info('Loading wallet for signing...');
|
|
@@ -125,33 +125,31 @@ export class CompileCommand extends BaseCommand {
|
|
|
125
125
|
|
|
126
126
|
this.logger.success(`Wallet loaded (MLDSA-${mldsaLevel})`);
|
|
127
127
|
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
const metadataBytes = Buffer.from(JSON.stringify(manifest), 'utf-8');
|
|
131
|
-
const checksum = computeChecksum(metadataBytes, bytecode, proto);
|
|
132
|
-
|
|
133
|
-
signature = wallet.signMLDSA(checksum);
|
|
134
|
-
this.logger.success(
|
|
135
|
-
`Plugin signed (${formatFileSize(signature.length)} signature)`,
|
|
136
|
-
);
|
|
128
|
+
// Create signing function that will be called with the final checksum
|
|
129
|
+
signFn = (checksum: Buffer) => wallet.signMLDSA(checksum);
|
|
137
130
|
} else {
|
|
138
131
|
this.logger.warn('Skipping signing (--no-sign)');
|
|
139
132
|
// Use dummy values for unsigned binary
|
|
140
133
|
mldsaLevel = 44;
|
|
141
134
|
publicKey = Buffer.alloc(1312); // MLDSA-44 public key size
|
|
142
|
-
signature = Buffer.alloc(2420); // MLDSA-44 signature size
|
|
143
135
|
}
|
|
144
136
|
|
|
145
137
|
// Build .opnet binary
|
|
146
138
|
this.logger.info('Assembling .opnet binary...');
|
|
147
|
-
const binary = buildOpnetBinary({
|
|
139
|
+
const { binary, checksum } = buildOpnetBinary({
|
|
148
140
|
mldsaLevel,
|
|
149
141
|
publicKey,
|
|
150
|
-
signature,
|
|
151
142
|
metadata: manifest,
|
|
152
143
|
bytecode,
|
|
153
144
|
proto,
|
|
145
|
+
signFn,
|
|
154
146
|
});
|
|
147
|
+
|
|
148
|
+
if (options.sign) {
|
|
149
|
+
this.logger.success(
|
|
150
|
+
`Plugin signed (checksum: sha256:${checksum.toString('hex').substring(0, 16)}...)`,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
155
153
|
this.logger.success(`Binary assembled (${formatFileSize(binary.length)})`);
|
|
156
154
|
|
|
157
155
|
// Write output
|
|
@@ -178,6 +176,7 @@ export class CompileCommand extends BaseCommand {
|
|
|
178
176
|
this.logger.log(`Plugin: ${manifest.name}@${manifest.version}`);
|
|
179
177
|
this.logger.log(`Type: ${manifest.pluginType}`);
|
|
180
178
|
this.logger.log(`MLDSA Level: ${mldsaLevel}`);
|
|
179
|
+
this.logger.log(`Checksum: sha256:${checksum.toString('hex')}`);
|
|
181
180
|
this.logger.log(`Signed: ${options.sign ? 'Yes' : 'No'}`);
|
|
182
181
|
this.logger.log('');
|
|
183
182
|
|
|
@@ -164,6 +164,12 @@ export class InitCommand extends BaseCommand {
|
|
|
164
164
|
|
|
165
165
|
// Create README.md
|
|
166
166
|
this.createReadme(projectDir, config, force);
|
|
167
|
+
|
|
168
|
+
// Create ESLint config
|
|
169
|
+
this.createEslintConfig(projectDir, force);
|
|
170
|
+
|
|
171
|
+
// Create Prettier config
|
|
172
|
+
this.createPrettierConfig(projectDir, force);
|
|
167
173
|
}
|
|
168
174
|
|
|
169
175
|
private createPluginJson(
|
|
@@ -179,11 +185,10 @@ export class InitCommand extends BaseCommand {
|
|
|
179
185
|
const manifest: Record<string, unknown> = {
|
|
180
186
|
name: config.pluginName,
|
|
181
187
|
version: '1.0.0',
|
|
182
|
-
opnetVersion: '
|
|
188
|
+
opnetVersion: '>=0.0.1',
|
|
183
189
|
main: 'dist/index.jsc',
|
|
184
190
|
target: 'bytenode',
|
|
185
191
|
type: 'plugin',
|
|
186
|
-
checksum: '',
|
|
187
192
|
author: config.authorEmail
|
|
188
193
|
? { name: config.authorName, email: config.authorEmail }
|
|
189
194
|
: { name: config.authorName },
|
|
@@ -277,9 +282,10 @@ export class InitCommand extends BaseCommand {
|
|
|
277
282
|
main: 'dist/index.js',
|
|
278
283
|
scripts: {
|
|
279
284
|
build: 'tsc',
|
|
280
|
-
compile: 'opnet compile',
|
|
281
|
-
verify: 'opnet verify',
|
|
285
|
+
compile: 'npx opnet compile',
|
|
286
|
+
verify: 'npx opnet verify',
|
|
282
287
|
lint: 'eslint src/',
|
|
288
|
+
format: 'prettier --write src/',
|
|
283
289
|
},
|
|
284
290
|
author: config.authorEmail
|
|
285
291
|
? `${config.authorName} <${config.authorEmail}>`
|
|
@@ -287,8 +293,12 @@ export class InitCommand extends BaseCommand {
|
|
|
287
293
|
license: 'Apache-2.0',
|
|
288
294
|
dependencies: { '@btc-vision/plugin-sdk': '^1.0.0' },
|
|
289
295
|
devDependencies: {
|
|
290
|
-
'@
|
|
296
|
+
'@eslint/js': '^9.39.0',
|
|
297
|
+
'@types/node': '^25.0.0',
|
|
298
|
+
eslint: '^9.39.0',
|
|
299
|
+
prettier: '^3.6.0',
|
|
291
300
|
typescript: '^5.8.0',
|
|
301
|
+
'typescript-eslint': '^8.39.0',
|
|
292
302
|
'@btc-vision/cli': '^1.0.0',
|
|
293
303
|
},
|
|
294
304
|
};
|
|
@@ -454,6 +464,78 @@ Apache-2.0
|
|
|
454
464
|
this.logger.success(' Created README.md');
|
|
455
465
|
}
|
|
456
466
|
|
|
467
|
+
private createEslintConfig(projectDir: string, force?: boolean): void {
|
|
468
|
+
const eslintPath = path.join(projectDir, 'eslint.config.js');
|
|
469
|
+
if (fs.existsSync(eslintPath) && !force) return;
|
|
470
|
+
|
|
471
|
+
const content = `// @ts-check
|
|
472
|
+
|
|
473
|
+
import eslint from '@eslint/js';
|
|
474
|
+
import tseslint from 'typescript-eslint';
|
|
475
|
+
|
|
476
|
+
export default tseslint.config(
|
|
477
|
+
eslint.configs.recommended,
|
|
478
|
+
...tseslint.configs.strictTypeChecked,
|
|
479
|
+
{
|
|
480
|
+
languageOptions: {
|
|
481
|
+
parserOptions: {
|
|
482
|
+
projectService: true,
|
|
483
|
+
tsconfigDirName: import.meta.dirname,
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
rules: {
|
|
487
|
+
'no-undef': 'off',
|
|
488
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
489
|
+
'no-empty': 'off',
|
|
490
|
+
'@typescript-eslint/restrict-template-expressions': 'off',
|
|
491
|
+
'@typescript-eslint/only-throw-error': 'off',
|
|
492
|
+
'@typescript-eslint/no-unnecessary-condition': 'off',
|
|
493
|
+
'@typescript-eslint/unbound-method': 'warn',
|
|
494
|
+
'@typescript-eslint/no-confusing-void-expression': 'off',
|
|
495
|
+
'@typescript-eslint/no-extraneous-class': 'off',
|
|
496
|
+
'no-async-promise-executor': 'off',
|
|
497
|
+
'@typescript-eslint/no-misused-promises': 'off',
|
|
498
|
+
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
|
|
499
|
+
'@typescript-eslint/no-duplicate-enum-values': 'off',
|
|
500
|
+
'prefer-spread': 'off',
|
|
501
|
+
'@typescript-eslint/no-empty-object-type': 'off',
|
|
502
|
+
'@typescript-eslint/no-base-to-string': 'off',
|
|
503
|
+
'@typescript-eslint/no-dynamic-delete': 'off',
|
|
504
|
+
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
files: ['**/*.js'],
|
|
509
|
+
...tseslint.configs.disableTypeChecked,
|
|
510
|
+
},
|
|
511
|
+
);
|
|
512
|
+
`;
|
|
513
|
+
|
|
514
|
+
fs.writeFileSync(eslintPath, content);
|
|
515
|
+
this.logger.success(' Created eslint.config.js');
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
private createPrettierConfig(projectDir: string, force?: boolean): void {
|
|
519
|
+
const prettierPath = path.join(projectDir, '.prettierrc.json');
|
|
520
|
+
if (fs.existsSync(prettierPath) && !force) return;
|
|
521
|
+
|
|
522
|
+
const config = {
|
|
523
|
+
printWidth: 100,
|
|
524
|
+
trailingComma: 'all',
|
|
525
|
+
tabWidth: 4,
|
|
526
|
+
semi: true,
|
|
527
|
+
singleQuote: true,
|
|
528
|
+
quoteProps: 'as-needed',
|
|
529
|
+
bracketSpacing: true,
|
|
530
|
+
bracketSameLine: true,
|
|
531
|
+
arrowParens: 'always',
|
|
532
|
+
singleAttributePerLine: true,
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
fs.writeFileSync(prettierPath, JSON.stringify(config, null, 4));
|
|
536
|
+
this.logger.success(' Created .prettierrc.json');
|
|
537
|
+
}
|
|
538
|
+
|
|
457
539
|
private toPascalCase(str: string): string {
|
|
458
540
|
return str
|
|
459
541
|
.split(/[-_]/)
|
|
@@ -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
|
-
//
|
|
81
|
-
this.logger.info('Signing...');
|
|
82
|
-
const
|
|
83
|
-
const checksum =
|
|
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
|