@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.
- package/README.md +55 -23
- package/build/commands/AcceptCommand.js +62 -15
- package/build/commands/CompileCommand.js +9 -10
- package/build/commands/ConfigCommand.js +2 -27
- package/build/commands/DeprecateCommand.js +32 -11
- package/build/commands/InitCommand.js +1 -7
- package/build/commands/PublishCommand.js +82 -27
- package/build/commands/ScopeRegisterCommand.d.ts +7 -0
- package/build/commands/ScopeRegisterCommand.js +115 -0
- package/build/commands/SignCommand.js +6 -9
- package/build/commands/TransferCommand.js +118 -30
- package/build/commands/UndeprecateCommand.js +31 -10
- package/build/index.js +2 -0
- package/build/lib/binary.d.ts +5 -2
- package/build/lib/binary.js +11 -6
- package/build/lib/config.d.ts +1 -0
- package/build/lib/config.js +3 -2
- package/build/lib/ipfs.js +85 -76
- package/build/lib/manifest.js +1 -1
- package/build/lib/registry.d.ts +1 -1
- package/build/lib/registry.js +3 -3
- package/build/lib/transaction.d.ts +27 -0
- package/build/lib/transaction.js +91 -0
- package/build/lib/wallet.d.ts +7 -7
- package/build/lib/wallet.js +3 -6
- package/build/types/index.d.ts +1 -0
- package/package.json +2 -1
- package/src/commands/AcceptCommand.ts +89 -16
- package/src/commands/CompileCommand.ts +13 -14
- package/src/commands/ConfigCommand.ts +2 -29
- package/src/commands/DeprecateCommand.ts +48 -11
- package/src/commands/InitCommand.ts +1 -7
- package/src/commands/PublishCommand.ts +138 -28
- package/src/commands/ScopeRegisterCommand.ts +164 -0
- package/src/commands/SignCommand.ts +9 -21
- package/src/commands/TransferCommand.ts +159 -31
- package/src/commands/UndeprecateCommand.ts +43 -10
- package/src/index.ts +2 -0
- package/src/lib/binary.ts +24 -22
- package/src/lib/config.ts +3 -2
- package/src/lib/ipfs.ts +113 -99
- package/src/lib/manifest.ts +1 -1
- package/src/lib/registry.ts +5 -2
- package/src/lib/transaction.ts +205 -0
- package/src/lib/wallet.ts +10 -19
- package/src/types/index.ts +3 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
|
+
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
+
import { getRegistryContract, getScope, getScopePrice } from '../lib/registry.js';
|
|
4
|
+
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
|
+
import { CLIWallet } from '../lib/wallet.js';
|
|
6
|
+
import { buildTransactionParams, checkBalance, formatSats, getWalletAddress, } from '../lib/transaction.js';
|
|
7
|
+
export class ScopeRegisterCommand extends BaseCommand {
|
|
8
|
+
constructor() {
|
|
9
|
+
super('scope:register', 'Register a new scope in the registry');
|
|
10
|
+
}
|
|
11
|
+
configure() {
|
|
12
|
+
this.command
|
|
13
|
+
.argument('<name>', 'Scope name (without @)')
|
|
14
|
+
.option('-n, --network <network>', 'Network', 'mainnet')
|
|
15
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
16
|
+
.action((name, options) => this.execute(name, options || { network: 'mainnet' }));
|
|
17
|
+
}
|
|
18
|
+
async execute(name, options) {
|
|
19
|
+
try {
|
|
20
|
+
const scopeName = name.startsWith('@') ? name.substring(1) : name;
|
|
21
|
+
if (!/^[a-z][a-z0-9-]*[a-z0-9]$/.test(scopeName) && !/^[a-z]$/.test(scopeName)) {
|
|
22
|
+
this.logger.fail('Invalid scope name');
|
|
23
|
+
this.logger.error('Scope name must:');
|
|
24
|
+
this.logger.error(' - Start with a lowercase letter');
|
|
25
|
+
this.logger.error(' - Contain only lowercase letters, numbers, and hyphens');
|
|
26
|
+
this.logger.error(' - End with a letter or number');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
this.logger.info('Loading wallet...');
|
|
30
|
+
const credentials = loadCredentials();
|
|
31
|
+
if (!credentials || !canSign(credentials)) {
|
|
32
|
+
this.logger.fail('No credentials configured');
|
|
33
|
+
this.logger.warn('Run `opnet login` to configure your wallet.');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
const wallet = CLIWallet.fromCredentials(credentials);
|
|
37
|
+
this.logger.success('Wallet loaded');
|
|
38
|
+
const network = (options?.network || 'mainnet');
|
|
39
|
+
this.logger.info(`Checking if @${scopeName} is available...`);
|
|
40
|
+
const existingScope = await getScope(scopeName, network);
|
|
41
|
+
if (existingScope) {
|
|
42
|
+
this.logger.fail('Scope already registered');
|
|
43
|
+
this.logger.error(`Scope @${scopeName} is already registered.`);
|
|
44
|
+
this.logger.log(`Owner: ${existingScope.owner}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
this.logger.success(`Scope @${scopeName} is available`);
|
|
48
|
+
this.logger.info('Fetching registration price...');
|
|
49
|
+
const scopePrice = await getScopePrice(network);
|
|
50
|
+
this.logger.success(`Registration price: ${formatSats(scopePrice)}`);
|
|
51
|
+
this.logger.info('Checking wallet balance...');
|
|
52
|
+
const minRequired = scopePrice + 50000n;
|
|
53
|
+
const { sufficient, balance } = await checkBalance(wallet, network, minRequired);
|
|
54
|
+
if (!sufficient) {
|
|
55
|
+
this.logger.fail('Insufficient balance');
|
|
56
|
+
this.logger.error(`Wallet balance: ${formatSats(balance)}`);
|
|
57
|
+
this.logger.error(`Required (approx): ${formatSats(minRequired)}`);
|
|
58
|
+
this.logger.error('Please fund your wallet before registering a scope.');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
this.logger.success(`Wallet balance: ${formatSats(balance)}`);
|
|
62
|
+
this.logger.log('');
|
|
63
|
+
this.logger.info('Scope Registration Summary');
|
|
64
|
+
this.logger.log('─'.repeat(50));
|
|
65
|
+
this.logger.log(`Scope: @${scopeName}`);
|
|
66
|
+
this.logger.log(`Price: ${formatSats(scopePrice)}`);
|
|
67
|
+
this.logger.log(`Network: ${options?.network}`);
|
|
68
|
+
this.logger.log(`Address: ${wallet.p2trAddress}`);
|
|
69
|
+
this.logger.log('');
|
|
70
|
+
if (!options?.yes) {
|
|
71
|
+
const confirmed = await confirm({
|
|
72
|
+
message: `Register scope @${scopeName}?`,
|
|
73
|
+
default: true,
|
|
74
|
+
});
|
|
75
|
+
if (!confirmed) {
|
|
76
|
+
this.logger.warn('Registration cancelled.');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
this.logger.info('Registering scope...');
|
|
81
|
+
const sender = getWalletAddress(wallet);
|
|
82
|
+
const contract = getRegistryContract(network, sender);
|
|
83
|
+
const txParams = buildTransactionParams(wallet, network);
|
|
84
|
+
const registerResult = await contract.registerScope(scopeName);
|
|
85
|
+
if (registerResult.revert) {
|
|
86
|
+
this.logger.fail('Registration would fail');
|
|
87
|
+
this.logger.error(`Reason: ${registerResult.revert}`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
if (registerResult.estimatedGas) {
|
|
91
|
+
this.logger.info(`Estimated gas: ${registerResult.estimatedGas} sats`);
|
|
92
|
+
}
|
|
93
|
+
const receipt = await registerResult.sendTransaction(txParams);
|
|
94
|
+
this.logger.log('');
|
|
95
|
+
this.logger.success('Scope registered successfully!');
|
|
96
|
+
this.logger.log('');
|
|
97
|
+
this.logger.log(`Scope: @${scopeName}`);
|
|
98
|
+
this.logger.log(`Owner: ${wallet.p2trAddress}`);
|
|
99
|
+
this.logger.log(`Transaction ID: ${receipt.transactionId}`);
|
|
100
|
+
this.logger.log(`Fees paid: ${formatSats(receipt.estimatedFees)}`);
|
|
101
|
+
this.logger.log('');
|
|
102
|
+
this.logger.info('You can now publish packages under this scope using: opnet publish');
|
|
103
|
+
this.logger.log('');
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
this.logger.fail('Scope registration failed');
|
|
107
|
+
if (this.isUserCancelled(error)) {
|
|
108
|
+
this.logger.warn('Registration cancelled.');
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
this.exitWithError(this.formatError(error));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export const scopeRegisterCommand = new ScopeRegisterCommand().getCommand();
|
|
@@ -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,
|
|
4
|
+
import { buildOpnetBinary, formatFileSize, parseOpnetBinary } 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 {
|
|
@@ -48,20 +48,17 @@ export class SignCommand extends BaseCommand {
|
|
|
48
48
|
this.logger.log('Use --force to re-sign with your key.');
|
|
49
49
|
process.exit(1);
|
|
50
50
|
}
|
|
51
|
-
this.logger.info('Signing...');
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const signature = wallet.signMLDSA(checksum);
|
|
55
|
-
this.logger.success(`Signed (${formatFileSize(signature.length)} signature)`);
|
|
56
|
-
this.logger.info('Rebuilding binary...');
|
|
57
|
-
const newBinary = buildOpnetBinary({
|
|
51
|
+
this.logger.info('Signing and rebuilding binary...');
|
|
52
|
+
const signFn = (checksum) => wallet.signMLDSA(checksum);
|
|
53
|
+
const { binary: newBinary, checksum } = buildOpnetBinary({
|
|
58
54
|
mldsaLevel: wallet.securityLevel,
|
|
59
55
|
publicKey: wallet.mldsaPublicKey,
|
|
60
|
-
signature,
|
|
61
56
|
metadata: parsed.metadata,
|
|
62
57
|
bytecode: parsed.bytecode,
|
|
63
58
|
proto: parsed.proto ?? Buffer.alloc(0),
|
|
59
|
+
signFn,
|
|
64
60
|
});
|
|
61
|
+
this.logger.success(`Signed (checksum: sha256:${checksum.toString('hex').substring(0, 16)}...)`);
|
|
65
62
|
this.logger.success(`Binary rebuilt (${formatFileSize(newBinary.length)})`);
|
|
66
63
|
const outputPath = options.output || file;
|
|
67
64
|
fs.writeFileSync(outputPath, newBinary);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { confirm, input } from '@inquirer/prompts';
|
|
2
|
+
import { Address } from '@btc-vision/transaction';
|
|
2
3
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
-
import { getPackage, getPendingScopeTransfer, getPendingTransfer, getScope, } from '../lib/registry.js';
|
|
4
|
+
import { getPackage, getPendingScopeTransfer, getPendingTransfer, getRegistryContract, getScope, } from '../lib/registry.js';
|
|
4
5
|
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
6
|
import { CLIWallet } from '../lib/wallet.js';
|
|
7
|
+
import { buildTransactionParams, checkBalance, formatSats, getWalletAddress, } from '../lib/transaction.js';
|
|
6
8
|
export class TransferCommand extends BaseCommand {
|
|
7
9
|
constructor() {
|
|
8
10
|
super('transfer', 'Initiate ownership transfer of a package or scope');
|
|
@@ -25,7 +27,7 @@ export class TransferCommand extends BaseCommand {
|
|
|
25
27
|
this.logger.warn('Run `opnet login` to configure your wallet.');
|
|
26
28
|
process.exit(1);
|
|
27
29
|
}
|
|
28
|
-
CLIWallet.fromCredentials(credentials);
|
|
30
|
+
const wallet = CLIWallet.fromCredentials(credentials);
|
|
29
31
|
this.logger.success('Wallet loaded');
|
|
30
32
|
const network = (options?.network || 'mainnet');
|
|
31
33
|
const isScope = name.startsWith('@') && !name.includes('/');
|
|
@@ -86,26 +88,63 @@ export class TransferCommand extends BaseCommand {
|
|
|
86
88
|
return;
|
|
87
89
|
}
|
|
88
90
|
}
|
|
91
|
+
this.logger.info('Checking wallet balance...');
|
|
92
|
+
const { sufficient, balance } = await checkBalance(wallet, network);
|
|
93
|
+
if (!sufficient) {
|
|
94
|
+
this.logger.fail('Insufficient balance');
|
|
95
|
+
this.logger.error(`Wallet balance: ${formatSats(balance)}`);
|
|
96
|
+
this.logger.error('Please fund your wallet before initiating transfer.');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
this.logger.success(`Wallet balance: ${formatSats(balance)}`);
|
|
89
100
|
this.logger.info('Initiating transfer...');
|
|
101
|
+
const sender = getWalletAddress(wallet);
|
|
102
|
+
const contract = getRegistryContract(network, sender);
|
|
103
|
+
const txParams = buildTransactionParams(wallet, network);
|
|
104
|
+
const newOwnerAddress = Address.fromString(targetOwner);
|
|
90
105
|
if (isScope) {
|
|
91
106
|
const scopeName = name.substring(1);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
107
|
+
const transferResult = await contract.initiateScopeTransfer(scopeName, newOwnerAddress);
|
|
108
|
+
if (transferResult.revert) {
|
|
109
|
+
this.logger.fail('Transfer initiation would fail');
|
|
110
|
+
this.logger.error(`Reason: ${transferResult.revert}`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
if (transferResult.estimatedGas) {
|
|
114
|
+
this.logger.info(`Estimated gas: ${transferResult.estimatedGas} sats`);
|
|
115
|
+
}
|
|
116
|
+
const receipt = await transferResult.sendTransaction(txParams);
|
|
117
|
+
this.logger.log('');
|
|
118
|
+
this.logger.success('Scope transfer initiated successfully!');
|
|
119
|
+
this.logger.log('');
|
|
120
|
+
this.logger.log(`Scope: ${name}`);
|
|
121
|
+
this.logger.log(`New Owner: ${targetOwner}`);
|
|
122
|
+
this.logger.log(`Transaction ID: ${receipt.transactionId}`);
|
|
123
|
+
this.logger.log(`Fees paid: ${formatSats(receipt.estimatedFees)}`);
|
|
124
|
+
this.logger.log('');
|
|
125
|
+
this.logger.warn('Note: The new owner must call `opnet accept` to complete the transfer.');
|
|
97
126
|
}
|
|
98
127
|
else {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
128
|
+
const transferResult = await contract.initiateTransfer(name, newOwnerAddress);
|
|
129
|
+
if (transferResult.revert) {
|
|
130
|
+
this.logger.fail('Transfer initiation would fail');
|
|
131
|
+
this.logger.error(`Reason: ${transferResult.revert}`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
if (transferResult.estimatedGas) {
|
|
135
|
+
this.logger.info(`Estimated gas: ${transferResult.estimatedGas} sats`);
|
|
136
|
+
}
|
|
137
|
+
const receipt = await transferResult.sendTransaction(txParams);
|
|
138
|
+
this.logger.log('');
|
|
139
|
+
this.logger.success('Package transfer initiated successfully!');
|
|
140
|
+
this.logger.log('');
|
|
141
|
+
this.logger.log(`Package: ${name}`);
|
|
142
|
+
this.logger.log(`New Owner: ${targetOwner}`);
|
|
143
|
+
this.logger.log(`Transaction ID: ${receipt.transactionId}`);
|
|
144
|
+
this.logger.log(`Fees paid: ${formatSats(receipt.estimatedFees)}`);
|
|
145
|
+
this.logger.log('');
|
|
146
|
+
this.logger.warn('Note: The new owner must call `opnet accept` to complete the transfer.');
|
|
104
147
|
}
|
|
105
|
-
this.logger.info('Transfer (transaction pending)');
|
|
106
|
-
this.logger.log('');
|
|
107
|
-
this.logger.success('Transfer initiated!');
|
|
108
|
-
this.logger.warn('Note: Registry transaction support is coming soon.');
|
|
109
148
|
this.logger.log('');
|
|
110
149
|
}
|
|
111
150
|
catch (error) {
|
|
@@ -119,6 +158,13 @@ export class TransferCommand extends BaseCommand {
|
|
|
119
158
|
}
|
|
120
159
|
async handleCancel(name, isScope, network, options) {
|
|
121
160
|
this.logger.info('Checking pending transfer...');
|
|
161
|
+
const credentials = loadCredentials();
|
|
162
|
+
if (!credentials || !canSign(credentials)) {
|
|
163
|
+
this.logger.fail('No credentials configured');
|
|
164
|
+
this.logger.warn('Run `opnet login` to configure your wallet.');
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
const wallet = CLIWallet.fromCredentials(credentials);
|
|
122
168
|
if (isScope) {
|
|
123
169
|
const scopeName = name.substring(1);
|
|
124
170
|
const pending = await getPendingScopeTransfer(scopeName, network);
|
|
@@ -138,12 +184,35 @@ export class TransferCommand extends BaseCommand {
|
|
|
138
184
|
return;
|
|
139
185
|
}
|
|
140
186
|
}
|
|
187
|
+
this.logger.info('Checking wallet balance...');
|
|
188
|
+
const { sufficient, balance } = await checkBalance(wallet, network);
|
|
189
|
+
if (!sufficient) {
|
|
190
|
+
this.logger.fail('Insufficient balance');
|
|
191
|
+
this.logger.error(`Wallet balance: ${formatSats(balance)}`);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
this.logger.success(`Wallet balance: ${formatSats(balance)}`);
|
|
141
195
|
this.logger.info('Cancelling transfer...');
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
196
|
+
const sender = getWalletAddress(wallet);
|
|
197
|
+
const contract = getRegistryContract(network, sender);
|
|
198
|
+
const txParams = buildTransactionParams(wallet, network);
|
|
199
|
+
const cancelResult = await contract.cancelScopeTransfer(scopeName);
|
|
200
|
+
if (cancelResult.revert) {
|
|
201
|
+
this.logger.fail('Cancellation would fail');
|
|
202
|
+
this.logger.error(`Reason: ${cancelResult.revert}`);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
if (cancelResult.estimatedGas) {
|
|
206
|
+
this.logger.info(`Estimated gas: ${cancelResult.estimatedGas} sats`);
|
|
207
|
+
}
|
|
208
|
+
const receipt = await cancelResult.sendTransaction(txParams);
|
|
209
|
+
this.logger.log('');
|
|
210
|
+
this.logger.success('Scope transfer cancelled successfully!');
|
|
211
|
+
this.logger.log('');
|
|
212
|
+
this.logger.log(`Scope: ${name}`);
|
|
213
|
+
this.logger.log(`Transaction ID: ${receipt.transactionId}`);
|
|
214
|
+
this.logger.log(`Fees paid: ${formatSats(receipt.estimatedFees)}`);
|
|
215
|
+
this.logger.log('');
|
|
147
216
|
}
|
|
148
217
|
else {
|
|
149
218
|
const pending = await getPendingTransfer(name, network);
|
|
@@ -163,17 +232,36 @@ export class TransferCommand extends BaseCommand {
|
|
|
163
232
|
return;
|
|
164
233
|
}
|
|
165
234
|
}
|
|
235
|
+
this.logger.info('Checking wallet balance...');
|
|
236
|
+
const { sufficient, balance } = await checkBalance(wallet, network);
|
|
237
|
+
if (!sufficient) {
|
|
238
|
+
this.logger.fail('Insufficient balance');
|
|
239
|
+
this.logger.error(`Wallet balance: ${formatSats(balance)}`);
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
this.logger.success(`Wallet balance: ${formatSats(balance)}`);
|
|
166
243
|
this.logger.info('Cancelling transfer...');
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
244
|
+
const sender = getWalletAddress(wallet);
|
|
245
|
+
const contract = getRegistryContract(network, sender);
|
|
246
|
+
const txParams = buildTransactionParams(wallet, network);
|
|
247
|
+
const cancelResult = await contract.cancelTransfer(name);
|
|
248
|
+
if (cancelResult.revert) {
|
|
249
|
+
this.logger.fail('Cancellation would fail');
|
|
250
|
+
this.logger.error(`Reason: ${cancelResult.revert}`);
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
if (cancelResult.estimatedGas) {
|
|
254
|
+
this.logger.info(`Estimated gas: ${cancelResult.estimatedGas} sats`);
|
|
255
|
+
}
|
|
256
|
+
const receipt = await cancelResult.sendTransaction(txParams);
|
|
257
|
+
this.logger.log('');
|
|
258
|
+
this.logger.success('Package transfer cancelled successfully!');
|
|
259
|
+
this.logger.log('');
|
|
260
|
+
this.logger.log(`Package: ${name}`);
|
|
261
|
+
this.logger.log(`Transaction ID: ${receipt.transactionId}`);
|
|
262
|
+
this.logger.log(`Fees paid: ${formatSats(receipt.estimatedFees)}`);
|
|
263
|
+
this.logger.log('');
|
|
172
264
|
}
|
|
173
|
-
this.logger.log('');
|
|
174
|
-
this.logger.success('Transfer cancellation submitted!');
|
|
175
|
-
this.logger.warn('Note: Registry transaction support is coming soon.');
|
|
176
|
-
this.logger.log('');
|
|
177
265
|
}
|
|
178
266
|
}
|
|
179
267
|
export const transferCommand = new TransferCommand().getCommand();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { confirm } from '@inquirer/prompts';
|
|
2
2
|
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
-
import { getPackage, getVersion, isVersionImmutable } from '../lib/registry.js';
|
|
3
|
+
import { getPackage, getRegistryContract, getVersion, isVersionImmutable } from '../lib/registry.js';
|
|
4
4
|
import { canSign, loadCredentials } from '../lib/credentials.js';
|
|
5
5
|
import { CLIWallet } from '../lib/wallet.js';
|
|
6
|
+
import { buildTransactionParams, checkBalance, formatSats, getWalletAddress, } from '../lib/transaction.js';
|
|
6
7
|
export class UndeprecateCommand extends BaseCommand {
|
|
7
8
|
constructor() {
|
|
8
9
|
super('undeprecate', 'Remove deprecation from a package version');
|
|
@@ -24,7 +25,7 @@ export class UndeprecateCommand extends BaseCommand {
|
|
|
24
25
|
this.logger.warn('Run `opnet login` to configure your wallet.');
|
|
25
26
|
process.exit(1);
|
|
26
27
|
}
|
|
27
|
-
CLIWallet.fromCredentials(credentials);
|
|
28
|
+
const wallet = CLIWallet.fromCredentials(credentials);
|
|
28
29
|
this.logger.success('Wallet loaded');
|
|
29
30
|
this.logger.info('Fetching package info...');
|
|
30
31
|
const network = (options?.network || 'mainnet');
|
|
@@ -70,16 +71,36 @@ export class UndeprecateCommand extends BaseCommand {
|
|
|
70
71
|
return;
|
|
71
72
|
}
|
|
72
73
|
}
|
|
74
|
+
this.logger.info('Checking wallet balance...');
|
|
75
|
+
const { sufficient, balance } = await checkBalance(wallet, network);
|
|
76
|
+
if (!sufficient) {
|
|
77
|
+
this.logger.fail('Insufficient balance');
|
|
78
|
+
this.logger.error(`Wallet balance: ${formatSats(balance)}`);
|
|
79
|
+
this.logger.error('Please fund your wallet before undeprecating.');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
this.logger.success(`Wallet balance: ${formatSats(balance)}`);
|
|
73
83
|
this.logger.info('Removing deprecation...');
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
84
|
+
const sender = getWalletAddress(wallet);
|
|
85
|
+
const contract = getRegistryContract(network, sender);
|
|
86
|
+
const txParams = buildTransactionParams(wallet, network);
|
|
87
|
+
const undeprecateResult = await contract.undeprecateVersion(packageName, version);
|
|
88
|
+
if (undeprecateResult.revert) {
|
|
89
|
+
this.logger.fail('Undeprecation would fail');
|
|
90
|
+
this.logger.error(`Reason: ${undeprecateResult.revert}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
if (undeprecateResult.estimatedGas) {
|
|
94
|
+
this.logger.info(`Estimated gas: ${undeprecateResult.estimatedGas} sats`);
|
|
95
|
+
}
|
|
96
|
+
const receipt = await undeprecateResult.sendTransaction(txParams);
|
|
97
|
+
this.logger.log('');
|
|
98
|
+
this.logger.success('Deprecation removed successfully!');
|
|
80
99
|
this.logger.log('');
|
|
81
|
-
this.logger.
|
|
82
|
-
this.logger.
|
|
100
|
+
this.logger.log(`Package: ${packageName}`);
|
|
101
|
+
this.logger.log(`Version: ${version}`);
|
|
102
|
+
this.logger.log(`Transaction ID: ${receipt.transactionId}`);
|
|
103
|
+
this.logger.log(`Fees paid: ${formatSats(receipt.estimatedFees)}`);
|
|
83
104
|
this.logger.log('');
|
|
84
105
|
}
|
|
85
106
|
catch (error) {
|
package/build/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import { deprecateCommand } from './commands/DeprecateCommand.js';
|
|
|
16
16
|
import { undeprecateCommand } from './commands/UndeprecateCommand.js';
|
|
17
17
|
import { transferCommand } from './commands/TransferCommand.js';
|
|
18
18
|
import { acceptCommand } from './commands/AcceptCommand.js';
|
|
19
|
+
import { scopeRegisterCommand } from './commands/ScopeRegisterCommand.js';
|
|
19
20
|
import { installCommand } from './commands/InstallCommand.js';
|
|
20
21
|
import { updateCommand } from './commands/UpdateCommand.js';
|
|
21
22
|
import { listCommand } from './commands/ListCommand.js';
|
|
@@ -41,6 +42,7 @@ program.addCommand(deprecateCommand);
|
|
|
41
42
|
program.addCommand(undeprecateCommand);
|
|
42
43
|
program.addCommand(transferCommand);
|
|
43
44
|
program.addCommand(acceptCommand);
|
|
45
|
+
program.addCommand(scopeRegisterCommand);
|
|
44
46
|
program.addCommand(installCommand);
|
|
45
47
|
program.addCommand(updateCommand);
|
|
46
48
|
program.addCommand(listCommand);
|
package/build/lib/binary.d.ts
CHANGED
|
@@ -6,11 +6,14 @@ export declare function verifyChecksum(parsed: IParsedPluginFile): boolean;
|
|
|
6
6
|
export declare function buildOpnetBinary(options: {
|
|
7
7
|
mldsaLevel: CLIMldsaLevel;
|
|
8
8
|
publicKey: Buffer;
|
|
9
|
-
signature: Buffer;
|
|
10
9
|
metadata: IPluginMetadata;
|
|
11
10
|
bytecode: Buffer;
|
|
12
11
|
proto?: Buffer;
|
|
13
|
-
|
|
12
|
+
signFn?: (checksum: Buffer) => Buffer;
|
|
13
|
+
}): {
|
|
14
|
+
binary: Buffer;
|
|
15
|
+
checksum: Buffer;
|
|
16
|
+
};
|
|
14
17
|
export declare function extractMetadata(data: Buffer): IPluginMetadata | null;
|
|
15
18
|
export declare function getParsedMldsaLevel(parsed: IParsedPluginFile): CLIMldsaLevel;
|
|
16
19
|
export declare function formatFileSize(bytes: number): string;
|
package/build/lib/binary.js
CHANGED
|
@@ -91,19 +91,24 @@ 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 +
|
|
@@ -140,8 +145,8 @@ export function buildOpnetBinary(options) {
|
|
|
140
145
|
offset += 4;
|
|
141
146
|
proto.copy(buffer, offset);
|
|
142
147
|
offset += proto.length;
|
|
143
|
-
|
|
144
|
-
return buffer;
|
|
148
|
+
finalChecksum.copy(buffer, offset);
|
|
149
|
+
return { binary: buffer, checksum: finalChecksum };
|
|
145
150
|
}
|
|
146
151
|
export function extractMetadata(data) {
|
|
147
152
|
try {
|
package/build/lib/config.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CLIConfig, CLIMldsaLevel, NetworkName } from '../types/index.js';
|
|
2
|
+
export declare const DEFAULT_CONFIG: CLIConfig;
|
|
2
3
|
export declare function ensureConfigDir(): void;
|
|
3
4
|
export declare function loadConfig(): CLIConfig;
|
|
4
5
|
export declare function saveConfig(config: CLIConfig): void;
|
package/build/lib/config.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as path from 'path';
|
|
|
3
3
|
import * as os from 'os';
|
|
4
4
|
const CONFIG_DIR = path.join(os.homedir(), '.opnet');
|
|
5
5
|
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
6
|
-
const DEFAULT_CONFIG = {
|
|
6
|
+
export const DEFAULT_CONFIG = {
|
|
7
7
|
defaultNetwork: 'regtest',
|
|
8
8
|
rpcUrls: {
|
|
9
9
|
mainnet: 'https://api.opnet.org',
|
|
@@ -19,11 +19,12 @@ const DEFAULT_CONFIG = {
|
|
|
19
19
|
],
|
|
20
20
|
ipfsPinningEndpoint: 'https://ipfs.opnet.org/api/v0/add',
|
|
21
21
|
ipfsPinningApiKey: '',
|
|
22
|
+
ipfsPinningSecret: '',
|
|
22
23
|
ipfsPinningAuthHeader: 'Authorization',
|
|
23
24
|
registryAddresses: {
|
|
24
25
|
mainnet: '',
|
|
25
26
|
testnet: '',
|
|
26
|
-
regtest: '',
|
|
27
|
+
regtest: '0x0737d17d0eff9915208f3c20ed7659587889bc94d25972672b3a6c03ff4ddbcc',
|
|
27
28
|
},
|
|
28
29
|
defaultMldsaLevel: 44,
|
|
29
30
|
indexerUrl: 'https://indexer.opnet.org',
|