@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
package/src/lib/ipfs.ts DELETED
@@ -1,382 +0,0 @@
1
- /**
2
- * IPFS operations for OPNet CLI
3
- *
4
- * Handles pinning and fetching plugin binaries from IPFS.
5
- *
6
- * @module lib/ipfs
7
- */
8
-
9
- import * as https from 'https';
10
- import * as http from 'http';
11
- import * as fs from 'fs';
12
- import { loadConfig } from './config.js';
13
-
14
- /**
15
- * IPFS pinning result
16
- */
17
- export interface PinResult {
18
- cid: string;
19
- size: number;
20
- }
21
-
22
- /**
23
- * IPFS gateway fetch result
24
- */
25
- export interface FetchResult {
26
- data: Buffer;
27
- size: number;
28
- }
29
-
30
- /**
31
- * HTTP request options
32
- */
33
- interface RequestOptions {
34
- method: string;
35
- headers?: Record<string, string>;
36
- body?: Buffer | string;
37
- timeout?: number;
38
- }
39
-
40
- /**
41
- * Make an HTTP/HTTPS request
42
- *
43
- * @param url - The URL to request
44
- * @param options - Request options
45
- * @returns Response body buffer
46
- */
47
- async function httpRequest(url: string, options: RequestOptions): Promise<Buffer> {
48
- return new Promise((resolve, reject) => {
49
- const parsedUrl = new URL(url);
50
- const isHttps = parsedUrl.protocol === 'https:';
51
- const lib = isHttps ? https : http;
52
-
53
- const reqOptions: https.RequestOptions = {
54
- hostname: parsedUrl.hostname,
55
- port: parsedUrl.port || (isHttps ? 443 : 80),
56
- path: parsedUrl.pathname + parsedUrl.search,
57
- method: options.method,
58
- headers: options.headers || {},
59
- timeout: options.timeout || 30000,
60
- };
61
-
62
- const req = lib.request(reqOptions, (res) => {
63
- const chunks: Buffer[] = [];
64
-
65
- res.on('data', (chunk: Buffer) => {
66
- chunks.push(chunk);
67
- });
68
-
69
- res.on('end', () => {
70
- const body = Buffer.concat(chunks);
71
-
72
- if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
73
- resolve(body);
74
- } else {
75
- reject(
76
- new Error(
77
- `HTTP ${res.statusCode}: ${res.statusMessage} - ${body.toString()}`,
78
- ),
79
- );
80
- }
81
- });
82
- });
83
-
84
- req.on('error', reject);
85
- req.on('timeout', () => {
86
- req.destroy();
87
- reject(new Error('Request timeout'));
88
- });
89
-
90
- if (options.body) {
91
- req.write(options.body);
92
- }
93
-
94
- req.end();
95
- });
96
- }
97
-
98
- /**
99
- * Pin a file to IPFS using the configured pinning service
100
- *
101
- * @param data - The file data to pin
102
- * @param name - Optional file name for metadata
103
- * @returns The IPFS CID
104
- */
105
- export async function pinToIPFS(data: Buffer, name?: string): Promise<PinResult> {
106
- try {
107
- const config = loadConfig();
108
- const endpoint = config.ipfsPinningEndpoint;
109
-
110
- if (!endpoint) {
111
- throw new Error(
112
- 'IPFS pinning endpoint not configured. Run `opnet config set ipfsPinningEndpoint <url>`',
113
- );
114
- }
115
-
116
- // Build multipart form data
117
- const boundary = '----FormBoundary' + Math.random().toString(36).substring(2);
118
- const fileName = name || 'plugin.opnet';
119
-
120
- const formParts: Buffer[] = [];
121
-
122
- // File part
123
- formParts.push(
124
- Buffer.from(
125
- `--${boundary}\r\n` +
126
- `Content-Disposition: form-data; name="file"; filename="${fileName}"\r\n` +
127
- `Content-Type: application/octet-stream\r\n\r\n`,
128
- ),
129
- );
130
- formParts.push(data);
131
- formParts.push(Buffer.from('\r\n'));
132
-
133
- // End boundary
134
- formParts.push(Buffer.from(`--${boundary}--\r\n`));
135
-
136
- const body = Buffer.concat(formParts);
137
-
138
- // Build headers
139
- const headers: Record<string, string> = {
140
- 'Content-Type': `multipart/form-data; boundary=${boundary}`,
141
- 'Content-Length': body.length.toString(),
142
- };
143
-
144
- // Add authorization if configured
145
- if (config.ipfsPinningAuthHeader) {
146
- const [headerName, headerValue] = config.ipfsPinningAuthHeader
147
- .split(':')
148
- .map((s) => s.trim());
149
- if (headerName && headerValue) {
150
- headers[headerName] = headerValue;
151
- }
152
- } else if (config.ipfsPinningApiKey) {
153
- headers['Authorization'] = `Bearer ${config.ipfsPinningApiKey}`;
154
- }
155
-
156
- // Detect pinning service type from URL and adjust request
157
- const url = new URL(endpoint);
158
-
159
- let requestUrl: string;
160
- if (url.hostname.includes('ipfs.opnet.org')) {
161
- // OPNet IPFS gateway - uses standard IPFS API
162
- requestUrl = endpoint;
163
- } else if (url.hostname.includes('pinata')) {
164
- // Pinata-specific endpoint
165
- requestUrl = 'https://api.pinata.cloud/pinning/pinFileToIPFS';
166
- // Only set pinata_api_key header if using API key (not JWT)
167
- // JWT tokens start with "eyJ", API keys don't
168
- if (config.ipfsPinningApiKey && !config.ipfsPinningApiKey.startsWith('eyJ')) {
169
- headers['pinata_api_key'] = config.ipfsPinningApiKey;
170
- if (config.ipfsPinningSecret) {
171
- headers['pinata_secret_api_key'] = config.ipfsPinningSecret;
172
- }
173
- }
174
- } else if (url.hostname.includes('web3.storage') || url.hostname.includes('w3s.link')) {
175
- // web3.storage endpoint
176
- requestUrl = endpoint.endsWith('/') ? endpoint + 'upload' : endpoint + '/upload';
177
- } else if (url.hostname.includes('nft.storage')) {
178
- // nft.storage endpoint
179
- requestUrl = 'https://api.nft.storage/upload';
180
- } else if (url.pathname.includes('/api/v0/')) {
181
- // Standard IPFS API endpoint
182
- requestUrl = endpoint;
183
- } else {
184
- // Generic IPFS pinning service (assumed to follow IPFS Pinning Services API)
185
- requestUrl = endpoint.endsWith('/') ? endpoint + 'pins' : endpoint + '/pins';
186
- }
187
-
188
- const response = await httpRequest(requestUrl, {
189
- method: 'POST',
190
- headers,
191
- body,
192
- timeout: 120000, // 2 minutes for upload
193
- });
194
-
195
- // Parse response to extract CID
196
- const result = JSON.parse(response.toString()) as Record<string, unknown>;
197
-
198
- // Handle different response formats
199
- let cid: string | undefined;
200
-
201
- if (typeof result.IpfsHash === 'string') {
202
- // Pinata format
203
- cid = result.IpfsHash;
204
- } else if (typeof result.cid === 'string') {
205
- // web3.storage / nft.storage format
206
- cid = result.cid;
207
- } else if (typeof result.Hash === 'string') {
208
- // IPFS API format
209
- cid = result.Hash;
210
- } else if (
211
- result.value &&
212
- typeof (result.value as Record<string, unknown>).cid === 'string'
213
- ) {
214
- // NFT.storage wrapped format
215
- cid = (result.value as Record<string, unknown>).cid as string;
216
- }
217
-
218
- if (!cid) {
219
- throw new Error(
220
- `Failed to extract CID from pinning response: ${JSON.stringify(result)}`,
221
- );
222
- }
223
-
224
- return {
225
- cid,
226
- size: data.length,
227
- };
228
- } catch (e) {
229
- throw new Error(`IPFS pinning failed: ${e instanceof Error ? e.message : String(e)}`);
230
- }
231
- }
232
-
233
- /**
234
- * Fetch a file from IPFS using configured gateways
235
- *
236
- * @param cid - The IPFS CID
237
- * @returns The file data
238
- */
239
- export async function fetchFromIPFS(cid: string): Promise<FetchResult> {
240
- const config = loadConfig();
241
- const gateways = config.ipfsGateways.length > 0 ? config.ipfsGateways : [config.ipfsGateway];
242
-
243
- let lastError: Error | undefined;
244
-
245
- for (const gateway of gateways) {
246
- try {
247
- const url = buildGatewayUrl(gateway, cid);
248
- const data = await httpRequest(url, {
249
- method: 'GET',
250
- timeout: 60000, // 1 minute
251
- });
252
-
253
- return {
254
- data,
255
- size: data.length,
256
- };
257
- } catch (error) {
258
- lastError = error instanceof Error ? error : new Error(String(error));
259
- // Try next gateway
260
- }
261
- }
262
-
263
- throw new Error(`Failed to fetch from all gateways: ${lastError?.message}`);
264
- }
265
-
266
- /**
267
- * Build a gateway URL for a CID
268
- *
269
- * @param gateway - The gateway base URL
270
- * @param cid - The IPFS CID
271
- * @returns Full URL
272
- */
273
- export function buildGatewayUrl(gateway: string, cid: string): string {
274
- // Remove trailing slash
275
- const base = gateway.replace(/\/$/, '');
276
-
277
- // Handle different gateway URL patterns
278
- if (base.includes('{cid}')) {
279
- // Template URL
280
- return base.replace('{cid}', cid);
281
- } else if (base.includes('/ipfs/')) {
282
- // Path-style gateway
283
- return `${base}${cid}`;
284
- } else {
285
- // Standard gateway
286
- return `${base}/ipfs/${cid}`;
287
- }
288
- }
289
-
290
- /**
291
- * Validate an IPFS CID
292
- *
293
- * @param cid - The CID to validate
294
- * @returns True if valid CID format
295
- */
296
- export function isValidCid(cid: string): boolean {
297
- // CIDv0 (Qm...) or CIDv1 (ba...)
298
- if (cid.startsWith('Qm') && cid.length === 46) {
299
- // CIDv0 base58btc
300
- return /^Qm[1-9A-HJ-NP-Za-km-z]{44}$/.test(cid);
301
- } else if (cid.startsWith('ba')) {
302
- // CIDv1 base32
303
- return /^ba[a-z2-7]{57,}$/.test(cid);
304
- } else if (cid.startsWith('b')) {
305
- // Other CIDv1 bases
306
- return cid.length >= 50;
307
- }
308
-
309
- return false;
310
- }
311
-
312
- /**
313
- * Download a plugin binary from IPFS and save to file
314
- *
315
- * @param cid - The IPFS CID
316
- * @param outputPath - Path to save the file
317
- * @returns The downloaded file size
318
- */
319
- export async function downloadPlugin(cid: string, outputPath: string): Promise<number> {
320
- const result = await fetchFromIPFS(cid);
321
- fs.writeFileSync(outputPath, result.data);
322
- return result.size;
323
- }
324
-
325
- /**
326
- * Upload a plugin binary file to IPFS
327
- *
328
- * @param filePath - Path to the plugin file
329
- * @returns The IPFS CID
330
- */
331
- export async function uploadPlugin(filePath: string): Promise<PinResult> {
332
- const data = fs.readFileSync(filePath);
333
- const fileName = filePath.split('/').pop() || 'plugin.opnet';
334
- return pinToIPFS(data, fileName);
335
- }
336
-
337
- /**
338
- * Check if a CID is available on any gateway
339
- *
340
- * @param cid - The IPFS CID
341
- * @returns True if the file is accessible
342
- */
343
- export async function checkAvailability(cid: string): Promise<boolean> {
344
- try {
345
- await fetchFromIPFS(cid);
346
- return true;
347
- } catch {
348
- return false;
349
- }
350
- }
351
-
352
- /**
353
- * Get IPFS gateway status
354
- *
355
- * @returns Object with gateway availability status
356
- */
357
- export async function getGatewayStatus(): Promise<Record<string, boolean>> {
358
- const config = loadConfig();
359
- const gateways = config.ipfsGateways.length > 0 ? config.ipfsGateways : [config.ipfsGateway];
360
-
361
- // Use a well-known CID for testing (empty directory)
362
- const testCid = 'QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn';
363
-
364
- const status: Record<string, boolean> = {};
365
-
366
- await Promise.all(
367
- gateways.map(async (gateway) => {
368
- try {
369
- const url = buildGatewayUrl(gateway, testCid);
370
- await httpRequest(url, {
371
- method: 'HEAD',
372
- timeout: 10000,
373
- });
374
- status[gateway] = true;
375
- } catch {
376
- status[gateway] = false;
377
- }
378
- }),
379
- );
380
-
381
- return status;
382
- }
@@ -1,195 +0,0 @@
1
- /**
2
- * Plugin manifest (plugin.json) utilities
3
- *
4
- * Uses @btc-vision/plugin-sdk for validation.
5
- *
6
- * @module lib/manifest
7
- */
8
-
9
- import * as fs from 'fs';
10
- import * as path from 'path';
11
- import {
12
- DEFAULT_LIFECYCLE,
13
- DEFAULT_PERMISSIONS,
14
- DEFAULT_RESOURCES,
15
- IPluginMetadata,
16
- IPluginPermissions,
17
- IValidationResult,
18
- PLUGIN_MANIFEST_FILENAME,
19
- PLUGIN_NAME_REGEX,
20
- validateManifest as sdkValidateManifest,
21
- } from '@btc-vision/plugin-sdk';
22
-
23
- /** Scoped package name pattern */
24
- const SCOPED_NAME_PATTERN = /^@[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/;
25
-
26
- /**
27
- * Validate a plugin name (scoped or unscoped)
28
- *
29
- * @param name - The name to validate
30
- * @returns Array of validation errors (empty if valid)
31
- */
32
- export function validatePluginName(name: string): string[] {
33
- const errors: string[] = [];
34
-
35
- if (!name) {
36
- errors.push('Name is required');
37
- return errors;
38
- }
39
-
40
- // Check if scoped
41
- if (name.startsWith('@')) {
42
- if (!SCOPED_NAME_PATTERN.test(name)) {
43
- errors.push(
44
- 'Scoped name must be @scope/name where scope and name are lowercase alphanumeric with hyphens, starting with a letter',
45
- );
46
- }
47
- } else {
48
- if (!PLUGIN_NAME_REGEX.test(name)) {
49
- errors.push('Name must be lowercase alphanumeric with hyphens, starting with a letter');
50
- }
51
- }
52
-
53
- // Check length
54
- if (name.length > 100) {
55
- errors.push('Name must be 100 characters or less');
56
- }
57
-
58
- return errors;
59
- }
60
-
61
- /**
62
- * Validate a complete plugin manifest using the SDK validator
63
- *
64
- * @param manifest - The manifest to validate
65
- * @returns Validation result with field-specific errors
66
- */
67
- export function validateManifest(manifest: Partial<IPluginMetadata>): IValidationResult {
68
- return sdkValidateManifest(manifest);
69
- }
70
-
71
- /**
72
- * Validate plugin permissions
73
- *
74
- * @param permissions - The permissions object
75
- * @returns Array of validation errors (empty if valid)
76
- */
77
- export function validatePermissions(permissions: IPluginPermissions): string[] {
78
- const errors: string[] = [];
79
-
80
- if (permissions.database?.enabled) {
81
- if (!permissions.database.collections || !Array.isArray(permissions.database.collections)) {
82
- errors.push('database.collections must be an array when database is enabled');
83
- }
84
- }
85
-
86
- return errors;
87
- }
88
-
89
- /**
90
- * Load and validate a plugin manifest from file
91
- *
92
- * Note: This performs basic validation suitable for source manifests.
93
- * The SDK's strict validation requires fields like 'checksum' which
94
- * are only computed during compilation, not in source plugin.json.
95
- *
96
- * @param manifestPath - Path to plugin.json
97
- * @returns The loaded manifest or throws with validation errors
98
- */
99
- export function loadManifest(manifestPath: string): IPluginMetadata {
100
- const resolvedPath = path.resolve(manifestPath);
101
-
102
- if (!fs.existsSync(resolvedPath)) {
103
- throw new Error(`Manifest not found: ${resolvedPath}`);
104
- }
105
-
106
- let manifest: Partial<IPluginMetadata>;
107
- try {
108
- const content = fs.readFileSync(resolvedPath, 'utf-8');
109
- manifest = JSON.parse(content) as Partial<IPluginMetadata>;
110
- } catch (e) {
111
- throw new Error(`Failed to parse manifest: ${e instanceof Error ? e.message : String(e)}`);
112
- }
113
-
114
- // Basic validation for source manifests (checksum is computed during compilation)
115
- const errors: string[] = [];
116
- if (!manifest.name || typeof manifest.name !== 'string') {
117
- errors.push('name is required');
118
- }
119
- if (!manifest.version || typeof manifest.version !== 'string') {
120
- errors.push('version is required');
121
- }
122
- if (!manifest.author || typeof manifest.author !== 'object') {
123
- errors.push('author is required');
124
- }
125
- if (!manifest.pluginType || !['standalone', 'library'].includes(manifest.pluginType)) {
126
- errors.push('pluginType must be "standalone" or "library"');
127
- }
128
-
129
- if (errors.length > 0) {
130
- throw new Error(`Invalid manifest:\n${errors.map((e) => ` - ${e}`).join('\n')}`);
131
- }
132
-
133
- // Set default checksum for compilation (will be computed)
134
- // Cast to mutable to allow setting checksum
135
- const result = manifest as { -readonly [K in keyof IPluginMetadata]: IPluginMetadata[K] };
136
- if (!result.checksum) {
137
- result.checksum = '';
138
- }
139
-
140
- return result as IPluginMetadata;
141
- }
142
-
143
- /**
144
- * Save a plugin manifest to file
145
- *
146
- * @param manifestPath - Path to save to
147
- * @param manifest - The manifest to save
148
- */
149
- export function saveManifest(manifestPath: string, manifest: IPluginMetadata): void {
150
- const content = JSON.stringify(manifest, null, 4);
151
- fs.writeFileSync(manifestPath, content, 'utf-8');
152
- }
153
-
154
- /**
155
- * Create a default plugin manifest
156
- *
157
- * @param options - Manifest options
158
- * @returns A complete manifest with defaults
159
- */
160
- export function createManifest(options: {
161
- name: string;
162
- author: string;
163
- email?: string;
164
- description?: string;
165
- pluginType: 'standalone' | 'library';
166
- }): Omit<IPluginMetadata, 'checksum'> {
167
- return {
168
- name: options.name,
169
- version: '1.0.0',
170
- opnetVersion: '>=0.0.1',
171
- main: 'dist/index.jsc',
172
- target: 'bytenode',
173
- type: 'plugin',
174
- author: {
175
- name: options.author,
176
- email: options.email,
177
- },
178
- description: options.description,
179
- pluginType: options.pluginType,
180
- permissions: DEFAULT_PERMISSIONS,
181
- resources: DEFAULT_RESOURCES,
182
- lifecycle: DEFAULT_LIFECYCLE,
183
- dependencies: {},
184
- };
185
- }
186
-
187
- /**
188
- * Get the manifest path for a directory
189
- *
190
- * @param dir - Directory to search
191
- * @returns Path to plugin.json
192
- */
193
- export function getManifestPath(dir: string = process.cwd()): string {
194
- return path.join(dir, PLUGIN_MANIFEST_FILENAME);
195
- }
@@ -1,121 +0,0 @@
1
- /**
2
- * JSONRpcProvider wrapper for OPNet CLI
3
- *
4
- * Provides a unified interface for blockchain interaction using the opnet package.
5
- *
6
- * @module lib/provider
7
- */
8
-
9
- import { JSONRpcProvider } from 'opnet';
10
-
11
- import { NetworkName } from '../types/index.js';
12
- import { getRegistryAddress, getRpcUrl, loadConfig } from './config.js';
13
- import { getNetwork } from './wallet.js';
14
-
15
- /** Provider timeout in milliseconds */
16
- const DEFAULT_TIMEOUT = 30000;
17
-
18
- /**
19
- * Provider instance cache
20
- */
21
- const providerCache = new Map<string, JSONRpcProvider>();
22
-
23
- /**
24
- * Get a JSONRpcProvider for a network
25
- *
26
- * @param network - Network name (defaults to configured default)
27
- * @returns JSONRpcProvider instance
28
- */
29
- export function getProvider(network?: NetworkName): JSONRpcProvider {
30
- const config = loadConfig();
31
- const targetNetwork = network || config.defaultNetwork;
32
- const rpcUrl = getRpcUrl(targetNetwork);
33
- const cacheKey = `${targetNetwork}:${rpcUrl}`;
34
-
35
- // Return cached provider if available
36
- const cached = providerCache.get(cacheKey);
37
- if (cached) {
38
- return cached;
39
- }
40
-
41
- // Create new provider
42
- const bitcoinNetwork = getNetwork(targetNetwork);
43
- const provider = new JSONRpcProvider(rpcUrl, bitcoinNetwork, DEFAULT_TIMEOUT);
44
-
45
- providerCache.set(cacheKey, provider);
46
- return provider;
47
- }
48
-
49
- /**
50
- * Clear provider cache (useful for testing or network changes)
51
- */
52
- export function clearProviderCache(): void {
53
- providerCache.clear();
54
- }
55
-
56
- /**
57
- * Get the registry contract address for a network
58
- *
59
- * @param network - Network name (defaults to configured default)
60
- * @returns The registry contract address
61
- */
62
- export function getRegistryContractAddress(network?: NetworkName): string {
63
- return getRegistryAddress(network);
64
- }
65
-
66
- /**
67
- * Check if the provider can connect to the RPC endpoint
68
- *
69
- * @param network - Network name (defaults to configured default)
70
- * @returns True if connection successful
71
- */
72
- export async function checkConnection(network?: NetworkName): Promise<boolean> {
73
- try {
74
- const provider = getProvider(network);
75
- // Try to get the current block to verify connection
76
- await provider.getBlockNumber();
77
- return true;
78
- } catch {
79
- return false;
80
- }
81
- }
82
-
83
- /**
84
- * Get the current block number
85
- *
86
- * @param network - Network name (defaults to configured default)
87
- * @returns Current block number
88
- */
89
- export async function getBlockNumber(network?: NetworkName): Promise<bigint> {
90
- const provider = getProvider(network);
91
- return provider.getBlockNumber();
92
- }
93
-
94
- /**
95
- * Get the balance for an address
96
- *
97
- * @param address - The address to check
98
- * @param network - Network name (defaults to configured default)
99
- * @returns Balance in satoshis
100
- */
101
- export async function getBalance(address: string, network?: NetworkName): Promise<bigint> {
102
- const provider = getProvider(network);
103
- return provider.getBalance(address);
104
- }
105
-
106
- /**
107
- * Broadcast a signed transaction
108
- *
109
- * @param rawTx - The raw transaction hex
110
- * @param network - Network name (defaults to configured default)
111
- * @returns Transaction hash
112
- */
113
- export async function broadcastTransaction(
114
- rawTx: string,
115
- network?: NetworkName,
116
- isPsbt: boolean = false,
117
- ): Promise<string> {
118
- const provider = getProvider(network);
119
- const result = await provider.sendRawTransaction(rawTx, isPsbt);
120
- return result.result ?? '';
121
- }