@btc-vision/cli 1.0.5 → 1.0.7

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 (51) hide show
  1. package/build/index.js +3 -4
  2. package/build/lib/config.js +1 -6
  3. package/build/lib/ipfs.d.ts +0 -2
  4. package/build/lib/ipfs.js +29 -32
  5. package/build/lib/wallet.js +1 -1
  6. package/package.json +4 -1
  7. package/.gitattributes +0 -2
  8. package/.github/dependabot.yml +0 -9
  9. package/.github/workflows/ci.yml +0 -48
  10. package/.prettierrc.json +0 -12
  11. package/CONTRIBUTING.md +0 -56
  12. package/NOTICE +0 -17
  13. package/SECURITY.md +0 -35
  14. package/eslint.config.js +0 -41
  15. package/gulpfile.js +0 -41
  16. package/src/commands/AcceptCommand.ts +0 -224
  17. package/src/commands/BaseCommand.ts +0 -59
  18. package/src/commands/CompileCommand.ts +0 -195
  19. package/src/commands/ConfigCommand.ts +0 -117
  20. package/src/commands/DeprecateCommand.ts +0 -193
  21. package/src/commands/InfoCommand.ts +0 -293
  22. package/src/commands/InitCommand.ts +0 -541
  23. package/src/commands/InstallCommand.ts +0 -179
  24. package/src/commands/KeygenCommand.ts +0 -157
  25. package/src/commands/ListCommand.ts +0 -169
  26. package/src/commands/LoginCommand.ts +0 -197
  27. package/src/commands/LogoutCommand.ts +0 -76
  28. package/src/commands/PublishCommand.ts +0 -340
  29. package/src/commands/ScopeRegisterCommand.ts +0 -164
  30. package/src/commands/SearchCommand.ts +0 -140
  31. package/src/commands/SignCommand.ts +0 -110
  32. package/src/commands/TransferCommand.ts +0 -363
  33. package/src/commands/UndeprecateCommand.ts +0 -167
  34. package/src/commands/UpdateCommand.ts +0 -200
  35. package/src/commands/VerifyCommand.ts +0 -228
  36. package/src/commands/WhoamiCommand.ts +0 -113
  37. package/src/index.ts +0 -88
  38. package/src/lib/PackageRegistry.abi.json +0 -765
  39. package/src/lib/PackageRegistry.abi.ts +0 -365
  40. package/src/lib/binary.ts +0 -338
  41. package/src/lib/config.ts +0 -265
  42. package/src/lib/credentials.ts +0 -176
  43. package/src/lib/ipfs.ts +0 -382
  44. package/src/lib/manifest.ts +0 -195
  45. package/src/lib/provider.ts +0 -121
  46. package/src/lib/registry.ts +0 -467
  47. package/src/lib/transaction.ts +0 -205
  48. package/src/lib/wallet.ts +0 -262
  49. package/src/types/PackageRegistry.ts +0 -344
  50. package/src/types/index.ts +0 -147
  51. package/tsconfig.json +0 -25
@@ -1,467 +0,0 @@
1
- /**
2
- * Package Registry contract interactions for OPNet CLI
3
- *
4
- * Provides functions for interacting with the on-chain PackageRegistry contract.
5
- *
6
- * @module lib/registry
7
- */
8
-
9
- import { getContract } from 'opnet';
10
- import { Address } from '@btc-vision/transaction';
11
- import * as crypto from 'crypto';
12
-
13
- import { CLIMldsaLevel, NetworkName, RegistryPluginType } from '../types/index.js';
14
- import { IPluginPermissions } from '@btc-vision/plugin-sdk';
15
- import { IPackageRegistry } from '../types/PackageRegistry.js';
16
- import { getProvider, getRegistryContractAddress } from './provider.js';
17
- import { getNetwork } from './wallet.js';
18
- import { loadConfig } from './config.js';
19
- import { PACKAGE_REGISTRY_ABI } from './PackageRegistry.abi.js';
20
-
21
- /**
22
- * Scope information
23
- */
24
- export interface ScopeInfo {
25
- exists: boolean;
26
- owner: Address;
27
- createdAt: bigint;
28
- }
29
-
30
- /**
31
- * Package information
32
- */
33
- export interface PackageInfo {
34
- exists: boolean;
35
- owner: Address;
36
- createdAt: bigint;
37
- versionCount: bigint;
38
- latestVersion: string;
39
- }
40
-
41
- /**
42
- * Version information
43
- */
44
- export interface VersionInfo {
45
- exists: boolean;
46
- ipfsCid: string;
47
- checksum: Uint8Array;
48
- sigHash: Uint8Array;
49
- mldsaLevel: number;
50
- opnetVersionRange: string;
51
- pluginType: number;
52
- permissionsHash: Uint8Array;
53
- depsHash: Uint8Array;
54
- publisher: Address;
55
- publishedAt: bigint;
56
- deprecated: boolean;
57
- }
58
-
59
- /**
60
- * Pending transfer information
61
- */
62
- export interface PendingTransferInfo {
63
- pendingOwner: Address;
64
- initiatedAt: bigint;
65
- }
66
-
67
- /**
68
- * Registry contract cache
69
- */
70
- const registryCache = new Map<string, IPackageRegistry>();
71
-
72
- /**
73
- * Get the registry contract instance
74
- *
75
- * @param network - Network name (defaults to configured default)
76
- * @param sender - Optional sender address for write operations
77
- * @returns Contract instance
78
- */
79
- export function getRegistryContract(network?: NetworkName, sender?: Address): IPackageRegistry {
80
- const config = loadConfig();
81
- const targetNetwork = network || config.defaultNetwork;
82
- // Include sender in cache key to handle both read-only and write cases
83
- const cacheKey = sender ? `${targetNetwork}:${sender.toHex()}` : targetNetwork;
84
-
85
- const cached = registryCache.get(cacheKey);
86
- if (cached) {
87
- return cached;
88
- }
89
-
90
- const provider = getProvider(targetNetwork);
91
- const registryAddress = getRegistryContractAddress(targetNetwork);
92
- const bitcoinNetwork = getNetwork(targetNetwork);
93
-
94
- const contract = getContract<IPackageRegistry>(
95
- registryAddress,
96
- PACKAGE_REGISTRY_ABI,
97
- provider,
98
- bitcoinNetwork,
99
- sender,
100
- );
101
-
102
- registryCache.set(cacheKey, contract);
103
- return contract;
104
- }
105
-
106
- /**
107
- * Clear registry contract cache
108
- */
109
- export function clearRegistryCache(): void {
110
- registryCache.clear();
111
- }
112
-
113
- /**
114
- * Get scope information
115
- *
116
- * @param scopeName - The scope name (without @)
117
- * @param network - Network name
118
- * @returns Scope information or null if not found
119
- */
120
- export async function getScope(
121
- scopeName: string,
122
- network?: NetworkName,
123
- ): Promise<ScopeInfo | null> {
124
- const contract = getRegistryContract(network);
125
- const result = await contract.getScope(scopeName);
126
-
127
- if (!result.properties.exists) {
128
- return null;
129
- }
130
-
131
- return {
132
- exists: result.properties.exists,
133
- owner: result.properties.owner,
134
- createdAt: result.properties.createdAt,
135
- };
136
- }
137
-
138
- /**
139
- * Get scope owner
140
- *
141
- * @param scopeName - The scope name (without @)
142
- * @param network - Network name
143
- * @returns Owner address or null if scope doesn't exist
144
- */
145
- export async function getScopeOwner(
146
- scopeName: string,
147
- network?: NetworkName,
148
- ): Promise<Address | null> {
149
- const contract = getRegistryContract(network);
150
- try {
151
- const result = await contract.getScopeOwner(scopeName);
152
- return result.properties.owner;
153
- } catch {
154
- return null;
155
- }
156
- }
157
-
158
- /**
159
- * Get package information
160
- *
161
- * @param packageName - The package name (with @ for scoped)
162
- * @param network - Network name
163
- * @returns Package information or null if not found
164
- */
165
- export async function getPackage(
166
- packageName: string,
167
- network?: NetworkName,
168
- ): Promise<PackageInfo | null> {
169
- const contract = getRegistryContract(network);
170
- const result = await contract.getPackage(packageName);
171
-
172
- if (!result.properties.exists) {
173
- return null;
174
- }
175
-
176
- return {
177
- exists: result.properties.exists,
178
- owner: result.properties.owner,
179
- createdAt: result.properties.createdAt,
180
- versionCount: result.properties.versionCount,
181
- latestVersion: result.properties.latestVersion,
182
- };
183
- }
184
-
185
- /**
186
- * Get package owner
187
- *
188
- * @param packageName - The package name
189
- * @param network - Network name
190
- * @returns Owner address or null if package doesn't exist
191
- */
192
- export async function getPackageOwner(
193
- packageName: string,
194
- network?: NetworkName,
195
- ): Promise<Address | null> {
196
- const contract = getRegistryContract(network);
197
- try {
198
- const result = await contract.getOwner(packageName);
199
- return result.properties.owner;
200
- } catch {
201
- return null;
202
- }
203
- }
204
-
205
- /**
206
- * Get version information
207
- *
208
- * @param packageName - The package name
209
- * @param version - The version string (semver)
210
- * @param network - Network name
211
- * @returns Version information or null if not found
212
- */
213
- export async function getVersion(
214
- packageName: string,
215
- version: string,
216
- network?: NetworkName,
217
- ): Promise<VersionInfo | null> {
218
- const contract = getRegistryContract(network);
219
- const result = await contract.getVersion(packageName, version);
220
-
221
- if (!result.properties.exists) {
222
- return null;
223
- }
224
-
225
- return {
226
- exists: result.properties.exists,
227
- ipfsCid: result.properties.ipfsCid,
228
- checksum: result.properties.checksum,
229
- sigHash: result.properties.sigHash,
230
- mldsaLevel: result.properties.mldsaLevel,
231
- opnetVersionRange: result.properties.opnetVersionRange,
232
- pluginType: result.properties.pluginType,
233
- permissionsHash: result.properties.permissionsHash,
234
- depsHash: result.properties.depsHash,
235
- publisher: result.properties.publisher,
236
- publishedAt: result.properties.publishedAt,
237
- deprecated: result.properties.deprecated,
238
- };
239
- }
240
-
241
- /**
242
- * Check if a version is deprecated
243
- *
244
- * @param packageName - The package name
245
- * @param version - The version string
246
- * @param network - Network name
247
- * @returns True if deprecated
248
- */
249
- export async function isVersionDeprecated(
250
- packageName: string,
251
- version: string,
252
- network?: NetworkName,
253
- ): Promise<boolean> {
254
- const contract = getRegistryContract(network);
255
- const result = await contract.isDeprecated(packageName, version);
256
- return result.properties.deprecated;
257
- }
258
-
259
- /**
260
- * Check if a version is immutable (past 72-hour window)
261
- *
262
- * @param packageName - The package name
263
- * @param version - The version string
264
- * @param network - Network name
265
- * @returns True if immutable
266
- */
267
- export async function isVersionImmutable(
268
- packageName: string,
269
- version: string,
270
- network?: NetworkName,
271
- ): Promise<boolean> {
272
- const contract = getRegistryContract(network);
273
- const result = await contract.isImmutable(packageName, version);
274
- return result.properties.immutable;
275
- }
276
-
277
- /**
278
- * Get pending package transfer
279
- *
280
- * @param packageName - The package name
281
- * @param network - Network name
282
- * @returns Pending transfer info or null
283
- */
284
- export async function getPendingTransfer(
285
- packageName: string,
286
- network?: NetworkName,
287
- ): Promise<PendingTransferInfo | null> {
288
- const contract = getRegistryContract(network);
289
- try {
290
- const result = await contract.getPendingTransfer(packageName);
291
- const pendingOwner = result.properties.pendingOwner;
292
-
293
- // Check if there's actually a pending transfer (address not zero)
294
- if (!pendingOwner || pendingOwner.toString() === '0'.repeat(64)) {
295
- return null;
296
- }
297
-
298
- return {
299
- pendingOwner,
300
- initiatedAt: result.properties.initiatedAt,
301
- };
302
- } catch {
303
- return null;
304
- }
305
- }
306
-
307
- /**
308
- * Get pending scope transfer
309
- *
310
- * @param scopeName - The scope name
311
- * @param network - Network name
312
- * @returns Pending transfer info or null
313
- */
314
- export async function getPendingScopeTransfer(
315
- scopeName: string,
316
- network?: NetworkName,
317
- ): Promise<PendingTransferInfo | null> {
318
- const contract = getRegistryContract(network);
319
- try {
320
- const result = await contract.getPendingScopeTransfer(scopeName);
321
- const pendingOwner = result.properties.pendingOwner;
322
-
323
- // Check if there's actually a pending transfer (address not zero)
324
- if (!pendingOwner || pendingOwner.toString() === '0'.repeat(64)) {
325
- return null;
326
- }
327
-
328
- return {
329
- pendingOwner,
330
- initiatedAt: result.properties.initiatedAt,
331
- };
332
- } catch {
333
- return null;
334
- }
335
- }
336
-
337
- /**
338
- * Get treasury address
339
- *
340
- * @param network - Network name
341
- * @returns Treasury address string
342
- */
343
- export async function getTreasuryAddress(network?: NetworkName): Promise<string> {
344
- const contract = getRegistryContract(network);
345
- const result = await contract.getTreasuryAddress();
346
- return result.properties.treasuryAddress;
347
- }
348
-
349
- /**
350
- * Get scope registration price
351
- *
352
- * @param network - Network name
353
- * @returns Price in satoshis
354
- */
355
- export async function getScopePrice(network?: NetworkName): Promise<bigint> {
356
- const contract = getRegistryContract(network);
357
- const result = await contract.getScopePrice();
358
- return result.properties.priceSats;
359
- }
360
-
361
- /**
362
- * Get package registration price
363
- *
364
- * @param network - Network name
365
- * @returns Price in satoshis
366
- */
367
- export async function getPackagePrice(network?: NetworkName): Promise<bigint> {
368
- const contract = getRegistryContract(network);
369
- const result = await contract.getPackagePrice();
370
- return result.properties.priceSats;
371
- }
372
-
373
- /**
374
- * Parse a package name into scope and name
375
- *
376
- * @param fullName - Full package name (e.g., "@scope/name" or "name")
377
- * @returns Object with scope (or null) and name
378
- */
379
- export function parsePackageName(fullName: string): { scope: string | null; name: string } {
380
- if (fullName.startsWith('@')) {
381
- const slashIndex = fullName.indexOf('/');
382
- if (slashIndex > 0) {
383
- return {
384
- scope: fullName.substring(1, slashIndex),
385
- name: fullName.substring(slashIndex + 1),
386
- };
387
- }
388
- }
389
- return { scope: null, name: fullName };
390
- }
391
-
392
- /**
393
- * Compute permissions hash from permissions object
394
- *
395
- * @param permissions - Plugin permissions
396
- * @returns SHA-256 hash as Uint8Array
397
- */
398
- export function computePermissionsHash(permissions: IPluginPermissions | undefined): Uint8Array {
399
- const json = JSON.stringify(permissions);
400
- const hash = crypto.createHash('sha256').update(json).digest();
401
- return new Uint8Array(hash);
402
- }
403
-
404
- /**
405
- * Encode dependencies for publishing
406
- *
407
- * @param dependencies - Dependencies map { name: version }
408
- * @returns Encoded dependencies as Uint8Array
409
- */
410
- export function encodeDependencies(dependencies: Record<string, string>): Uint8Array {
411
- if (Object.keys(dependencies).length === 0) {
412
- return new Uint8Array(0);
413
- }
414
-
415
- const json = JSON.stringify(dependencies);
416
- return new Uint8Array(Buffer.from(json, 'utf-8'));
417
- }
418
-
419
- /**
420
- * Convert registry MLDSA level (1, 2, 3) to actual level (44, 65, 87)
421
- *
422
- * @param registryLevel - Registry level (1, 2, 3)
423
- * @returns MLDSA level (44, 65, 87)
424
- */
425
- export function registryToMldsaLevel(registryLevel: number): CLIMldsaLevel {
426
- const levels: Record<number, CLIMldsaLevel> = {
427
- 1: 44,
428
- 2: 65,
429
- 3: 87,
430
- };
431
- return levels[registryLevel] || 44;
432
- }
433
-
434
- /**
435
- * Convert MLDSA level (44, 65, 87) to registry level (1, 2, 3)
436
- *
437
- * @param mldsaLevel - MLDSA level (44, 65, 87)
438
- * @returns Registry level (1, 2, 3)
439
- */
440
- export function mldsaLevelToRegistry(mldsaLevel: CLIMldsaLevel): number {
441
- const levels: Record<CLIMldsaLevel, number> = {
442
- 44: 1,
443
- 65: 2,
444
- 87: 3,
445
- };
446
- return levels[mldsaLevel] || 1;
447
- }
448
-
449
- /**
450
- * Convert registry plugin type (1, 2) to string
451
- *
452
- * @param registryType - Registry plugin type (1, 2)
453
- * @returns Plugin type string
454
- */
455
- export function registryToPluginType(registryType: number): RegistryPluginType {
456
- return registryType === 2 ? 'library' : 'standalone';
457
- }
458
-
459
- /**
460
- * Convert plugin type string to registry value
461
- *
462
- * @param pluginType - Plugin type string
463
- * @returns Registry plugin type (1, 2)
464
- */
465
- export function pluginTypeToRegistry(pluginType: RegistryPluginType): number {
466
- return pluginType === 'library' ? 2 : 1;
467
- }
@@ -1,205 +0,0 @@
1
- /**
2
- * Transaction helper for OPNet CLI
3
- *
4
- * Provides utilities for building and executing registry transactions.
5
- *
6
- * @module lib/transaction
7
- */
8
-
9
- import { Address } from '@btc-vision/transaction';
10
- import { TransactionParameters } from 'opnet';
11
- import ora, { Ora } from 'ora';
12
-
13
- import { CLIWallet, getNetwork } from './wallet.js';
14
- import { NetworkName } from '../types/index.js';
15
- import { getProvider } from './provider.js';
16
- import { PsbtOutputExtended } from '@btc-vision/bitcoin';
17
-
18
- /** Default maximum satoshis to spend per transaction */
19
- export const DEFAULT_MAX_SAT_TO_SPEND = 100_000n;
20
-
21
- /** Default fee rate in sat/vbyte */
22
- export const DEFAULT_FEE_RATE = 6;
23
-
24
- /**
25
- * Build TransactionParameters from a CLIWallet
26
- *
27
- * @param wallet - The CLI wallet instance
28
- * @param network - Target network name
29
- * @param maxSatToSpend - Maximum satoshis to spend (optional)
30
- * @param feeRate - Fee rate in sat/vbyte (optional)
31
- * @param extra
32
- * @returns TransactionParameters for contract calls
33
- */
34
- export function buildTransactionParams(
35
- wallet: CLIWallet,
36
- network: NetworkName,
37
- maxSatToSpend: bigint = DEFAULT_MAX_SAT_TO_SPEND,
38
- feeRate: number = DEFAULT_FEE_RATE,
39
- extra?: PsbtOutputExtended,
40
- ): TransactionParameters {
41
- const bitcoinNetwork = getNetwork(network);
42
-
43
- return {
44
- signer: wallet.keypair,
45
- mldsaSigner: wallet.mldsaKeypair,
46
- refundTo: wallet.p2trAddress,
47
- maximumAllowedSatToSpend: maxSatToSpend,
48
- network: bitcoinNetwork,
49
- feeRate,
50
- extraOutputs: extra ? [extra] : undefined,
51
- };
52
- }
53
-
54
- /**
55
- * Get the sender Address from a wallet
56
- *
57
- * @param wallet - The CLI wallet
58
- * @returns Address instance for the wallet
59
- */
60
- export function getWalletAddress(wallet: CLIWallet): Address {
61
- return wallet.address;
62
- }
63
-
64
- /**
65
- * Format satoshis for display
66
- *
67
- * @param sats - Amount in satoshis
68
- * @returns Formatted string with BTC equivalent
69
- */
70
- export function formatSats(sats: bigint): string {
71
- const btc = Number(sats) / 100_000_000;
72
- if (btc >= 0.001) {
73
- return `${sats} sats (${btc.toFixed(8)} BTC)`;
74
- }
75
- return `${sats} sats`;
76
- }
77
-
78
- /**
79
- * Check if wallet has sufficient balance for transaction
80
- *
81
- * @param wallet - The CLI wallet
82
- * @param network - Target network
83
- * @param minBalance - Minimum required balance in satoshis
84
- * @returns True if balance is sufficient
85
- */
86
- export async function checkBalance(
87
- wallet: CLIWallet,
88
- network: NetworkName,
89
- minBalance: bigint = 10_000n,
90
- ): Promise<{ sufficient: boolean; balance: bigint }> {
91
- const provider = getProvider(network);
92
- const balance = await provider.getBalance(wallet.p2trAddress);
93
-
94
- return {
95
- sufficient: balance >= minBalance,
96
- balance,
97
- };
98
- }
99
-
100
- /** Default polling interval in milliseconds */
101
- export const DEFAULT_POLL_INTERVAL = 10_000;
102
-
103
- /** Default maximum wait time in milliseconds (10 minutes) */
104
- export const DEFAULT_MAX_WAIT_TIME = 600_000;
105
-
106
- export interface TransactionConfirmationResult {
107
- confirmed: boolean;
108
- blockNumber?: bigint;
109
- revert?: string;
110
- error?: string;
111
- }
112
-
113
- /**
114
- * Wait for a transaction to be confirmed on-chain
115
- *
116
- * Polls the transaction status every pollInterval ms until:
117
- * - The transaction is confirmed (has a blockNumber)
118
- * - The transaction fails (has a revert)
119
- * - The maximum wait time is exceeded
120
- *
121
- * @param txHash - The transaction hash to wait for
122
- * @param network - Target network
123
- * @param options - Optional configuration
124
- * @returns Transaction confirmation result
125
- */
126
- export async function waitForTransactionConfirmation(
127
- txHash: string,
128
- network: NetworkName,
129
- options?: {
130
- pollInterval?: number;
131
- maxWaitTime?: number;
132
- message?: string;
133
- },
134
- ): Promise<TransactionConfirmationResult> {
135
- const pollInterval = options?.pollInterval ?? DEFAULT_POLL_INTERVAL;
136
- const maxWaitTime = options?.maxWaitTime ?? DEFAULT_MAX_WAIT_TIME;
137
- const message = options?.message ?? 'Waiting for transaction confirmation';
138
-
139
- const provider = getProvider(network);
140
- const startTime = Date.now();
141
-
142
- const spinner: Ora = ora({
143
- text: `${message} (0s elapsed)`,
144
- spinner: 'dots',
145
- }).start();
146
-
147
- const updateSpinnerText = (): void => {
148
- const elapsed = Math.floor((Date.now() - startTime) / 1000);
149
- spinner.text = `${message} (${elapsed}s elapsed)`;
150
- };
151
-
152
- // Update spinner text every second
153
- const textUpdateInterval = setInterval(updateSpinnerText, 1000);
154
-
155
- try {
156
- while (Date.now() - startTime < maxWaitTime) {
157
- try {
158
- const tx = await provider.getTransaction(txHash);
159
-
160
- // Check if transaction has a block number (confirmed)
161
- if (tx.blockNumber !== undefined && tx.blockNumber !== null) {
162
- const blockNum =
163
- typeof tx.blockNumber === 'bigint'
164
- ? tx.blockNumber
165
- : BigInt(tx.blockNumber);
166
- spinner.succeed(`Transaction confirmed in block ${blockNum}`);
167
- return {
168
- confirmed: true,
169
- blockNumber: blockNum,
170
- };
171
- }
172
-
173
- // Check if transaction reverted
174
- if (tx.revert) {
175
- spinner.fail(`Transaction reverted: ${tx.revert}`);
176
- return {
177
- confirmed: false,
178
- revert: tx.revert,
179
- };
180
- }
181
- } catch {
182
- // Transaction not found yet, continue polling
183
- }
184
-
185
- // Wait before next poll
186
- await sleep(pollInterval);
187
- }
188
-
189
- // Timeout reached
190
- spinner.fail(`Timeout waiting for transaction confirmation`);
191
- return {
192
- confirmed: false,
193
- error: `Transaction not confirmed within ${maxWaitTime / 1000} seconds`,
194
- };
195
- } finally {
196
- clearInterval(textUpdateInterval);
197
- }
198
- }
199
-
200
- /**
201
- * Sleep for a given number of milliseconds
202
- */
203
- function sleep(ms: number): Promise<void> {
204
- return new Promise((resolve) => setTimeout(resolve, ms));
205
- }