@offckb/cli 0.4.8 → 0.4.9-canary-2b6b3af.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/build/index.js +1553 -202
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -235,16 +235,23 @@ exports.defaultSettings = {
|
|
|
235
235
|
transactionsPath: path.resolve(exports.dataPath, 'mainnet/transactions'),
|
|
236
236
|
},
|
|
237
237
|
tools: {
|
|
238
|
+
rootFolder: path.resolve(exports.dataPath, 'tools'),
|
|
238
239
|
ckbDebugger: {
|
|
239
240
|
minVersion: '0.200.0',
|
|
240
241
|
},
|
|
242
|
+
ckbTui: {
|
|
243
|
+
version: 'v0.1.3',
|
|
244
|
+
},
|
|
241
245
|
},
|
|
242
246
|
};
|
|
243
247
|
function readSettings() {
|
|
244
248
|
try {
|
|
245
249
|
if (fs.existsSync(exports.configPath)) {
|
|
246
250
|
const data = fs.readFileSync(exports.configPath, 'utf8');
|
|
247
|
-
|
|
251
|
+
const parsed = JSON.parse(data);
|
|
252
|
+
validateSettings(parsed);
|
|
253
|
+
// Deep-clone defaults before merging to prevent mutation of the shared default
|
|
254
|
+
return deepMerge(deepClone(exports.defaultSettings), parsed);
|
|
248
255
|
}
|
|
249
256
|
else {
|
|
250
257
|
return exports.defaultSettings;
|
|
@@ -274,10 +281,26 @@ function getCKBBinaryPath(version) {
|
|
|
274
281
|
const binaryName = platform === 'win32' ? 'ckb.exe' : 'ckb';
|
|
275
282
|
return path.join(getCKBBinaryInstallPath(version), binaryName);
|
|
276
283
|
}
|
|
284
|
+
function deepClone(obj) {
|
|
285
|
+
if (obj === null || typeof obj !== 'object') {
|
|
286
|
+
return obj;
|
|
287
|
+
}
|
|
288
|
+
if (Array.isArray(obj)) {
|
|
289
|
+
return obj.map(deepClone);
|
|
290
|
+
}
|
|
291
|
+
const clone = {};
|
|
292
|
+
for (const key in obj) {
|
|
293
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
294
|
+
clone[key] = deepClone(obj[key]);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return clone;
|
|
298
|
+
}
|
|
299
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
277
300
|
function deepMerge(target, source) {
|
|
278
301
|
for (const key in source) {
|
|
279
|
-
if (source[key] && typeof source[key] === 'object') {
|
|
280
|
-
if (!target[key]) {
|
|
302
|
+
if (source[key] !== null && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
303
|
+
if (!target[key] || typeof target[key] !== 'object') {
|
|
281
304
|
target[key] = {};
|
|
282
305
|
}
|
|
283
306
|
deepMerge(target[key], source[key]);
|
|
@@ -288,6 +311,29 @@ function deepMerge(target, source) {
|
|
|
288
311
|
}
|
|
289
312
|
return target;
|
|
290
313
|
}
|
|
314
|
+
function validateSettings(raw) {
|
|
315
|
+
if (!raw || typeof raw !== 'object') {
|
|
316
|
+
throw new Error('Settings must be a JSON object');
|
|
317
|
+
}
|
|
318
|
+
const obj = raw;
|
|
319
|
+
if (obj.tools && typeof obj.tools === 'object') {
|
|
320
|
+
const tools = obj.tools;
|
|
321
|
+
if (tools.rootFolder !== undefined && typeof tools.rootFolder !== 'string') {
|
|
322
|
+
throw new Error('tools.rootFolder must be a string path');
|
|
323
|
+
}
|
|
324
|
+
if (tools.ckbTui && typeof tools.ckbTui === 'object') {
|
|
325
|
+
const ckbTui = tools.ckbTui;
|
|
326
|
+
if (ckbTui.version !== undefined && typeof ckbTui.version !== 'string') {
|
|
327
|
+
throw new Error('tools.ckbTui.version must be a string');
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (obj.proxy !== undefined && obj.proxy !== null) {
|
|
332
|
+
if (typeof obj.proxy !== 'object') {
|
|
333
|
+
throw new Error('proxy must be an object');
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
291
337
|
|
|
292
338
|
|
|
293
339
|
/***/ }),
|
|
@@ -316,6 +362,7 @@ const deposit_1 = __nccwpck_require__(48598);
|
|
|
316
362
|
const deploy_1 = __nccwpck_require__(79617);
|
|
317
363
|
const transfer_1 = __nccwpck_require__(40265);
|
|
318
364
|
const balance_1 = __nccwpck_require__(77640);
|
|
365
|
+
const udt_1 = __nccwpck_require__(50703);
|
|
319
366
|
const create_1 = __nccwpck_require__(51534);
|
|
320
367
|
const config_1 = __nccwpck_require__(93004);
|
|
321
368
|
const devnet_config_1 = __nccwpck_require__(10015);
|
|
@@ -325,20 +372,34 @@ const transfer_all_1 = __nccwpck_require__(92039);
|
|
|
325
372
|
const gen_1 = __nccwpck_require__(750);
|
|
326
373
|
const ckb_debugger_1 = __nccwpck_require__(14815);
|
|
327
374
|
const logger_1 = __nccwpck_require__(65370);
|
|
375
|
+
const status_1 = __nccwpck_require__(71420);
|
|
376
|
+
const validator_1 = __nccwpck_require__(39534);
|
|
328
377
|
const version = (__nccwpck_require__(8330)/* .version */ .rE);
|
|
329
378
|
const description = (__nccwpck_require__(8330)/* .description */ .h_);
|
|
330
379
|
// fix windows terminal encoding of simplified chinese text
|
|
331
380
|
(0, encoding_1.setUTF8EncodingForWindows)();
|
|
332
381
|
const program = new commander_1.Command();
|
|
333
382
|
program.name('offckb').description(description).version(version).enablePositionalOptions();
|
|
334
|
-
program
|
|
383
|
+
program.option('--json', 'Output logs in JSON format for agent/programmatic consumption');
|
|
384
|
+
program.hook('preAction', (thisCommand) => {
|
|
385
|
+
const opts = thisCommand.opts();
|
|
386
|
+
if (opts.json) {
|
|
387
|
+
logger_1.logger.setJsonMode(true);
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
const nodeCommand = program
|
|
335
391
|
.command('node [CKB-Version]')
|
|
336
392
|
.description('Use the CKB to start devnet')
|
|
337
393
|
.option('--network <network>', 'Specify the network to deploy to', 'devnet')
|
|
338
394
|
.option('-b, --binary-path <binaryPath>', 'Specify the CKB binary path to use, only for devnet, when set, will ignore version and network')
|
|
395
|
+
.option('--daemon', 'Run the node in the background as a daemon (devnet only)')
|
|
339
396
|
.action((version, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
340
|
-
return (0, node_1.startNode)({ version, network: options.network, binaryPath: options.binaryPath });
|
|
397
|
+
return (0, node_1.startNode)({ version, network: options.network, binaryPath: options.binaryPath, daemon: options.daemon });
|
|
341
398
|
}));
|
|
399
|
+
nodeCommand
|
|
400
|
+
.command('stop')
|
|
401
|
+
.description('Stop the running CKB devnet daemon')
|
|
402
|
+
.action(() => __awaiter(void 0, void 0, void 0, function* () { return (0, node_1.stopNode)(); }));
|
|
342
403
|
program
|
|
343
404
|
.command('create [project-name]')
|
|
344
405
|
.description('Create a new CKB Smart Contract project in JavaScript.')
|
|
@@ -412,13 +473,15 @@ program
|
|
|
412
473
|
return (0, deposit_1.deposit)(toAddress, amountInCKB, options);
|
|
413
474
|
}));
|
|
414
475
|
program
|
|
415
|
-
.command('transfer [toAddress] [
|
|
416
|
-
.description('Transfer CKB tokens to address, only devnet and testnet')
|
|
476
|
+
.command('transfer [toAddress] [amount]')
|
|
477
|
+
.description('Transfer CKB or UDT tokens to address, only devnet and testnet')
|
|
417
478
|
.option('--network <network>', 'Specify the network to transfer to', 'devnet')
|
|
418
|
-
.option('--privkey <privkey>', 'Specify the private key to transfer
|
|
479
|
+
.option('--privkey <privkey>', 'Specify the private key to transfer')
|
|
480
|
+
.addOption(new commander_1.Option('--udt-kind <kind>', 'Specify the UDT kind').choices(['sudt', 'xudt']).default('sudt'))
|
|
481
|
+
.option('--udt-type-args <typeArgs>', 'Specify the UDT type script args to transfer UDT')
|
|
419
482
|
.option('-r, --proxy-rpc', 'Use Proxy RPC to connect to blockchain')
|
|
420
|
-
.action((toAddress,
|
|
421
|
-
return (0, transfer_1.transfer)(toAddress,
|
|
483
|
+
.action((toAddress, amount, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
484
|
+
return (0, transfer_1.transfer)(toAddress, amount, options);
|
|
422
485
|
}));
|
|
423
486
|
program
|
|
424
487
|
.command('transfer-all [toAddress]')
|
|
@@ -431,11 +494,36 @@ program
|
|
|
431
494
|
}));
|
|
432
495
|
program
|
|
433
496
|
.command('balance [toAddress]')
|
|
434
|
-
.description('Check account balance, only devnet and testnet')
|
|
497
|
+
.description('Check account balance (CKB + detected SUDT/xUDT), only devnet and testnet')
|
|
435
498
|
.option('--network <network>', 'Specify the network to check', 'devnet')
|
|
499
|
+
.addOption(new commander_1.Option('--udt-kind <kind>', 'Filter by UDT kind').choices(['sudt', 'xudt']))
|
|
500
|
+
.option('--udt-type-args <typeArgs>', 'Filter by UDT type script args')
|
|
501
|
+
.option('--no-udt', 'Skip UDT balance scan')
|
|
436
502
|
.action((toAddress, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
437
503
|
return (0, balance_1.balanceOf)(toAddress, options);
|
|
438
504
|
}));
|
|
505
|
+
const udtCommand = program.command('udt').description('UDT token commands');
|
|
506
|
+
udtCommand
|
|
507
|
+
.command('issue <amount>')
|
|
508
|
+
.description('Issue new UDT tokens, only devnet and testnet')
|
|
509
|
+
.option('--network <network>', 'Specify the network', 'devnet')
|
|
510
|
+
.addOption(new commander_1.Option('--udt-kind <kind>', 'Specify the UDT kind').choices(['sudt', 'xudt']).default('sudt'))
|
|
511
|
+
.option('--type-args <typeArgs>', 'Specify the UDT type script args (xudt only; defaults to signer lock hash)')
|
|
512
|
+
.option('--to <toAddress>', 'Specify the receiver address (defaults to signer)')
|
|
513
|
+
.option('--privkey <privkey>', 'Specify the private key to issue UDT')
|
|
514
|
+
.action((amount, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
515
|
+
return (0, udt_1.udtIssue)(amount, options);
|
|
516
|
+
}));
|
|
517
|
+
udtCommand
|
|
518
|
+
.command('destroy <amount>')
|
|
519
|
+
.description('Destroy UDT tokens, only devnet and testnet')
|
|
520
|
+
.option('--network <network>', 'Specify the network', 'devnet')
|
|
521
|
+
.addOption(new commander_1.Option('--udt-kind <kind>', 'Specify the UDT kind').choices(['sudt', 'xudt']).default('sudt'))
|
|
522
|
+
.requiredOption('--type-args <typeArgs>', 'Specify the UDT type script args')
|
|
523
|
+
.option('--privkey <privkey>', 'Specify the private key to destroy UDT')
|
|
524
|
+
.action((amount, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
525
|
+
return (0, udt_1.udtDestroy)(amount, options);
|
|
526
|
+
}));
|
|
439
527
|
program
|
|
440
528
|
.command('debugger')
|
|
441
529
|
.description('Port of the raw CKB Standalone Debugger')
|
|
@@ -445,6 +533,14 @@ program
|
|
|
445
533
|
.action(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
446
534
|
return ckb_debugger_1.CKBDebugger.runWithArgs(process.argv.slice(2));
|
|
447
535
|
}));
|
|
536
|
+
program
|
|
537
|
+
.command('status')
|
|
538
|
+
.description('Show ckb-tui status interface')
|
|
539
|
+
.option('--network <network>', 'Specify the network whose node status to monitor', 'devnet')
|
|
540
|
+
.action((option) => __awaiter(void 0, void 0, void 0, function* () {
|
|
541
|
+
(0, validator_1.validateNetworkOpt)(option.network);
|
|
542
|
+
return yield (0, status_1.status)({ network: option.network });
|
|
543
|
+
}));
|
|
448
544
|
program
|
|
449
545
|
.command('config <action> [item] [value]')
|
|
450
546
|
.description('do a configuration action')
|
|
@@ -534,11 +630,31 @@ function balanceOf(address_1) {
|
|
|
534
630
|
const network = opt.network;
|
|
535
631
|
(0, validator_1.validateNetworkOpt)(network);
|
|
536
632
|
const ckb = new ckb_1.CKB({ network });
|
|
537
|
-
const balanceInCKB = yield
|
|
538
|
-
|
|
633
|
+
const [balanceInCKB, udtBalances] = yield Promise.all([
|
|
634
|
+
ckb.balance(address),
|
|
635
|
+
opt.udt !== false ? ckb.detectUdtBalances(address) : Promise.resolve([]),
|
|
636
|
+
]);
|
|
637
|
+
logger_1.logger.info(`CKB: ${balanceInCKB}`);
|
|
638
|
+
const filtered = filterUdtBalances(udtBalances, opt);
|
|
639
|
+
if (filtered.length > 0) {
|
|
640
|
+
logger_1.logger.info('UDT:');
|
|
641
|
+
for (const udt of filtered) {
|
|
642
|
+
logger_1.logger.info(` ${udt.kind} (args=${udt.args}): ${udt.balance}`);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
539
645
|
process.exit(0);
|
|
540
646
|
});
|
|
541
647
|
}
|
|
648
|
+
function filterUdtBalances(balances, opt) {
|
|
649
|
+
if (!opt.udtKind && !opt.udtTypeArgs) {
|
|
650
|
+
return balances;
|
|
651
|
+
}
|
|
652
|
+
return balances.filter((udt) => {
|
|
653
|
+
const kindMatch = opt.udtKind ? udt.kind === opt.udtKind : true;
|
|
654
|
+
const argsMatch = opt.udtTypeArgs ? udt.args === opt.udtTypeArgs : true;
|
|
655
|
+
return kindMatch && argsMatch;
|
|
656
|
+
});
|
|
657
|
+
}
|
|
542
658
|
|
|
543
659
|
|
|
544
660
|
/***/ }),
|
|
@@ -1400,6 +1516,39 @@ function devnetConfig() {
|
|
|
1400
1516
|
|
|
1401
1517
|
"use strict";
|
|
1402
1518
|
|
|
1519
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
1520
|
+
if (k2 === undefined) k2 = k;
|
|
1521
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
1522
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
1523
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
1524
|
+
}
|
|
1525
|
+
Object.defineProperty(o, k2, desc);
|
|
1526
|
+
}) : (function(o, m, k, k2) {
|
|
1527
|
+
if (k2 === undefined) k2 = k;
|
|
1528
|
+
o[k2] = m[k];
|
|
1529
|
+
}));
|
|
1530
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
1531
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
1532
|
+
}) : function(o, v) {
|
|
1533
|
+
o["default"] = v;
|
|
1534
|
+
});
|
|
1535
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
1536
|
+
var ownKeys = function(o) {
|
|
1537
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
1538
|
+
var ar = [];
|
|
1539
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
1540
|
+
return ar;
|
|
1541
|
+
};
|
|
1542
|
+
return ownKeys(o);
|
|
1543
|
+
};
|
|
1544
|
+
return function (mod) {
|
|
1545
|
+
if (mod && mod.__esModule) return mod;
|
|
1546
|
+
var result = {};
|
|
1547
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
1548
|
+
__setModuleDefault(result, mod);
|
|
1549
|
+
return result;
|
|
1550
|
+
};
|
|
1551
|
+
})();
|
|
1403
1552
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
1404
1553
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
1405
1554
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -1412,9 +1561,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
1412
1561
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
1413
1562
|
exports.startNode = startNode;
|
|
1414
1563
|
exports.nodeDevnet = nodeDevnet;
|
|
1564
|
+
exports.stopNode = stopNode;
|
|
1415
1565
|
exports.nodeTestnet = nodeTestnet;
|
|
1416
1566
|
exports.nodeMainnet = nodeMainnet;
|
|
1417
1567
|
const child_process_1 = __nccwpck_require__(35317);
|
|
1568
|
+
const fs = __importStar(__nccwpck_require__(79896));
|
|
1569
|
+
const path = __importStar(__nccwpck_require__(16928));
|
|
1418
1570
|
const init_chain_1 = __nccwpck_require__(1360);
|
|
1419
1571
|
const install_1 = __nccwpck_require__(65611);
|
|
1420
1572
|
const setting_1 = __nccwpck_require__(25546);
|
|
@@ -1422,13 +1574,20 @@ const encoding_1 = __nccwpck_require__(6851);
|
|
|
1422
1574
|
const rpc_proxy_1 = __nccwpck_require__(46589);
|
|
1423
1575
|
const base_1 = __nccwpck_require__(69951);
|
|
1424
1576
|
const logger_1 = __nccwpck_require__(65370);
|
|
1425
|
-
|
|
1577
|
+
const DAEMON_LOG_DIR = 'logs';
|
|
1578
|
+
const DAEMON_LOG_FILE = 'daemon.log';
|
|
1579
|
+
const DAEMON_PID_FILE = 'daemon.pid';
|
|
1580
|
+
const DAEMON_CHILD_ENV = 'OFFCKB_DAEMON_CHILD';
|
|
1581
|
+
function startNode({ version, network = base_1.Network.devnet, binaryPath, daemon }) {
|
|
1426
1582
|
if (binaryPath && network !== base_1.Network.devnet) {
|
|
1427
1583
|
logger_1.logger.warn('Custom binaryPath is only supported for devnet. The provided binaryPath will be ignored.');
|
|
1428
1584
|
}
|
|
1585
|
+
if (daemon && network !== base_1.Network.devnet) {
|
|
1586
|
+
logger_1.logger.warn('Daemon mode is only supported for devnet. The daemon flag will be ignored.');
|
|
1587
|
+
}
|
|
1429
1588
|
switch (network) {
|
|
1430
1589
|
case base_1.Network.devnet:
|
|
1431
|
-
return nodeDevnet({ version, binaryPath });
|
|
1590
|
+
return nodeDevnet({ version, binaryPath, daemon });
|
|
1432
1591
|
case base_1.Network.testnet:
|
|
1433
1592
|
return nodeTestnet();
|
|
1434
1593
|
case base_1.Network.mainnet:
|
|
@@ -1438,8 +1597,11 @@ function startNode({ version, network = base_1.Network.devnet, binaryPath }) {
|
|
|
1438
1597
|
}
|
|
1439
1598
|
}
|
|
1440
1599
|
function nodeDevnet(_a) {
|
|
1441
|
-
return __awaiter(this, arguments, void 0, function* ({ version, binaryPath }) {
|
|
1600
|
+
return __awaiter(this, arguments, void 0, function* ({ version, binaryPath, daemon }) {
|
|
1442
1601
|
var _b, _c;
|
|
1602
|
+
if (daemon) {
|
|
1603
|
+
return startDaemon();
|
|
1604
|
+
}
|
|
1443
1605
|
const settings = (0, setting_1.readSettings)();
|
|
1444
1606
|
const ckbVersion = version || settings.bins.defaultCKBVersion;
|
|
1445
1607
|
let ckbBinPath = '';
|
|
@@ -1494,6 +1656,314 @@ function nodeDevnet(_a) {
|
|
|
1494
1656
|
}
|
|
1495
1657
|
});
|
|
1496
1658
|
}
|
|
1659
|
+
function resolveDaemonPaths() {
|
|
1660
|
+
const settings = (0, setting_1.readSettings)();
|
|
1661
|
+
const logDir = path.join(settings.devnet.dataPath, DAEMON_LOG_DIR);
|
|
1662
|
+
const logFile = path.join(logDir, DAEMON_LOG_FILE);
|
|
1663
|
+
const pidFile = path.join(logDir, DAEMON_PID_FILE);
|
|
1664
|
+
return { logDir, logFile, pidFile };
|
|
1665
|
+
}
|
|
1666
|
+
function readPidFile(pidFile) {
|
|
1667
|
+
var _a, _b;
|
|
1668
|
+
let raw;
|
|
1669
|
+
try {
|
|
1670
|
+
raw = fs.readFileSync(pidFile, 'utf8').trim();
|
|
1671
|
+
}
|
|
1672
|
+
catch (error) {
|
|
1673
|
+
// Treat a missing or unreadable PID file as "no daemon".
|
|
1674
|
+
return null;
|
|
1675
|
+
}
|
|
1676
|
+
if (!raw) {
|
|
1677
|
+
return null;
|
|
1678
|
+
}
|
|
1679
|
+
// Backward compatibility: plain integer PID written by older versions.
|
|
1680
|
+
const plainPid = Number(raw);
|
|
1681
|
+
if (Number.isInteger(plainPid) && plainPid > 0) {
|
|
1682
|
+
return { pid: plainPid, scriptPath: (_a = resolveCliEntry()) !== null && _a !== void 0 ? _a : '', startedAt: new Date(0).toISOString() };
|
|
1683
|
+
}
|
|
1684
|
+
try {
|
|
1685
|
+
const parsed = JSON.parse(raw);
|
|
1686
|
+
const pid = Number(parsed.pid);
|
|
1687
|
+
if (Number.isInteger(pid) && pid > 0 && typeof parsed.scriptPath === 'string') {
|
|
1688
|
+
return {
|
|
1689
|
+
pid,
|
|
1690
|
+
scriptPath: parsed.scriptPath,
|
|
1691
|
+
startedAt: (_b = parsed.startedAt) !== null && _b !== void 0 ? _b : new Date(0).toISOString(),
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
catch (_c) {
|
|
1696
|
+
// fall through to sentinel below
|
|
1697
|
+
}
|
|
1698
|
+
// Content exists but is neither a valid plain PID nor valid metadata.
|
|
1699
|
+
// Return a sentinel so stopNode can report an invalid PID and clean up.
|
|
1700
|
+
return { pid: NaN, scriptPath: '', startedAt: new Date(0).toISOString() };
|
|
1701
|
+
}
|
|
1702
|
+
function writePidFile(pidFile, metadata) {
|
|
1703
|
+
fs.writeFileSync(pidFile, JSON.stringify(metadata, null, 2));
|
|
1704
|
+
}
|
|
1705
|
+
function resolveCliEntry() {
|
|
1706
|
+
var _a;
|
|
1707
|
+
// In priority order. process.argv[1] is the most reliable for a Node CLI.
|
|
1708
|
+
// OFFCKB_CLI_PATH is an escape hatch for packaged/npx/weird environments.
|
|
1709
|
+
// require.main?.filename is a final fallback when argv is unavailable.
|
|
1710
|
+
const candidates = [process.env.OFFCKB_CLI_PATH, process.argv[1], (_a = require.main) === null || _a === void 0 ? void 0 : _a.filename].filter((c) => typeof c === 'string' && c.length > 0);
|
|
1711
|
+
for (const candidate of candidates) {
|
|
1712
|
+
try {
|
|
1713
|
+
const resolved = path.resolve(candidate);
|
|
1714
|
+
const stats = fs.statSync(resolved);
|
|
1715
|
+
if (stats.isFile()) {
|
|
1716
|
+
return resolved;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
catch (_b) {
|
|
1720
|
+
// Candidate is missing or not a file; try the next one.
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
return null;
|
|
1724
|
+
}
|
|
1725
|
+
function isProcessAlive(pid) {
|
|
1726
|
+
try {
|
|
1727
|
+
process.kill(pid, 0);
|
|
1728
|
+
return true;
|
|
1729
|
+
}
|
|
1730
|
+
catch (_a) {
|
|
1731
|
+
return false;
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
function cleanupPidFile(pidFile) {
|
|
1735
|
+
try {
|
|
1736
|
+
fs.unlinkSync(pidFile);
|
|
1737
|
+
}
|
|
1738
|
+
catch (error) {
|
|
1739
|
+
logger_1.logger.warn(`Failed to remove PID file ${pidFile}:`, error);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
function waitForProcessExit(pid, timeoutMs) {
|
|
1743
|
+
const start = Date.now();
|
|
1744
|
+
return new Promise((resolve) => {
|
|
1745
|
+
const check = () => {
|
|
1746
|
+
if (!isProcessAlive(pid)) {
|
|
1747
|
+
resolve(true);
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1750
|
+
if (Date.now() - start >= timeoutMs) {
|
|
1751
|
+
resolve(false);
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
setTimeout(check, 100);
|
|
1755
|
+
};
|
|
1756
|
+
check();
|
|
1757
|
+
});
|
|
1758
|
+
}
|
|
1759
|
+
function getProcessCommandLine(pid) {
|
|
1760
|
+
return new Promise((resolve) => {
|
|
1761
|
+
if (process.platform === 'win32') {
|
|
1762
|
+
(0, child_process_1.exec)(`wmic process where ProcessId=${pid} get CommandLine /format:list`, (error, stdout) => {
|
|
1763
|
+
if (error) {
|
|
1764
|
+
resolve(null);
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1767
|
+
const match = stdout.match(/CommandLine=(.+)/);
|
|
1768
|
+
resolve(match ? match[1].trim() : null);
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
else {
|
|
1772
|
+
(0, child_process_1.exec)(`ps -p ${pid} -o args=`, (error, stdout) => {
|
|
1773
|
+
if (error) {
|
|
1774
|
+
resolve(null);
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
resolve(stdout.trim());
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
function verifyDaemonIdentity(pid, metadata) {
|
|
1783
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1784
|
+
const cmdline = yield getProcessCommandLine(pid);
|
|
1785
|
+
if (!cmdline) {
|
|
1786
|
+
return false;
|
|
1787
|
+
}
|
|
1788
|
+
// The daemon child re-runs the same CLI entry point, so its command line
|
|
1789
|
+
// should reference the same script and should be a Node process.
|
|
1790
|
+
const scriptName = path.basename(metadata.scriptPath);
|
|
1791
|
+
const scriptDir = path.dirname(metadata.scriptPath);
|
|
1792
|
+
const looksLikeNode = cmdline.includes('node') || cmdline.includes('nodejs');
|
|
1793
|
+
const looksLikeOurScript = cmdline.includes(metadata.scriptPath) || (scriptName !== '' && cmdline.includes(scriptName));
|
|
1794
|
+
const looksLikeOffckb = cmdline.includes('offckb') || scriptDir.includes('offckb');
|
|
1795
|
+
return looksLikeNode && (looksLikeOurScript || looksLikeOffckb);
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
function terminateProcess(pid, signal) {
|
|
1799
|
+
return new Promise((resolve, reject) => {
|
|
1800
|
+
if (process.platform === 'win32') {
|
|
1801
|
+
// Windows has no POSIX signals and process.kill(pid) only terminates the
|
|
1802
|
+
// single process. Use taskkill to terminate the whole tree.
|
|
1803
|
+
// /T kills the process and all child processes.
|
|
1804
|
+
// /F forces termination when SIGKILL is requested.
|
|
1805
|
+
const args = signal === 'SIGKILL' ? ['/T', '/F', '/PID', String(pid)] : ['/T', '/PID', String(pid)];
|
|
1806
|
+
const taskkill = (0, child_process_1.spawn)('taskkill', args, { stdio: 'ignore' });
|
|
1807
|
+
taskkill.on('error', reject);
|
|
1808
|
+
taskkill.on('exit', () => {
|
|
1809
|
+
// taskkill may return non-zero if the process is already gone, which
|
|
1810
|
+
// is acceptable for our purposes.
|
|
1811
|
+
resolve();
|
|
1812
|
+
});
|
|
1813
|
+
return;
|
|
1814
|
+
}
|
|
1815
|
+
// On POSIX, detached: true makes the child a session/process group leader.
|
|
1816
|
+
// A negative pid sends the signal to the entire process group, ensuring
|
|
1817
|
+
// the CKB node, miner and RPC proxy all receive it.
|
|
1818
|
+
try {
|
|
1819
|
+
process.kill(-pid, signal);
|
|
1820
|
+
resolve();
|
|
1821
|
+
}
|
|
1822
|
+
catch (error) {
|
|
1823
|
+
reject(error);
|
|
1824
|
+
}
|
|
1825
|
+
});
|
|
1826
|
+
}
|
|
1827
|
+
function startDaemon() {
|
|
1828
|
+
const { logDir, logFile, pidFile } = resolveDaemonPaths();
|
|
1829
|
+
// Prevent duplicate daemon starts. If a daemon is already running, refuse
|
|
1830
|
+
// to overwrite its PID file.
|
|
1831
|
+
const existing = readPidFile(pidFile);
|
|
1832
|
+
if (existing && isProcessAlive(existing.pid)) {
|
|
1833
|
+
logger_1.logger.error(`A CKB devnet daemon is already running (PID ${existing.pid}). Stop it first with: offckb node stop`);
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
if (existing && !isProcessAlive(existing.pid)) {
|
|
1837
|
+
// Stale PID file from a crashed daemon; clean it up before starting anew.
|
|
1838
|
+
cleanupPidFile(pidFile);
|
|
1839
|
+
}
|
|
1840
|
+
let out;
|
|
1841
|
+
let err;
|
|
1842
|
+
try {
|
|
1843
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
1844
|
+
out = fs.openSync(logFile, 'a');
|
|
1845
|
+
err = fs.openSync(logFile, 'a');
|
|
1846
|
+
}
|
|
1847
|
+
catch (error) {
|
|
1848
|
+
logger_1.logger.error(`Failed to prepare daemon log directory or log file at ${logFile}:`, error);
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
const scriptPath = resolveCliEntry();
|
|
1852
|
+
if (!scriptPath) {
|
|
1853
|
+
logger_1.logger.error('Unable to determine the CLI entry point for daemon mode. Set OFFCKB_CLI_PATH to the offckb script.');
|
|
1854
|
+
closeFileDescriptors(out, err);
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
const childArgs = process.argv.slice(2).filter((arg) => arg !== '--daemon');
|
|
1858
|
+
const childEnv = Object.assign(Object.assign({}, process.env), { [DAEMON_CHILD_ENV]: '1' });
|
|
1859
|
+
let child;
|
|
1860
|
+
try {
|
|
1861
|
+
child = (0, child_process_1.spawn)(process.execPath, [scriptPath, ...childArgs], {
|
|
1862
|
+
detached: true,
|
|
1863
|
+
stdio: ['ignore', out, err],
|
|
1864
|
+
env: childEnv,
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
catch (error) {
|
|
1868
|
+
logger_1.logger.error('Failed to spawn daemon process:', error);
|
|
1869
|
+
closeFileDescriptors(out, err);
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
if (!child.pid) {
|
|
1873
|
+
logger_1.logger.error('Failed to spawn daemon process: no PID returned.');
|
|
1874
|
+
closeFileDescriptors(out, err);
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1877
|
+
child.unref();
|
|
1878
|
+
child.on('error', (error) => {
|
|
1879
|
+
logger_1.logger.error('Daemon child process failed to start:', error);
|
|
1880
|
+
cleanupPidFile(pidFile);
|
|
1881
|
+
});
|
|
1882
|
+
const metadata = {
|
|
1883
|
+
pid: child.pid,
|
|
1884
|
+
scriptPath,
|
|
1885
|
+
startedAt: new Date().toISOString(),
|
|
1886
|
+
};
|
|
1887
|
+
writePidFile(pidFile, metadata);
|
|
1888
|
+
// File descriptors are now owned by the spawned child; close our copies.
|
|
1889
|
+
closeFileDescriptors(out, err);
|
|
1890
|
+
logger_1.logger.success(`CKB devnet daemon started with PID ${child.pid}.`);
|
|
1891
|
+
logger_1.logger.info(`Logs: ${logFile}`);
|
|
1892
|
+
logger_1.logger.info(`PID file: ${pidFile}`);
|
|
1893
|
+
logger_1.logger.info('Stop the daemon with: offckb node stop');
|
|
1894
|
+
}
|
|
1895
|
+
function closeFileDescriptors(...fds) {
|
|
1896
|
+
for (const fd of fds) {
|
|
1897
|
+
if (fd === undefined)
|
|
1898
|
+
continue;
|
|
1899
|
+
try {
|
|
1900
|
+
fs.closeSync(fd);
|
|
1901
|
+
}
|
|
1902
|
+
catch (_a) {
|
|
1903
|
+
// ignore
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
function stopNode() {
|
|
1908
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1909
|
+
const { pidFile } = resolveDaemonPaths();
|
|
1910
|
+
const metadata = readPidFile(pidFile);
|
|
1911
|
+
if (!metadata) {
|
|
1912
|
+
logger_1.logger.warn(`No daemon PID file found at ${pidFile}. Is the devnet daemon running?`);
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
const pid = metadata.pid;
|
|
1916
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
1917
|
+
logger_1.logger.error(`Invalid PID in ${pidFile}: ${pid}`);
|
|
1918
|
+
cleanupPidFile(pidFile);
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
if (!isProcessAlive(pid)) {
|
|
1922
|
+
logger_1.logger.warn(`Daemon process ${pid} is not running.`);
|
|
1923
|
+
cleanupPidFile(pidFile);
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
const identityOk = yield verifyDaemonIdentity(pid, metadata);
|
|
1927
|
+
if (!identityOk) {
|
|
1928
|
+
logger_1.logger.error(`Process ${pid} does not appear to be the offckb daemon. Refusing to send signals to avoid killing an unrelated process. ` +
|
|
1929
|
+
`If you are sure this is the daemon, stop it manually and remove ${pidFile}.`);
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
logger_1.logger.info(`Stopping CKB devnet daemon (PID ${pid})...`);
|
|
1933
|
+
try {
|
|
1934
|
+
yield terminateProcess(pid, 'SIGTERM');
|
|
1935
|
+
}
|
|
1936
|
+
catch (error) {
|
|
1937
|
+
const err = error;
|
|
1938
|
+
if (err.code === 'ESRCH') {
|
|
1939
|
+
logger_1.logger.warn(`Daemon process ${pid} is not running.`);
|
|
1940
|
+
cleanupPidFile(pidFile);
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
if (err.code === 'EPERM') {
|
|
1944
|
+
logger_1.logger.error(`Permission denied when sending SIGTERM to daemon process ${pid}.`);
|
|
1945
|
+
}
|
|
1946
|
+
else {
|
|
1947
|
+
logger_1.logger.error(`Failed to send SIGTERM to daemon process ${pid}:`, error);
|
|
1948
|
+
}
|
|
1949
|
+
// Still try to clean up the PID file so the user can recover.
|
|
1950
|
+
cleanupPidFile(pidFile);
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
const exited = yield waitForProcessExit(pid, 5000);
|
|
1954
|
+
if (!exited) {
|
|
1955
|
+
logger_1.logger.warn(`Daemon process ${pid} did not exit gracefully, sending SIGKILL...`);
|
|
1956
|
+
try {
|
|
1957
|
+
yield terminateProcess(pid, 'SIGKILL');
|
|
1958
|
+
}
|
|
1959
|
+
catch (error) {
|
|
1960
|
+
logger_1.logger.error(`Failed to send SIGKILL to daemon process ${pid}:`, error);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
cleanupPidFile(pidFile);
|
|
1964
|
+
logger_1.logger.success('CKB devnet daemon stopped.');
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1497
1967
|
function nodeTestnet() {
|
|
1498
1968
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1499
1969
|
// todo: maybe we can actually start a node for testnet later
|
|
@@ -1518,6 +1988,130 @@ function nodeMainnet() {
|
|
|
1518
1988
|
}
|
|
1519
1989
|
|
|
1520
1990
|
|
|
1991
|
+
/***/ }),
|
|
1992
|
+
|
|
1993
|
+
/***/ 71420:
|
|
1994
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
1995
|
+
|
|
1996
|
+
"use strict";
|
|
1997
|
+
|
|
1998
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
1999
|
+
if (k2 === undefined) k2 = k;
|
|
2000
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
2001
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
2002
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
2003
|
+
}
|
|
2004
|
+
Object.defineProperty(o, k2, desc);
|
|
2005
|
+
}) : (function(o, m, k, k2) {
|
|
2006
|
+
if (k2 === undefined) k2 = k;
|
|
2007
|
+
o[k2] = m[k];
|
|
2008
|
+
}));
|
|
2009
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
2010
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
2011
|
+
}) : function(o, v) {
|
|
2012
|
+
o["default"] = v;
|
|
2013
|
+
});
|
|
2014
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
2015
|
+
var ownKeys = function(o) {
|
|
2016
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
2017
|
+
var ar = [];
|
|
2018
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
2019
|
+
return ar;
|
|
2020
|
+
};
|
|
2021
|
+
return ownKeys(o);
|
|
2022
|
+
};
|
|
2023
|
+
return function (mod) {
|
|
2024
|
+
if (mod && mod.__esModule) return mod;
|
|
2025
|
+
var result = {};
|
|
2026
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
2027
|
+
__setModuleDefault(result, mod);
|
|
2028
|
+
return result;
|
|
2029
|
+
};
|
|
2030
|
+
})();
|
|
2031
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2032
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
2033
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
2034
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
2035
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
2036
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
2037
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
2038
|
+
});
|
|
2039
|
+
};
|
|
2040
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
2041
|
+
exports.status = status;
|
|
2042
|
+
const setting_1 = __nccwpck_require__(25546);
|
|
2043
|
+
const ckb_tui_1 = __nccwpck_require__(7020);
|
|
2044
|
+
const base_1 = __nccwpck_require__(69951);
|
|
2045
|
+
const logger_1 = __nccwpck_require__(65370);
|
|
2046
|
+
const net = __importStar(__nccwpck_require__(69278));
|
|
2047
|
+
const NETWORK_SETTINGS_KEY = {
|
|
2048
|
+
[base_1.Network.devnet]: 'devnet',
|
|
2049
|
+
[base_1.Network.testnet]: 'testnet',
|
|
2050
|
+
[base_1.Network.mainnet]: 'mainnet',
|
|
2051
|
+
};
|
|
2052
|
+
function status(_a) {
|
|
2053
|
+
return __awaiter(this, arguments, void 0, function* ({ network }) {
|
|
2054
|
+
var _b;
|
|
2055
|
+
// ckb-tui is an interactive terminal UI. Running it without a TTY
|
|
2056
|
+
// (pipe, redirect, CI) would hang or produce garbage output.
|
|
2057
|
+
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
2058
|
+
logger_1.logger.error('The status command requires an interactive terminal (TTY). ' +
|
|
2059
|
+
'It cannot be used in pipes, redirects, or non-interactive environments like CI.');
|
|
2060
|
+
process.exit(1);
|
|
2061
|
+
}
|
|
2062
|
+
const settings = (0, setting_1.readSettings)();
|
|
2063
|
+
const networkKey = NETWORK_SETTINGS_KEY[network];
|
|
2064
|
+
const port = settings[networkKey].rpcProxyPort;
|
|
2065
|
+
const url = `http://127.0.0.1:${port}`;
|
|
2066
|
+
const isListening = yield isRPCPortListening(port);
|
|
2067
|
+
if (!isListening) {
|
|
2068
|
+
logger_1.logger.error(`RPC port ${port} is not listening. Please make sure the ${network} node is running and Proxy RPC is enabled.`);
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
const result = ckb_tui_1.CKBTui.run(['-r', url]);
|
|
2072
|
+
// Propagate ckb-tui exit code so scripts can detect TUI failure
|
|
2073
|
+
if (result.status !== 0) {
|
|
2074
|
+
process.exitCode = (_b = result.status) !== null && _b !== void 0 ? _b : 1;
|
|
2075
|
+
}
|
|
2076
|
+
});
|
|
2077
|
+
}
|
|
2078
|
+
function isRPCPortListening(port) {
|
|
2079
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2080
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
2081
|
+
return false;
|
|
2082
|
+
}
|
|
2083
|
+
const client = new net.Socket();
|
|
2084
|
+
return new Promise((resolve) => {
|
|
2085
|
+
let settled = false;
|
|
2086
|
+
const TIMEOUT_MS = 2000;
|
|
2087
|
+
const timeout = setTimeout(() => {
|
|
2088
|
+
if (!settled) {
|
|
2089
|
+
settled = true;
|
|
2090
|
+
client.destroy();
|
|
2091
|
+
resolve(false);
|
|
2092
|
+
}
|
|
2093
|
+
}, TIMEOUT_MS);
|
|
2094
|
+
client.once('error', () => {
|
|
2095
|
+
if (!settled) {
|
|
2096
|
+
settled = true;
|
|
2097
|
+
clearTimeout(timeout);
|
|
2098
|
+
resolve(false);
|
|
2099
|
+
}
|
|
2100
|
+
});
|
|
2101
|
+
client.once('connect', () => {
|
|
2102
|
+
if (!settled) {
|
|
2103
|
+
settled = true;
|
|
2104
|
+
clearTimeout(timeout);
|
|
2105
|
+
client.end();
|
|
2106
|
+
resolve(true);
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
2109
|
+
client.connect(port, '127.0.0.1');
|
|
2110
|
+
});
|
|
2111
|
+
});
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
|
|
1521
2115
|
/***/ }),
|
|
1522
2116
|
|
|
1523
2117
|
/***/ 86198:
|
|
@@ -1829,9 +2423,9 @@ const ckb_1 = __nccwpck_require__(83748);
|
|
|
1829
2423
|
const base_1 = __nccwpck_require__(69951);
|
|
1830
2424
|
const link_1 = __nccwpck_require__(27814);
|
|
1831
2425
|
const validator_1 = __nccwpck_require__(39534);
|
|
1832
|
-
|
|
1833
|
-
function
|
|
1834
|
-
|
|
2426
|
+
function transfer(toAddress_1, amount_1) {
|
|
2427
|
+
return __awaiter(this, arguments, void 0, function* (toAddress, amount, opt = { network: base_1.Network.devnet }) {
|
|
2428
|
+
var _a;
|
|
1835
2429
|
const network = opt.network;
|
|
1836
2430
|
(0, validator_1.validateNetworkOpt)(network);
|
|
1837
2431
|
if (opt.privkey == null) {
|
|
@@ -1839,16 +2433,89 @@ function transfer(toAddress_1, amountInCKB_1) {
|
|
|
1839
2433
|
}
|
|
1840
2434
|
const privateKey = opt.privkey;
|
|
1841
2435
|
const ckb = new ckb_1.CKB({ network });
|
|
2436
|
+
if (opt.udtTypeArgs) {
|
|
2437
|
+
const kind = (_a = opt.udtKind) !== null && _a !== void 0 ? _a : 'sudt';
|
|
2438
|
+
(0, validator_1.validateUdtKind)(kind);
|
|
2439
|
+
const udtTypeArgs = (0, validator_1.validateUdtTypeArgs)(kind, opt.udtTypeArgs);
|
|
2440
|
+
const udtType = yield ckb.buildUdtTypeScript(kind, udtTypeArgs);
|
|
2441
|
+
const txHash = yield ckb.udtTransfer({
|
|
2442
|
+
toAddress,
|
|
2443
|
+
amount,
|
|
2444
|
+
privateKey,
|
|
2445
|
+
udtType,
|
|
2446
|
+
kind,
|
|
2447
|
+
});
|
|
2448
|
+
(0, link_1.logTxSuccess)(network, txHash, 'transfer UDT');
|
|
2449
|
+
return;
|
|
2450
|
+
}
|
|
1842
2451
|
const txHash = yield ckb.transfer({
|
|
1843
2452
|
toAddress,
|
|
1844
|
-
amountInCKB,
|
|
2453
|
+
amountInCKB: amount,
|
|
1845
2454
|
privateKey,
|
|
1846
2455
|
});
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
2456
|
+
(0, link_1.logTxSuccess)(network, txHash, 'transfer');
|
|
2457
|
+
});
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
|
|
2461
|
+
/***/ }),
|
|
2462
|
+
|
|
2463
|
+
/***/ 50703:
|
|
2464
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
2465
|
+
|
|
2466
|
+
"use strict";
|
|
2467
|
+
|
|
2468
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2469
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
2470
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
2471
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
2472
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
2473
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
2474
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
2475
|
+
});
|
|
2476
|
+
};
|
|
2477
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
2478
|
+
exports.udtIssue = udtIssue;
|
|
2479
|
+
exports.udtDestroy = udtDestroy;
|
|
2480
|
+
const ckb_1 = __nccwpck_require__(83748);
|
|
2481
|
+
const base_1 = __nccwpck_require__(69951);
|
|
2482
|
+
const link_1 = __nccwpck_require__(27814);
|
|
2483
|
+
const validator_1 = __nccwpck_require__(39534);
|
|
2484
|
+
function udtIssue(amount_1) {
|
|
2485
|
+
return __awaiter(this, arguments, void 0, function* (amount, opt = { network: base_1.Network.devnet, udtKind: 'sudt', privkey: '' }) {
|
|
2486
|
+
const network = opt.network;
|
|
2487
|
+
(0, validator_1.validateNetworkOpt)(network);
|
|
2488
|
+
(0, validator_1.validateUdtKind)(opt.udtKind);
|
|
2489
|
+
if (!opt.privkey) {
|
|
2490
|
+
throw new Error('--privkey is required!');
|
|
1850
2491
|
}
|
|
1851
|
-
|
|
2492
|
+
const ckb = new ckb_1.CKB({ network });
|
|
2493
|
+
const txHash = yield ckb.udtIssue({
|
|
2494
|
+
privateKey: opt.privkey,
|
|
2495
|
+
kind: opt.udtKind,
|
|
2496
|
+
amount,
|
|
2497
|
+
typeArgs: opt.typeArgs ? (0, validator_1.validateUdtTypeArgs)(opt.udtKind, opt.typeArgs) : undefined,
|
|
2498
|
+
toAddress: opt.to,
|
|
2499
|
+
});
|
|
2500
|
+
(0, link_1.logTxSuccess)(network, txHash, 'issued UDT');
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2503
|
+
function udtDestroy(amount_1) {
|
|
2504
|
+
return __awaiter(this, arguments, void 0, function* (amount, opt = { network: base_1.Network.devnet, udtKind: 'sudt', typeArgs: '', privkey: '' }) {
|
|
2505
|
+
const network = opt.network;
|
|
2506
|
+
(0, validator_1.validateNetworkOpt)(network);
|
|
2507
|
+
(0, validator_1.validateUdtKind)(opt.udtKind);
|
|
2508
|
+
if (!opt.privkey) {
|
|
2509
|
+
throw new Error('--privkey is required!');
|
|
2510
|
+
}
|
|
2511
|
+
const ckb = new ckb_1.CKB({ network });
|
|
2512
|
+
const txHash = yield ckb.udtDestroy({
|
|
2513
|
+
privateKey: opt.privkey,
|
|
2514
|
+
kind: opt.udtKind,
|
|
2515
|
+
amount,
|
|
2516
|
+
typeArgs: (0, validator_1.validateUdtTypeArgs)(opt.udtKind, opt.typeArgs),
|
|
2517
|
+
});
|
|
2518
|
+
(0, link_1.logTxSuccess)(network, txHash, 'destroyed UDT');
|
|
1852
2519
|
});
|
|
1853
2520
|
}
|
|
1854
2521
|
|
|
@@ -3827,18 +4494,36 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
3827
4494
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
3828
4495
|
});
|
|
3829
4496
|
};
|
|
4497
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
4498
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
4499
|
+
var m = o[Symbol.asyncIterator], i;
|
|
4500
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
4501
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
4502
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
4503
|
+
};
|
|
3830
4504
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
3831
4505
|
exports.CKB = exports.CKBProps = void 0;
|
|
3832
4506
|
const core_1 = __nccwpck_require__(39842);
|
|
3833
4507
|
const validator_1 = __nccwpck_require__(39534);
|
|
3834
4508
|
const network_1 = __nccwpck_require__(5370);
|
|
3835
4509
|
const private_1 = __nccwpck_require__(5835);
|
|
4510
|
+
const public_1 = __nccwpck_require__(84535);
|
|
3836
4511
|
const migration_1 = __nccwpck_require__(76679);
|
|
3837
4512
|
const base_1 = __nccwpck_require__(69951);
|
|
3838
4513
|
const logger_1 = __nccwpck_require__(65370);
|
|
4514
|
+
const DEFAULT_UDT_SCAN_MAX_CELLS = 1000;
|
|
4515
|
+
const DEFAULT_UDT_DESTROY_MAX_INPUT_CELLS = 100;
|
|
3839
4516
|
class CKBProps {
|
|
3840
4517
|
}
|
|
3841
4518
|
exports.CKBProps = CKBProps;
|
|
4519
|
+
function readUdtBalance(outputData) {
|
|
4520
|
+
try {
|
|
4521
|
+
return BigInt(core_1.ccc.udtBalanceFrom(outputData));
|
|
4522
|
+
}
|
|
4523
|
+
catch (_a) {
|
|
4524
|
+
return null;
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
3842
4527
|
class CKB {
|
|
3843
4528
|
constructor({ network = base_1.Network.devnet, feeRate = 1000, isEnableProxyRpc = true }) {
|
|
3844
4529
|
if (!(0, validator_1.isValidNetworkString)(network)) {
|
|
@@ -3972,6 +4657,286 @@ class CKB {
|
|
|
3972
4657
|
return txHash;
|
|
3973
4658
|
});
|
|
3974
4659
|
}
|
|
4660
|
+
getSystemScripts() {
|
|
4661
|
+
if (this.network === base_1.Network.mainnet) {
|
|
4662
|
+
return public_1.MAINNET_SYSTEM_SCRIPTS;
|
|
4663
|
+
}
|
|
4664
|
+
if (this.network === base_1.Network.testnet) {
|
|
4665
|
+
return public_1.TESTNET_SYSTEM_SCRIPTS;
|
|
4666
|
+
}
|
|
4667
|
+
const scripts = (0, private_1.getDevnetSystemScriptsFromListHashes)();
|
|
4668
|
+
if (!scripts) {
|
|
4669
|
+
throw new Error(`Failed to load devnet system scripts`);
|
|
4670
|
+
}
|
|
4671
|
+
return scripts;
|
|
4672
|
+
}
|
|
4673
|
+
buildUdtTypeScript(kind, args) {
|
|
4674
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
4675
|
+
if (kind === 'xudt') {
|
|
4676
|
+
return core_1.ccc.Script.fromKnownScript(this.client, core_1.ccc.KnownScript.XUdt, args);
|
|
4677
|
+
}
|
|
4678
|
+
const scriptInfo = yield this.getUdtScriptInfo(kind);
|
|
4679
|
+
return core_1.ccc.Script.from({
|
|
4680
|
+
codeHash: scriptInfo.codeHash,
|
|
4681
|
+
hashType: scriptInfo.hashType,
|
|
4682
|
+
args,
|
|
4683
|
+
});
|
|
4684
|
+
});
|
|
4685
|
+
}
|
|
4686
|
+
getUdtScriptInfo(kind) {
|
|
4687
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
4688
|
+
var _a;
|
|
4689
|
+
if (kind === 'xudt') {
|
|
4690
|
+
return this.client.getKnownScript(core_1.ccc.KnownScript.XUdt);
|
|
4691
|
+
}
|
|
4692
|
+
const systemScripts = this.getSystemScripts();
|
|
4693
|
+
const sudtScript = (_a = systemScripts.sudt) === null || _a === void 0 ? void 0 : _a.script;
|
|
4694
|
+
if (!sudtScript) {
|
|
4695
|
+
throw new Error(`SUDT script not found on ${this.network}`);
|
|
4696
|
+
}
|
|
4697
|
+
return sudtScript;
|
|
4698
|
+
});
|
|
4699
|
+
}
|
|
4700
|
+
detectUdtBalances(address_1) {
|
|
4701
|
+
return __awaiter(this, arguments, void 0, function* (address, { maxCells = DEFAULT_UDT_SCAN_MAX_CELLS } = {}) {
|
|
4702
|
+
const lock = (yield core_1.ccc.Address.fromString(address, this.client)).script;
|
|
4703
|
+
const sudtScriptInfo = yield this.getUdtScriptInfo('sudt').catch(() => null);
|
|
4704
|
+
const xudtScriptInfo = yield this.getUdtScriptInfo('xudt').catch(() => null);
|
|
4705
|
+
const balances = new Map();
|
|
4706
|
+
let scanned = 0;
|
|
4707
|
+
const scan = (scriptInfo, kind) => __awaiter(this, void 0, void 0, function* () {
|
|
4708
|
+
var _a, e_1, _b, _c;
|
|
4709
|
+
var _d, _e;
|
|
4710
|
+
try {
|
|
4711
|
+
for (var _f = true, _g = __asyncValues(this.client.findCells({
|
|
4712
|
+
script: {
|
|
4713
|
+
codeHash: scriptInfo.codeHash,
|
|
4714
|
+
hashType: scriptInfo.hashType,
|
|
4715
|
+
args: '0x',
|
|
4716
|
+
},
|
|
4717
|
+
scriptType: 'type',
|
|
4718
|
+
scriptSearchMode: 'prefix',
|
|
4719
|
+
filter: { script: lock },
|
|
4720
|
+
withData: true,
|
|
4721
|
+
}, 'asc')), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
|
|
4722
|
+
_c = _h.value;
|
|
4723
|
+
_f = false;
|
|
4724
|
+
const cell = _c;
|
|
4725
|
+
if (scanned >= maxCells) {
|
|
4726
|
+
logger_1.logger.warn(`UDT balance scan stopped after ${maxCells} cells; balances may be incomplete`);
|
|
4727
|
+
break;
|
|
4728
|
+
}
|
|
4729
|
+
scanned++;
|
|
4730
|
+
const type = cell.cellOutput.type;
|
|
4731
|
+
if (!type) {
|
|
4732
|
+
continue;
|
|
4733
|
+
}
|
|
4734
|
+
const cellBalance = readUdtBalance(cell.outputData);
|
|
4735
|
+
if (cellBalance == null) {
|
|
4736
|
+
logger_1.logger.debug(`Skipping corrupted UDT cell ${(_d = cell.outPoint) === null || _d === void 0 ? void 0 : _d.txHash}:${(_e = cell.outPoint) === null || _e === void 0 ? void 0 : _e.index}`);
|
|
4737
|
+
continue;
|
|
4738
|
+
}
|
|
4739
|
+
const key = `${kind}:${type.codeHash}:${type.hashType}:${type.args}`;
|
|
4740
|
+
const entry = balances.get(key);
|
|
4741
|
+
if (entry) {
|
|
4742
|
+
entry.balance += cellBalance;
|
|
4743
|
+
}
|
|
4744
|
+
else {
|
|
4745
|
+
balances.set(key, {
|
|
4746
|
+
kind,
|
|
4747
|
+
codeHash: type.codeHash,
|
|
4748
|
+
hashType: String(type.hashType),
|
|
4749
|
+
args: type.args,
|
|
4750
|
+
balance: cellBalance,
|
|
4751
|
+
});
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4755
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
4756
|
+
finally {
|
|
4757
|
+
try {
|
|
4758
|
+
if (!_f && !_a && (_b = _g.return)) yield _b.call(_g);
|
|
4759
|
+
}
|
|
4760
|
+
finally { if (e_1) throw e_1.error; }
|
|
4761
|
+
}
|
|
4762
|
+
});
|
|
4763
|
+
if (sudtScriptInfo) {
|
|
4764
|
+
yield scan(sudtScriptInfo, 'sudt');
|
|
4765
|
+
}
|
|
4766
|
+
if (xudtScriptInfo) {
|
|
4767
|
+
yield scan(xudtScriptInfo, 'xudt');
|
|
4768
|
+
}
|
|
4769
|
+
return Array.from(balances.values()).map((item) => (Object.assign(Object.assign({}, item), { balance: item.balance.toString() })));
|
|
4770
|
+
});
|
|
4771
|
+
}
|
|
4772
|
+
udtBalance(address_1, udtType_1) {
|
|
4773
|
+
return __awaiter(this, arguments, void 0, function* (address, udtType, { maxCells = DEFAULT_UDT_SCAN_MAX_CELLS } = {}) {
|
|
4774
|
+
var _a, e_2, _b, _c;
|
|
4775
|
+
const lock = (yield core_1.ccc.Address.fromString(address, this.client)).script;
|
|
4776
|
+
let balance = BigInt(0);
|
|
4777
|
+
let scanned = 0;
|
|
4778
|
+
try {
|
|
4779
|
+
for (var _d = true, _e = __asyncValues(this.client.findCellsByLock(lock, udtType, true)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
4780
|
+
_c = _f.value;
|
|
4781
|
+
_d = false;
|
|
4782
|
+
const cell = _c;
|
|
4783
|
+
scanned++;
|
|
4784
|
+
if (scanned > maxCells) {
|
|
4785
|
+
logger_1.logger.warn(`UDT balance scan stopped after ${maxCells} cells; balances may be incomplete`);
|
|
4786
|
+
break;
|
|
4787
|
+
}
|
|
4788
|
+
const cellBalance = readUdtBalance(cell.outputData);
|
|
4789
|
+
if (cellBalance != null) {
|
|
4790
|
+
balance += cellBalance;
|
|
4791
|
+
}
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
4795
|
+
finally {
|
|
4796
|
+
try {
|
|
4797
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
4798
|
+
}
|
|
4799
|
+
finally { if (e_2) throw e_2.error; }
|
|
4800
|
+
}
|
|
4801
|
+
return balance.toString();
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
udtTransfer(_a) {
|
|
4805
|
+
return __awaiter(this, arguments, void 0, function* ({ privateKey, toAddress, amount, udtType, kind }) {
|
|
4806
|
+
const signer = this.buildSigner(privateKey);
|
|
4807
|
+
const to = yield core_1.ccc.Address.fromString(toAddress, this.client);
|
|
4808
|
+
const amountBigInt = (0, validator_1.validateUdtAmount)(amount);
|
|
4809
|
+
const outputsData = [core_1.ccc.hexFrom(core_1.ccc.numToBytes(amountBigInt, 16))];
|
|
4810
|
+
const tx = core_1.ccc.Transaction.from({
|
|
4811
|
+
outputs: [
|
|
4812
|
+
{
|
|
4813
|
+
lock: to.script,
|
|
4814
|
+
type: udtType,
|
|
4815
|
+
capacity: core_1.ccc.fixedPointFrom(0),
|
|
4816
|
+
},
|
|
4817
|
+
],
|
|
4818
|
+
outputsData,
|
|
4819
|
+
});
|
|
4820
|
+
const scriptInfo = yield this.getUdtScriptInfo(kind);
|
|
4821
|
+
tx.addCellDeps(scriptInfo.cellDeps.map((dep) => dep.cellDep));
|
|
4822
|
+
yield tx.completeInputsByUdt(signer, udtType);
|
|
4823
|
+
const inputsUdtBalance = yield tx.getInputsUdtBalance(this.client, udtType);
|
|
4824
|
+
const outputsUdtBalance = tx.getOutputsUdtBalance(udtType);
|
|
4825
|
+
const changeAmount = inputsUdtBalance - outputsUdtBalance;
|
|
4826
|
+
if (changeAmount > BigInt(0)) {
|
|
4827
|
+
const from = yield signer.getAddressObjSecp256k1();
|
|
4828
|
+
tx.outputs.push(core_1.ccc.CellOutput.from({
|
|
4829
|
+
lock: from.script,
|
|
4830
|
+
type: udtType,
|
|
4831
|
+
capacity: core_1.ccc.fixedPointFrom(0),
|
|
4832
|
+
}, core_1.ccc.hexFrom(core_1.ccc.numToBytes(changeAmount, 16))));
|
|
4833
|
+
tx.outputsData.push(core_1.ccc.hexFrom(core_1.ccc.numToBytes(changeAmount, 16)));
|
|
4834
|
+
}
|
|
4835
|
+
yield tx.completeFeeBy(signer, this.feeRate);
|
|
4836
|
+
const txHash = yield signer.sendTransaction(tx);
|
|
4837
|
+
return txHash;
|
|
4838
|
+
});
|
|
4839
|
+
}
|
|
4840
|
+
udtIssue(_a) {
|
|
4841
|
+
return __awaiter(this, arguments, void 0, function* ({ privateKey, kind, amount, typeArgs, toAddress }) {
|
|
4842
|
+
const signer = this.buildSigner(privateKey);
|
|
4843
|
+
const signerAddress = yield signer.getAddressObjSecp256k1();
|
|
4844
|
+
const to = toAddress ? yield core_1.ccc.Address.fromString(toAddress, this.client) : signerAddress;
|
|
4845
|
+
const amountBigInt = (0, validator_1.validateUdtAmount)(amount);
|
|
4846
|
+
let resolvedTypeArgs;
|
|
4847
|
+
if (kind === 'sudt') {
|
|
4848
|
+
if (typeArgs) {
|
|
4849
|
+
logger_1.logger.warn('SUDT type args are derived from the issuer lock hash; --type-args is ignored');
|
|
4850
|
+
}
|
|
4851
|
+
const issuerLockHash = signerAddress.script.hash();
|
|
4852
|
+
resolvedTypeArgs = ('0x' + issuerLockHash.slice(2, 42));
|
|
4853
|
+
}
|
|
4854
|
+
else {
|
|
4855
|
+
if (typeArgs) {
|
|
4856
|
+
resolvedTypeArgs = (0, validator_1.validateUdtTypeArgs)(kind, typeArgs);
|
|
4857
|
+
}
|
|
4858
|
+
else {
|
|
4859
|
+
const issuerLockHash = signerAddress.script.hash();
|
|
4860
|
+
resolvedTypeArgs = issuerLockHash;
|
|
4861
|
+
}
|
|
4862
|
+
}
|
|
4863
|
+
const udtType = yield this.buildUdtTypeScript(kind, resolvedTypeArgs);
|
|
4864
|
+
const outputsData = [core_1.ccc.hexFrom(core_1.ccc.numToBytes(amountBigInt, 16))];
|
|
4865
|
+
const tx = core_1.ccc.Transaction.from({
|
|
4866
|
+
outputs: [
|
|
4867
|
+
{
|
|
4868
|
+
lock: to.script,
|
|
4869
|
+
type: udtType,
|
|
4870
|
+
capacity: core_1.ccc.fixedPointFrom(0),
|
|
4871
|
+
},
|
|
4872
|
+
],
|
|
4873
|
+
outputsData,
|
|
4874
|
+
});
|
|
4875
|
+
const scriptInfo = yield this.getUdtScriptInfo(kind);
|
|
4876
|
+
tx.addCellDeps(scriptInfo.cellDeps.map((dep) => dep.cellDep));
|
|
4877
|
+
yield tx.completeInputsByCapacity(signer);
|
|
4878
|
+
yield tx.completeFeeBy(signer, this.feeRate);
|
|
4879
|
+
const txHash = yield signer.sendTransaction(tx);
|
|
4880
|
+
return txHash;
|
|
4881
|
+
});
|
|
4882
|
+
}
|
|
4883
|
+
udtDestroy(_a) {
|
|
4884
|
+
return __awaiter(this, arguments, void 0, function* ({ privateKey, kind, typeArgs, amount }, { maxInputCells = DEFAULT_UDT_DESTROY_MAX_INPUT_CELLS } = {}) {
|
|
4885
|
+
var _b, e_3, _c, _d;
|
|
4886
|
+
const signer = this.buildSigner(privateKey);
|
|
4887
|
+
const from = yield signer.getAddressObjSecp256k1();
|
|
4888
|
+
const validatedTypeArgs = (0, validator_1.validateUdtTypeArgs)(kind, typeArgs);
|
|
4889
|
+
const udtType = yield this.buildUdtTypeScript(kind, validatedTypeArgs);
|
|
4890
|
+
const destroyAmount = (0, validator_1.validateUdtAmount)(amount);
|
|
4891
|
+
const cells = [];
|
|
4892
|
+
let totalBalance = BigInt(0);
|
|
4893
|
+
try {
|
|
4894
|
+
for (var _e = true, _f = __asyncValues(this.client.findCellsByLock(from.script, udtType, true)), _g; _g = yield _f.next(), _b = _g.done, !_b; _e = true) {
|
|
4895
|
+
_d = _g.value;
|
|
4896
|
+
_e = false;
|
|
4897
|
+
const cell = _d;
|
|
4898
|
+
if (cells.length >= maxInputCells) {
|
|
4899
|
+
throw new Error(`Too many UDT cells to destroy (limit: ${maxInputCells}); split into smaller operations`);
|
|
4900
|
+
}
|
|
4901
|
+
const cellBalance = readUdtBalance(cell.outputData);
|
|
4902
|
+
if (cellBalance == null) {
|
|
4903
|
+
continue;
|
|
4904
|
+
}
|
|
4905
|
+
cells.push(cell);
|
|
4906
|
+
totalBalance += cellBalance;
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
4910
|
+
finally {
|
|
4911
|
+
try {
|
|
4912
|
+
if (!_e && !_b && (_c = _f.return)) yield _c.call(_f);
|
|
4913
|
+
}
|
|
4914
|
+
finally { if (e_3) throw e_3.error; }
|
|
4915
|
+
}
|
|
4916
|
+
if (totalBalance < destroyAmount) {
|
|
4917
|
+
throw new Error(`Insufficient UDT balance: ${totalBalance} < ${destroyAmount}`);
|
|
4918
|
+
}
|
|
4919
|
+
if (destroyAmount === totalBalance) {
|
|
4920
|
+
throw new Error('Destroying the entire UDT balance may be rejected by the UDT script. Leave at least 1 token or use a smaller amount.');
|
|
4921
|
+
}
|
|
4922
|
+
const tx = core_1.ccc.Transaction.from({});
|
|
4923
|
+
for (const cell of cells) {
|
|
4924
|
+
tx.addInput({ previousOutput: cell.outPoint });
|
|
4925
|
+
}
|
|
4926
|
+
const remaining = totalBalance - destroyAmount;
|
|
4927
|
+
tx.addOutput(core_1.ccc.CellOutput.from({
|
|
4928
|
+
lock: from.script,
|
|
4929
|
+
type: udtType,
|
|
4930
|
+
capacity: core_1.ccc.fixedPointFrom(0),
|
|
4931
|
+
}, core_1.ccc.hexFrom(core_1.ccc.numToBytes(remaining, 16))), core_1.ccc.hexFrom(core_1.ccc.numToBytes(remaining, 16)));
|
|
4932
|
+
const scriptInfo = yield this.getUdtScriptInfo(kind);
|
|
4933
|
+
tx.addCellDeps(scriptInfo.cellDeps.map((dep) => dep.cellDep));
|
|
4934
|
+
yield tx.completeInputsByCapacity(signer);
|
|
4935
|
+
yield tx.completeFeeBy(signer, this.feeRate);
|
|
4936
|
+
const txHash = yield signer.sendTransaction(tx);
|
|
4937
|
+
return txHash;
|
|
4938
|
+
});
|
|
4939
|
+
}
|
|
3975
4940
|
deployScript(scriptBinBytes, privateKey) {
|
|
3976
4941
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3977
4942
|
const signer = this.buildSigner(privateKey);
|
|
@@ -5103,222 +6068,530 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
5103
6068
|
return result;
|
|
5104
6069
|
};
|
|
5105
6070
|
})();
|
|
5106
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
5107
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5108
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5109
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5110
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
5111
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
5112
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
5113
|
-
});
|
|
6071
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6072
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
6073
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6074
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6075
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6076
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
6077
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
6078
|
+
});
|
|
6079
|
+
};
|
|
6080
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
6081
|
+
exports.CKBDebugger = void 0;
|
|
6082
|
+
const child_process_1 = __nccwpck_require__(35317);
|
|
6083
|
+
const path = __importStar(__nccwpck_require__(16928));
|
|
6084
|
+
const setting_1 = __nccwpck_require__(25546);
|
|
6085
|
+
const ckb_debugger_wasm_1 = __nccwpck_require__(52948);
|
|
6086
|
+
const logger_1 = __nccwpck_require__(65370);
|
|
6087
|
+
class CKBDebugger {
|
|
6088
|
+
static getWasmDebugger() {
|
|
6089
|
+
if (!this.wasmDebugger) {
|
|
6090
|
+
const wasmPath = path.join(__dirname, 'ckb-debugger.wasm');
|
|
6091
|
+
this.wasmDebugger = new ckb_debugger_wasm_1.CkbDebuggerWasi({
|
|
6092
|
+
wasmPath,
|
|
6093
|
+
captureOutput: false, // Use stdio directly since custom capture doesn't work with WASI
|
|
6094
|
+
});
|
|
6095
|
+
}
|
|
6096
|
+
return this.wasmDebugger;
|
|
6097
|
+
}
|
|
6098
|
+
/**
|
|
6099
|
+
* Check if we're in a recursive call to avoid infinite loops
|
|
6100
|
+
* This happens when ckb-debugger binary points to offckb CLI
|
|
6101
|
+
*/
|
|
6102
|
+
static isRecursiveCall() {
|
|
6103
|
+
// Check if we're already running as a ckb-debugger process
|
|
6104
|
+
if (process.argv[1] && process.argv[1].includes('ckb-debugger')) {
|
|
6105
|
+
logger_1.logger.debug('Detected ckb-debugger process, using WASM to avoid recursion');
|
|
6106
|
+
return true;
|
|
6107
|
+
}
|
|
6108
|
+
// Check if we're running the debugger command (which could be called from ckb-debugger binary)
|
|
6109
|
+
if (process.argv.includes('debugger')) {
|
|
6110
|
+
logger_1.logger.debug('Detected debugger command, using WASM to avoid recursion');
|
|
6111
|
+
return true;
|
|
6112
|
+
}
|
|
6113
|
+
return false;
|
|
6114
|
+
}
|
|
6115
|
+
static shouldUseWasm() {
|
|
6116
|
+
if (this.isRecursiveCall()) {
|
|
6117
|
+
return true;
|
|
6118
|
+
}
|
|
6119
|
+
if (this.isBinaryInstalled() && this.isBinaryVersionValid()) {
|
|
6120
|
+
logger_1.logger.debug('Using native ckb-debugger (better performance)');
|
|
6121
|
+
return false;
|
|
6122
|
+
}
|
|
6123
|
+
else {
|
|
6124
|
+
logger_1.logger.debug('Native ckb-debugger not available, falling back to WASM version');
|
|
6125
|
+
return true;
|
|
6126
|
+
}
|
|
6127
|
+
}
|
|
6128
|
+
static execute(args) {
|
|
6129
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
6130
|
+
if (this.shouldUseWasm()) {
|
|
6131
|
+
try {
|
|
6132
|
+
const result = yield this.getWasmDebugger().run(args);
|
|
6133
|
+
if (result.exitCode !== 0) {
|
|
6134
|
+
process.exit(result.exitCode);
|
|
6135
|
+
}
|
|
6136
|
+
}
|
|
6137
|
+
catch (error) {
|
|
6138
|
+
logger_1.logger.error('WASM debugger execution failed:', error);
|
|
6139
|
+
process.exit(1);
|
|
6140
|
+
}
|
|
6141
|
+
}
|
|
6142
|
+
else {
|
|
6143
|
+
const command = `ckb-debugger ${args.join(' ')}`;
|
|
6144
|
+
(0, child_process_1.execSync)(command, { stdio: 'inherit' });
|
|
6145
|
+
}
|
|
6146
|
+
});
|
|
6147
|
+
}
|
|
6148
|
+
static runRaw(options) {
|
|
6149
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
6150
|
+
const args = options.split(' ').filter((arg) => arg.trim());
|
|
6151
|
+
yield this.execute(args);
|
|
6152
|
+
});
|
|
6153
|
+
}
|
|
6154
|
+
static runTxCellScript(_a) {
|
|
6155
|
+
return __awaiter(this, arguments, void 0, function* ({ fullTxJsonFilePath, cellIndex, cellType, scriptGroupType }) {
|
|
6156
|
+
const args = [
|
|
6157
|
+
'--tx-file',
|
|
6158
|
+
fullTxJsonFilePath,
|
|
6159
|
+
'--cell-index',
|
|
6160
|
+
cellIndex.toString(),
|
|
6161
|
+
'--cell-type',
|
|
6162
|
+
cellType,
|
|
6163
|
+
'--script-group-type',
|
|
6164
|
+
scriptGroupType,
|
|
6165
|
+
];
|
|
6166
|
+
yield this.execute(args);
|
|
6167
|
+
});
|
|
6168
|
+
}
|
|
6169
|
+
static isBinaryInstalled() {
|
|
6170
|
+
const result = (0, child_process_1.spawnSync)('ckb-debugger', ['--version'], { stdio: 'ignore' });
|
|
6171
|
+
return result.status === 0;
|
|
6172
|
+
}
|
|
6173
|
+
static isBinaryVersionValid() {
|
|
6174
|
+
const result = (0, child_process_1.spawnSync)('ckb-debugger', ['--version']);
|
|
6175
|
+
if (result.status !== 0) {
|
|
6176
|
+
return false;
|
|
6177
|
+
}
|
|
6178
|
+
try {
|
|
6179
|
+
const version = result.stdout.toString().split(' ')[1];
|
|
6180
|
+
const settings = (0, setting_1.readSettings)();
|
|
6181
|
+
if (version < settings.tools.ckbDebugger.minVersion) {
|
|
6182
|
+
return false;
|
|
6183
|
+
}
|
|
6184
|
+
return true;
|
|
6185
|
+
}
|
|
6186
|
+
catch (error) {
|
|
6187
|
+
return false;
|
|
6188
|
+
}
|
|
6189
|
+
}
|
|
6190
|
+
static installCKBDebuggerBinary() {
|
|
6191
|
+
const command = `cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger`;
|
|
6192
|
+
try {
|
|
6193
|
+
logger_1.logger.info('Installing ckb-debugger...');
|
|
6194
|
+
(0, child_process_1.execSync)(command, { stdio: 'inherit' });
|
|
6195
|
+
logger_1.logger.info('ckb-debugger installed successfully. You can uninstall it by running: cargo uninstall ckb-debugger');
|
|
6196
|
+
}
|
|
6197
|
+
catch (error) {
|
|
6198
|
+
logger_1.logger.error('Failed to install ckb-debugger:', error);
|
|
6199
|
+
process.exit(1);
|
|
6200
|
+
}
|
|
6201
|
+
}
|
|
6202
|
+
/**
|
|
6203
|
+
* Create a ckb-debugger fallback binary that points to offckb debugger
|
|
6204
|
+
* This creates a shell script that calls: offckb debugger [args]
|
|
6205
|
+
* Purpose: Reduce user friction by providing a placeholder when native binary is not available
|
|
6206
|
+
* Users can install the real ckb-debugger binary for better performance if needed
|
|
6207
|
+
*/
|
|
6208
|
+
static createCkbDebuggerFallback() {
|
|
6209
|
+
const fs = __nccwpck_require__(79896);
|
|
6210
|
+
const { spawnSync } = __nccwpck_require__(35317);
|
|
6211
|
+
const isWindows = process.platform === 'win32';
|
|
6212
|
+
const binName = isWindows ? 'ckb-debugger.cmd' : 'ckb-debugger';
|
|
6213
|
+
// Find the offckb binary location
|
|
6214
|
+
let offckbPath;
|
|
6215
|
+
if (isWindows) {
|
|
6216
|
+
const result = spawnSync('where', ['offckb'], { encoding: 'utf8' });
|
|
6217
|
+
offckbPath = result.stdout.trim().split('\n')[0];
|
|
6218
|
+
}
|
|
6219
|
+
else {
|
|
6220
|
+
const result = spawnSync('which', ['offckb'], { encoding: 'utf8' });
|
|
6221
|
+
offckbPath = result.stdout.trim();
|
|
6222
|
+
}
|
|
6223
|
+
if (!offckbPath) {
|
|
6224
|
+
logger_1.logger.error('❌ Could not find offckb binary. Please ensure offckb is installed and in your PATH.');
|
|
6225
|
+
process.exit(1);
|
|
6226
|
+
}
|
|
6227
|
+
// Get the directory where offckb is located
|
|
6228
|
+
const offckbDir = path.dirname(offckbPath);
|
|
6229
|
+
const targetPath = path.join(offckbDir, binName);
|
|
6230
|
+
// Create the binary content
|
|
6231
|
+
let binContent;
|
|
6232
|
+
if (isWindows) {
|
|
6233
|
+
// Windows batch file
|
|
6234
|
+
binContent = `@echo off
|
|
6235
|
+
offckb debugger %*`;
|
|
6236
|
+
}
|
|
6237
|
+
else {
|
|
6238
|
+
// Unix shell script
|
|
6239
|
+
binContent = `#!/bin/sh
|
|
6240
|
+
exec offckb debugger "$@"`;
|
|
6241
|
+
}
|
|
6242
|
+
try {
|
|
6243
|
+
// Ensure directory exists
|
|
6244
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
6245
|
+
// Write the binary
|
|
6246
|
+
fs.writeFileSync(targetPath, binContent);
|
|
6247
|
+
// Make executable on Unix systems
|
|
6248
|
+
if (!isWindows) {
|
|
6249
|
+
fs.chmodSync(targetPath, '755');
|
|
6250
|
+
}
|
|
6251
|
+
logger_1.logger.info(`✅ Created ckb-debugger fallback at: ${targetPath}`);
|
|
6252
|
+
logger_1.logger.info(` This fallback uses WASM and calls: offckb debugger [args]`);
|
|
6253
|
+
logger_1.logger.info(` For better performance, install the real binary: cargo install --git https://github.com/nervosnetwork/ckb-standalone-debugger ckb-debugger`);
|
|
6254
|
+
logger_1.logger.info(` To uninstall the fallback binary: rm ${targetPath}`);
|
|
6255
|
+
}
|
|
6256
|
+
catch (error) {
|
|
6257
|
+
logger_1.logger.error(`❌ Failed to create ckb-debugger fallback: ${error.message}`);
|
|
6258
|
+
logger_1.logger.error(` Make sure you have write permissions to: ${path.dirname(targetPath)}`);
|
|
6259
|
+
process.exit(1);
|
|
6260
|
+
}
|
|
6261
|
+
}
|
|
6262
|
+
// Additional convenience methods that work with both native binary CLI and WASM
|
|
6263
|
+
static runWithArgs(args) {
|
|
6264
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
6265
|
+
yield this.execute(args);
|
|
6266
|
+
});
|
|
6267
|
+
}
|
|
6268
|
+
static version() {
|
|
6269
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
6270
|
+
if (this.shouldUseWasm()) {
|
|
6271
|
+
const result = yield this.getWasmDebugger().run(['--version']);
|
|
6272
|
+
return result;
|
|
6273
|
+
}
|
|
6274
|
+
else {
|
|
6275
|
+
const result = (0, child_process_1.spawnSync)('ckb-debugger', ['--version'], { encoding: 'utf8' });
|
|
6276
|
+
return {
|
|
6277
|
+
exitCode: result.status || 0,
|
|
6278
|
+
output: result.stdout,
|
|
6279
|
+
error: result.stderr,
|
|
6280
|
+
};
|
|
6281
|
+
}
|
|
6282
|
+
});
|
|
6283
|
+
}
|
|
6284
|
+
}
|
|
6285
|
+
exports.CKBDebugger = CKBDebugger;
|
|
6286
|
+
CKBDebugger.wasmDebugger = null;
|
|
6287
|
+
|
|
6288
|
+
|
|
6289
|
+
/***/ }),
|
|
6290
|
+
|
|
6291
|
+
/***/ 7020:
|
|
6292
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
6293
|
+
|
|
6294
|
+
"use strict";
|
|
6295
|
+
|
|
6296
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6297
|
+
if (k2 === undefined) k2 = k;
|
|
6298
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6299
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6300
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
6301
|
+
}
|
|
6302
|
+
Object.defineProperty(o, k2, desc);
|
|
6303
|
+
}) : (function(o, m, k, k2) {
|
|
6304
|
+
if (k2 === undefined) k2 = k;
|
|
6305
|
+
o[k2] = m[k];
|
|
6306
|
+
}));
|
|
6307
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
6308
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
6309
|
+
}) : function(o, v) {
|
|
6310
|
+
o["default"] = v;
|
|
6311
|
+
});
|
|
6312
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
6313
|
+
var ownKeys = function(o) {
|
|
6314
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
6315
|
+
var ar = [];
|
|
6316
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
6317
|
+
return ar;
|
|
6318
|
+
};
|
|
6319
|
+
return ownKeys(o);
|
|
6320
|
+
};
|
|
6321
|
+
return function (mod) {
|
|
6322
|
+
if (mod && mod.__esModule) return mod;
|
|
6323
|
+
var result = {};
|
|
6324
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
6325
|
+
__setModuleDefault(result, mod);
|
|
6326
|
+
return result;
|
|
6327
|
+
};
|
|
6328
|
+
})();
|
|
6329
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6330
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5114
6331
|
};
|
|
5115
6332
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
5116
|
-
exports.
|
|
6333
|
+
exports.CKBTui = void 0;
|
|
5117
6334
|
const child_process_1 = __nccwpck_require__(35317);
|
|
5118
6335
|
const path = __importStar(__nccwpck_require__(16928));
|
|
6336
|
+
const fs = __importStar(__nccwpck_require__(79896));
|
|
6337
|
+
const os = __importStar(__nccwpck_require__(70857));
|
|
6338
|
+
const crypto = __importStar(__nccwpck_require__(76982));
|
|
6339
|
+
const adm_zip_1 = __importDefault(__nccwpck_require__(83746));
|
|
5119
6340
|
const setting_1 = __nccwpck_require__(25546);
|
|
5120
|
-
const ckb_debugger_wasm_1 = __nccwpck_require__(52948);
|
|
5121
6341
|
const logger_1 = __nccwpck_require__(65370);
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
6342
|
+
const fs_1 = __nccwpck_require__(37293);
|
|
6343
|
+
const DOWNLOAD_TIMEOUT_MS = 120000;
|
|
6344
|
+
const EXTRACT_TIMEOUT_MS = 60000;
|
|
6345
|
+
// Strict semver regex: v<major>.<minor>.<patch> (no leading zeros on digits)
|
|
6346
|
+
const STRICT_VERSION_REGEX = /^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
6347
|
+
class CKBTui {
|
|
6348
|
+
/**
|
|
6349
|
+
* Pure lookup — returns the expected binary path without triggering any
|
|
6350
|
+
* download or installation side effects. May return null if not yet computed.
|
|
6351
|
+
*/
|
|
6352
|
+
static getBinaryPath() {
|
|
6353
|
+
if (!this.binaryPath) {
|
|
6354
|
+
const settings = (0, setting_1.readSettings)();
|
|
6355
|
+
const binDir = this.resolveAndValidateBinDir(settings.tools.rootFolder);
|
|
6356
|
+
const binaryName = process.platform === 'win32' ? 'ckb-tui.exe' : 'ckb-tui';
|
|
6357
|
+
this.binaryPath = path.join(binDir, binaryName);
|
|
5130
6358
|
}
|
|
5131
|
-
return this.
|
|
6359
|
+
return this.binaryPath;
|
|
5132
6360
|
}
|
|
5133
6361
|
/**
|
|
5134
|
-
*
|
|
5135
|
-
*
|
|
6362
|
+
* Returns the binary path, downloading and installing if the binary
|
|
6363
|
+
* does not already exist.
|
|
5136
6364
|
*/
|
|
5137
|
-
static
|
|
5138
|
-
|
|
5139
|
-
if (
|
|
5140
|
-
|
|
5141
|
-
return true;
|
|
6365
|
+
static ensureInstalled() {
|
|
6366
|
+
const binaryPath = this.getBinaryPath();
|
|
6367
|
+
if (binaryPath && fs.existsSync(binaryPath)) {
|
|
6368
|
+
return binaryPath;
|
|
5142
6369
|
}
|
|
5143
|
-
//
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
}
|
|
5148
|
-
return false;
|
|
6370
|
+
// Reset and re-install
|
|
6371
|
+
this.binaryPath = null;
|
|
6372
|
+
this.installSync();
|
|
6373
|
+
return this.binaryPath;
|
|
5149
6374
|
}
|
|
5150
|
-
static
|
|
5151
|
-
|
|
5152
|
-
|
|
6375
|
+
static isInstalled() {
|
|
6376
|
+
try {
|
|
6377
|
+
const binPath = this.getBinaryPath();
|
|
6378
|
+
return binPath !== null && fs.existsSync(binPath);
|
|
5153
6379
|
}
|
|
5154
|
-
|
|
5155
|
-
logger_1.logger.debug('Using native ckb-debugger (better performance)');
|
|
6380
|
+
catch (_a) {
|
|
5156
6381
|
return false;
|
|
5157
6382
|
}
|
|
5158
|
-
else {
|
|
5159
|
-
logger_1.logger.debug('Native ckb-debugger not available, falling back to WASM version');
|
|
5160
|
-
return true;
|
|
5161
|
-
}
|
|
5162
|
-
}
|
|
5163
|
-
static execute(args) {
|
|
5164
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
5165
|
-
if (this.shouldUseWasm()) {
|
|
5166
|
-
try {
|
|
5167
|
-
const result = yield this.getWasmDebugger().run(args);
|
|
5168
|
-
if (result.exitCode !== 0) {
|
|
5169
|
-
process.exit(result.exitCode);
|
|
5170
|
-
}
|
|
5171
|
-
}
|
|
5172
|
-
catch (error) {
|
|
5173
|
-
logger_1.logger.error('WASM debugger execution failed:', error);
|
|
5174
|
-
process.exit(1);
|
|
5175
|
-
}
|
|
5176
|
-
}
|
|
5177
|
-
else {
|
|
5178
|
-
const command = `ckb-debugger ${args.join(' ')}`;
|
|
5179
|
-
(0, child_process_1.execSync)(command, { stdio: 'inherit' });
|
|
5180
|
-
}
|
|
5181
|
-
});
|
|
5182
6383
|
}
|
|
5183
|
-
static
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
yield this.execute(args);
|
|
5187
|
-
});
|
|
6384
|
+
static run(args = []) {
|
|
6385
|
+
const binaryPath = this.ensureInstalled();
|
|
6386
|
+
return (0, child_process_1.spawnSync)(binaryPath, args, { stdio: 'inherit' });
|
|
5188
6387
|
}
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
}
|
|
6388
|
+
// --- private helpers ---
|
|
6389
|
+
/**
|
|
6390
|
+
* Resolve and validate that the configured rootFolder is under the
|
|
6391
|
+
* OffCKB data directory. Rejects paths that resolve outside.
|
|
6392
|
+
*/
|
|
6393
|
+
static resolveAndValidateBinDir(configuredRoot) {
|
|
6394
|
+
const resolved = path.resolve(configuredRoot);
|
|
6395
|
+
const resolvedData = path.resolve(setting_1.dataPath);
|
|
6396
|
+
// Require the resolved path to be within the resolved data directory
|
|
6397
|
+
const relative = path.relative(resolvedData, resolved);
|
|
6398
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
6399
|
+
throw new Error(`tools.rootFolder ("${configuredRoot}") resolves outside the OffCKB data directory ` +
|
|
6400
|
+
`("${resolvedData}"). For security, tool binaries must be stored under the data path.`);
|
|
6401
|
+
}
|
|
6402
|
+
return resolved;
|
|
5203
6403
|
}
|
|
5204
|
-
static
|
|
5205
|
-
|
|
5206
|
-
|
|
6404
|
+
static validateVersion(version) {
|
|
6405
|
+
if (!STRICT_VERSION_REGEX.test(version)) {
|
|
6406
|
+
throw new Error(`Invalid version format: "${version}". Expected format: vX.Y.Z (e.g., v0.1.3)`);
|
|
6407
|
+
}
|
|
5207
6408
|
}
|
|
5208
|
-
static
|
|
5209
|
-
const
|
|
5210
|
-
|
|
5211
|
-
|
|
6409
|
+
static getAssetName() {
|
|
6410
|
+
const platform = process.platform;
|
|
6411
|
+
const arch = process.arch;
|
|
6412
|
+
if (platform === 'darwin') {
|
|
6413
|
+
if (arch !== 'arm64') {
|
|
6414
|
+
throw new Error(`Unsupported architecture for macOS: ${arch}. Only Apple Silicon (arm64) is supported.`);
|
|
6415
|
+
}
|
|
6416
|
+
return 'ckb-tui-with-node-macos-aarch64.tar.gz';
|
|
5212
6417
|
}
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
if (version < settings.tools.ckbDebugger.minVersion) {
|
|
5217
|
-
return false;
|
|
6418
|
+
else if (platform === 'linux') {
|
|
6419
|
+
if (arch !== 'x64') {
|
|
6420
|
+
throw new Error(`Unsupported architecture for Linux: ${arch}. Only x86_64 is supported.`);
|
|
5218
6421
|
}
|
|
5219
|
-
return
|
|
6422
|
+
return 'ckb-tui-with-node-linux-amd64.tar.gz';
|
|
5220
6423
|
}
|
|
5221
|
-
|
|
5222
|
-
|
|
6424
|
+
else if (platform === 'win32') {
|
|
6425
|
+
if (arch !== 'x64') {
|
|
6426
|
+
throw new Error(`Unsupported architecture for Windows: ${arch}. Only x86_64 is supported.`);
|
|
6427
|
+
}
|
|
6428
|
+
return 'ckb-tui-with-node-windows-amd64.zip';
|
|
5223
6429
|
}
|
|
6430
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
5224
6431
|
}
|
|
5225
|
-
|
|
5226
|
-
|
|
6432
|
+
/**
|
|
6433
|
+
* Synchronously download and install the ckb-tui binary.
|
|
6434
|
+
* Uses spawnSync with array arguments (no shell interpolation) for security.
|
|
6435
|
+
*/
|
|
6436
|
+
static installSync() {
|
|
6437
|
+
const settings = (0, setting_1.readSettings)();
|
|
6438
|
+
const version = settings.tools.ckbTui.version;
|
|
6439
|
+
this.validateVersion(version);
|
|
6440
|
+
const assetName = this.getAssetName();
|
|
6441
|
+
const binDir = this.resolveAndValidateBinDir(settings.tools.rootFolder);
|
|
6442
|
+
const binaryName = process.platform === 'win32' ? 'ckb-tui.exe' : 'ckb-tui';
|
|
6443
|
+
this.binaryPath = path.join(binDir, binaryName);
|
|
6444
|
+
const downloadUrl = `https://github.com/Officeyutong/ckb-tui/releases/download/${version}/${assetName}`;
|
|
6445
|
+
// Ensure the target directory exists
|
|
6446
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
6447
|
+
// Use a temp directory for atomic download & extraction
|
|
6448
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'offckb-ckb-tui-'));
|
|
6449
|
+
const archivePath = path.join(tempDir, assetName);
|
|
5227
6450
|
try {
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
6451
|
+
// 1. Download
|
|
6452
|
+
logger_1.logger.info(`Downloading ckb-tui from ${downloadUrl}...`);
|
|
6453
|
+
const curlResult = (0, child_process_1.spawnSync)('curl', ['-fsSL', '--max-time', '300', '-o', archivePath, downloadUrl], {
|
|
6454
|
+
stdio: 'inherit',
|
|
6455
|
+
timeout: DOWNLOAD_TIMEOUT_MS,
|
|
6456
|
+
});
|
|
6457
|
+
if (curlResult.error) {
|
|
6458
|
+
throw new Error(`Failed to download ckb-tui: ${curlResult.error.message}`);
|
|
6459
|
+
}
|
|
6460
|
+
if (curlResult.status !== 0) {
|
|
6461
|
+
throw new Error(`curl exited with code ${curlResult.status}`);
|
|
6462
|
+
}
|
|
6463
|
+
// 2. Verify checksum (best-effort: warns if checksum file is unavailable)
|
|
6464
|
+
this.verifyChecksum(version, assetName, archivePath);
|
|
6465
|
+
// 3. Extract to temp directory
|
|
6466
|
+
logger_1.logger.info('Extracting...');
|
|
6467
|
+
const extractDir = path.join(tempDir, 'extracted');
|
|
6468
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
6469
|
+
this.extractArchive(archivePath, extractDir);
|
|
6470
|
+
// 4. Locate the extracted binary
|
|
6471
|
+
const extractedBinary = (0, fs_1.findFileInFolder)(extractDir, binaryName);
|
|
6472
|
+
if (!extractedBinary) {
|
|
6473
|
+
throw new Error(`ckb-tui binary ("${binaryName}") was not found after extraction.`);
|
|
6474
|
+
}
|
|
6475
|
+
// 5. Atomically move to the final location
|
|
6476
|
+
fs.renameSync(extractedBinary, this.binaryPath);
|
|
6477
|
+
// 6. Make executable on Unix
|
|
6478
|
+
if (process.platform !== 'win32') {
|
|
6479
|
+
fs.chmodSync(this.binaryPath, 0o755);
|
|
6480
|
+
}
|
|
6481
|
+
logger_1.logger.info('ckb-tui installed successfully.');
|
|
5231
6482
|
}
|
|
5232
6483
|
catch (error) {
|
|
5233
|
-
|
|
5234
|
-
|
|
6484
|
+
// Reset cached path on failure so a subsequent call retries
|
|
6485
|
+
this.binaryPath = null;
|
|
6486
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6487
|
+
logger_1.logger.error('Failed to download/install ckb-tui:', message, '\nPlease check your network connectivity, verify that the specified version exists in the releases, ' +
|
|
6488
|
+
'and ensure you have sufficient file system permissions.');
|
|
6489
|
+
throw error;
|
|
6490
|
+
}
|
|
6491
|
+
finally {
|
|
6492
|
+
// Clean up the temp directory
|
|
6493
|
+
try {
|
|
6494
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
6495
|
+
}
|
|
6496
|
+
catch (_a) {
|
|
6497
|
+
// Best-effort cleanup — temp dir will be cleaned by the OS eventually
|
|
6498
|
+
}
|
|
5235
6499
|
}
|
|
5236
6500
|
}
|
|
5237
6501
|
/**
|
|
5238
|
-
*
|
|
5239
|
-
*
|
|
5240
|
-
*
|
|
5241
|
-
*
|
|
6502
|
+
* Best-effort SHA-256 checksum verification.
|
|
6503
|
+
* Downloads the checksum file published alongside the release asset and
|
|
6504
|
+
* verifies the downloaded archive. Logs a warning (but does not fail) if
|
|
6505
|
+
* the checksum file is unavailable — this maintains compatibility while
|
|
6506
|
+
* the upstream project adopts checksum publishing.
|
|
5242
6507
|
*/
|
|
5243
|
-
static
|
|
5244
|
-
const
|
|
5245
|
-
const
|
|
5246
|
-
const
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
if (
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
else {
|
|
5255
|
-
const result = spawnSync('which', ['offckb'], { encoding: 'utf8' });
|
|
5256
|
-
offckbPath = result.stdout.trim();
|
|
5257
|
-
}
|
|
5258
|
-
if (!offckbPath) {
|
|
5259
|
-
logger_1.logger.error('❌ Could not find offckb binary. Please ensure offckb is installed and in your PATH.');
|
|
5260
|
-
process.exit(1);
|
|
5261
|
-
}
|
|
5262
|
-
// Get the directory where offckb is located
|
|
5263
|
-
const offckbDir = path.dirname(offckbPath);
|
|
5264
|
-
const targetPath = path.join(offckbDir, binName);
|
|
5265
|
-
// Create the binary content
|
|
5266
|
-
let binContent;
|
|
5267
|
-
if (isWindows) {
|
|
5268
|
-
// Windows batch file
|
|
5269
|
-
binContent = `@echo off
|
|
5270
|
-
offckb debugger %*`;
|
|
5271
|
-
}
|
|
5272
|
-
else {
|
|
5273
|
-
// Unix shell script
|
|
5274
|
-
binContent = `#!/bin/sh
|
|
5275
|
-
exec offckb debugger "$@"`;
|
|
6508
|
+
static verifyChecksum(version, assetName, archivePath) {
|
|
6509
|
+
const checksumUrl = `https://github.com/Officeyutong/ckb-tui/releases/download/${version}/checksums-sha256.txt`;
|
|
6510
|
+
const checksumPath = path.join(path.dirname(archivePath), 'checksums-sha256.txt');
|
|
6511
|
+
const fetchResult = (0, child_process_1.spawnSync)('curl', ['-fsSL', '--max-time', '30', '-o', checksumPath, checksumUrl], {
|
|
6512
|
+
stdio: 'pipe',
|
|
6513
|
+
timeout: 30000,
|
|
6514
|
+
});
|
|
6515
|
+
if (fetchResult.status !== 0) {
|
|
6516
|
+
logger_1.logger.warn(`SHA-256 checksum file not available for version ${version}. ` +
|
|
6517
|
+
'Skipping integrity verification. Consider asking the upstream maintainer to publish checksum files.');
|
|
6518
|
+
return;
|
|
5276
6519
|
}
|
|
5277
6520
|
try {
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
if (!isWindows) {
|
|
5284
|
-
fs.chmodSync(targetPath, '755');
|
|
6521
|
+
const checksumContent = fs.readFileSync(checksumPath, 'utf8');
|
|
6522
|
+
const expectedHash = this.parseChecksumFile(checksumContent, assetName);
|
|
6523
|
+
if (!expectedHash) {
|
|
6524
|
+
logger_1.logger.warn(`Checksum entry for "${assetName}" not found in checksums file. Skipping verification.`);
|
|
6525
|
+
return;
|
|
5285
6526
|
}
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
6527
|
+
const actualHash = crypto.createHash('sha256').update(fs.readFileSync(archivePath)).digest('hex');
|
|
6528
|
+
if (actualHash !== expectedHash) {
|
|
6529
|
+
throw new Error(`SHA-256 checksum mismatch for ${assetName}.\n` +
|
|
6530
|
+
`Expected: ${expectedHash}\nActual: ${actualHash}\n` +
|
|
6531
|
+
'The downloaded file may be corrupted or tampered with.');
|
|
6532
|
+
}
|
|
6533
|
+
logger_1.logger.info('SHA-256 checksum verified successfully.');
|
|
5290
6534
|
}
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
6535
|
+
finally {
|
|
6536
|
+
try {
|
|
6537
|
+
fs.unlinkSync(checksumPath);
|
|
6538
|
+
}
|
|
6539
|
+
catch (_a) {
|
|
6540
|
+
// Best effort
|
|
6541
|
+
}
|
|
5295
6542
|
}
|
|
5296
6543
|
}
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
6544
|
+
/**
|
|
6545
|
+
* Parse a standard SHA-256 checksum file (format: "<hash> <filename>" per line)
|
|
6546
|
+
* and return the hex hash for the given asset name, or null if not found.
|
|
6547
|
+
*/
|
|
6548
|
+
static parseChecksumFile(content, assetName) {
|
|
6549
|
+
for (const line of content.split('\n')) {
|
|
6550
|
+
const trimmed = line.trim();
|
|
6551
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
6552
|
+
continue;
|
|
6553
|
+
const match = trimmed.match(/^([0-9a-fA-F]{64})\s+[*]?(.+)$/);
|
|
6554
|
+
if (match && match[2] === assetName) {
|
|
6555
|
+
return match[1].toLowerCase();
|
|
6556
|
+
}
|
|
6557
|
+
}
|
|
6558
|
+
return null;
|
|
5302
6559
|
}
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
6560
|
+
/**
|
|
6561
|
+
* Extract a downloaded archive to the given directory.
|
|
6562
|
+
* Uses AdmZip for .zip files (Node-native, no shell) and spawnSync with array
|
|
6563
|
+
* arguments for .tar.gz (no shell interpolation).
|
|
6564
|
+
*/
|
|
6565
|
+
static extractArchive(archivePath, extractDir) {
|
|
6566
|
+
if (archivePath.endsWith('.tar.gz')) {
|
|
6567
|
+
const result = (0, child_process_1.spawnSync)('tar', ['-xzf', archivePath, '-C', extractDir], {
|
|
6568
|
+
stdio: 'inherit',
|
|
6569
|
+
timeout: EXTRACT_TIMEOUT_MS,
|
|
6570
|
+
});
|
|
6571
|
+
if (result.error) {
|
|
6572
|
+
throw new Error(`tar extraction failed: ${result.error.message}`);
|
|
5308
6573
|
}
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
return {
|
|
5312
|
-
exitCode: result.status || 0,
|
|
5313
|
-
output: result.stdout,
|
|
5314
|
-
error: result.stderr,
|
|
5315
|
-
};
|
|
6574
|
+
if (result.status !== 0) {
|
|
6575
|
+
throw new Error(`tar exited with code ${result.status}`);
|
|
5316
6576
|
}
|
|
5317
|
-
}
|
|
6577
|
+
}
|
|
6578
|
+
else if (archivePath.endsWith('.zip')) {
|
|
6579
|
+
try {
|
|
6580
|
+
const zip = new adm_zip_1.default(archivePath);
|
|
6581
|
+
zip.extractAllTo(extractDir, true);
|
|
6582
|
+
}
|
|
6583
|
+
catch (error) {
|
|
6584
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6585
|
+
throw new Error(`ZIP extraction failed: ${message}`);
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6588
|
+
else {
|
|
6589
|
+
throw new Error(`Unsupported archive format: ${path.extname(archivePath)}`);
|
|
6590
|
+
}
|
|
5318
6591
|
}
|
|
5319
6592
|
}
|
|
5320
|
-
exports.
|
|
5321
|
-
|
|
6593
|
+
exports.CKBTui = CKBTui;
|
|
6594
|
+
CKBTui.binaryPath = null;
|
|
5322
6595
|
|
|
5323
6596
|
|
|
5324
6597
|
/***/ }),
|
|
@@ -7749,15 +9022,25 @@ function getSubfolders(folderPath) {
|
|
|
7749
9022
|
/***/ }),
|
|
7750
9023
|
|
|
7751
9024
|
/***/ 27814:
|
|
7752
|
-
/***/ ((__unused_webpack_module, exports) => {
|
|
9025
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
7753
9026
|
|
|
7754
9027
|
"use strict";
|
|
7755
9028
|
|
|
7756
9029
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
7757
9030
|
exports.buildTestnetTxLink = buildTestnetTxLink;
|
|
9031
|
+
exports.logTxSuccess = logTxSuccess;
|
|
9032
|
+
const logger_1 = __nccwpck_require__(65370);
|
|
7758
9033
|
function buildTestnetTxLink(txHash) {
|
|
7759
9034
|
return `https://pudge.explorer.nervos.org/transaction/${txHash}`;
|
|
7760
9035
|
}
|
|
9036
|
+
function logTxSuccess(network, txHash, action) {
|
|
9037
|
+
if (network === 'testnet') {
|
|
9038
|
+
logger_1.logger.info(`Successfully ${action}, check ${buildTestnetTxLink(txHash)} for details.`);
|
|
9039
|
+
}
|
|
9040
|
+
else {
|
|
9041
|
+
logger_1.logger.info(`Successfully ${action}, txHash:`, txHash);
|
|
9042
|
+
}
|
|
9043
|
+
}
|
|
7761
9044
|
|
|
7762
9045
|
|
|
7763
9046
|
/***/ }),
|
|
@@ -7819,6 +9102,7 @@ class UnifiedLogger {
|
|
|
7819
9102
|
constructor(options = {}) {
|
|
7820
9103
|
this.enableColors = options.enableColors !== false;
|
|
7821
9104
|
this.showLevel = options.showLevel !== false;
|
|
9105
|
+
this.jsonMode = options.jsonMode === true;
|
|
7822
9106
|
// Create Winston logger with custom format and levels
|
|
7823
9107
|
this.logger = winston_1.default.createLogger({
|
|
7824
9108
|
level: options.level || node_process_1.default.env.LOG_LEVEL || 'info',
|
|
@@ -7832,17 +9116,33 @@ class UnifiedLogger {
|
|
|
7832
9116
|
format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.errors({ stack: true }), winston_1.default.format.printf(({ level, message, timestamp }) => {
|
|
7833
9117
|
return this.formatMessage(level, message, timestamp);
|
|
7834
9118
|
})),
|
|
7835
|
-
transports: [
|
|
9119
|
+
transports: options.transports || [
|
|
7836
9120
|
new winston_1.default.transports.Console({
|
|
7837
9121
|
stderrLevels: ['error', 'warn'],
|
|
7838
9122
|
}),
|
|
7839
9123
|
],
|
|
7840
9124
|
});
|
|
7841
9125
|
}
|
|
9126
|
+
/**
|
|
9127
|
+
* Toggle JSON output mode. When enabled, every log line is emitted as a
|
|
9128
|
+
* structured JSON object, which is easier for agents and scripts to parse.
|
|
9129
|
+
*/
|
|
9130
|
+
setJsonMode(enabled) {
|
|
9131
|
+
this.jsonMode = enabled;
|
|
9132
|
+
}
|
|
7842
9133
|
/**
|
|
7843
9134
|
* Format the message with appropriate colors and structure
|
|
7844
9135
|
*/
|
|
7845
|
-
formatMessage(level, message,
|
|
9136
|
+
formatMessage(level, message, timestamp) {
|
|
9137
|
+
// Agent-friendly JSON output: one JSON object per log line
|
|
9138
|
+
if (this.jsonMode) {
|
|
9139
|
+
const normalizedMessage = Array.isArray(message) ? message.join('\n') : String(message);
|
|
9140
|
+
return JSON.stringify({
|
|
9141
|
+
level,
|
|
9142
|
+
message: normalizedMessage,
|
|
9143
|
+
timestamp,
|
|
9144
|
+
});
|
|
9145
|
+
}
|
|
7846
9146
|
// If showLevel is false, return just the message
|
|
7847
9147
|
if (!this.showLevel) {
|
|
7848
9148
|
if (Array.isArray(message)) {
|
|
@@ -7925,6 +9225,12 @@ class UnifiedLogger {
|
|
|
7925
9225
|
* Log a message with the specified level
|
|
7926
9226
|
*/
|
|
7927
9227
|
log(level, message) {
|
|
9228
|
+
// In JSON mode, emit multi-line messages as a single structured log entry
|
|
9229
|
+
// so agents can parse one complete JSON object per line.
|
|
9230
|
+
if (this.jsonMode && Array.isArray(message)) {
|
|
9231
|
+
this.logger.log(level, message.join('\n'));
|
|
9232
|
+
return;
|
|
9233
|
+
}
|
|
7928
9234
|
if (Array.isArray(message)) {
|
|
7929
9235
|
message.forEach((line) => this.logger.log(level, line));
|
|
7930
9236
|
}
|
|
@@ -8091,6 +9397,11 @@ exports.isValidNetworkString = isValidNetworkString;
|
|
|
8091
9397
|
exports.validateNetworkOpt = validateNetworkOpt;
|
|
8092
9398
|
exports.isValidVersion = isValidVersion;
|
|
8093
9399
|
exports.normalizePrivKey = normalizePrivKey;
|
|
9400
|
+
exports.isValidUdtKind = isValidUdtKind;
|
|
9401
|
+
exports.validateUdtKind = validateUdtKind;
|
|
9402
|
+
exports.validateUdtAmount = validateUdtAmount;
|
|
9403
|
+
exports.validateHexString = validateHexString;
|
|
9404
|
+
exports.validateUdtTypeArgs = validateUdtTypeArgs;
|
|
8094
9405
|
const path_1 = __importDefault(__nccwpck_require__(16928));
|
|
8095
9406
|
const fs_1 = __importDefault(__nccwpck_require__(79896));
|
|
8096
9407
|
const base_1 = __nccwpck_require__(69951);
|
|
@@ -8179,6 +9490,46 @@ function normalizePrivKey(privKey) {
|
|
|
8179
9490
|
// Return the formally strictly padded ckb format `0x` string
|
|
8180
9491
|
return '0x' + key;
|
|
8181
9492
|
}
|
|
9493
|
+
function isValidUdtKind(kind) {
|
|
9494
|
+
return kind === 'sudt' || kind === 'xudt';
|
|
9495
|
+
}
|
|
9496
|
+
function validateUdtKind(kind) {
|
|
9497
|
+
if (!kind) {
|
|
9498
|
+
throw new Error('UDT kind is required');
|
|
9499
|
+
}
|
|
9500
|
+
if (!isValidUdtKind(kind)) {
|
|
9501
|
+
throw new Error(`invalid UDT kind "${kind}", must be "sudt" or "xudt"`);
|
|
9502
|
+
}
|
|
9503
|
+
}
|
|
9504
|
+
const U128_MAX = (BigInt(1) << BigInt(128)) - BigInt(1);
|
|
9505
|
+
function validateUdtAmount(amount) {
|
|
9506
|
+
if (!/^\d+$/.test(amount)) {
|
|
9507
|
+
throw new Error(`invalid UDT amount "${amount}", must be a non-negative decimal integer`);
|
|
9508
|
+
}
|
|
9509
|
+
const value = BigInt(amount);
|
|
9510
|
+
if (value > U128_MAX) {
|
|
9511
|
+
throw new Error(`UDT amount exceeds 128-bit max: ${amount}`);
|
|
9512
|
+
}
|
|
9513
|
+
return value;
|
|
9514
|
+
}
|
|
9515
|
+
const HEX_REGEX = /^0x[0-9a-fA-F]*$/;
|
|
9516
|
+
function validateHexString(value, name) {
|
|
9517
|
+
if (!value || !HEX_REGEX.test(value)) {
|
|
9518
|
+
throw new Error(`invalid ${name} "${value}", must be a hex string starting with 0x`);
|
|
9519
|
+
}
|
|
9520
|
+
return value;
|
|
9521
|
+
}
|
|
9522
|
+
function validateUdtTypeArgs(kind, typeArgs) {
|
|
9523
|
+
const hex = validateHexString(typeArgs, 'type args');
|
|
9524
|
+
const byteLength = (hex.length - 2) / 2;
|
|
9525
|
+
if (kind === 'sudt' && byteLength !== 20) {
|
|
9526
|
+
throw new Error(`invalid SUDT type args length: expected 20 bytes, got ${byteLength}`);
|
|
9527
|
+
}
|
|
9528
|
+
if (kind === 'xudt' && byteLength !== 32) {
|
|
9529
|
+
throw new Error(`invalid xUDT type args length: expected 32 bytes, got ${byteLength}`);
|
|
9530
|
+
}
|
|
9531
|
+
return hex;
|
|
9532
|
+
}
|
|
8182
9533
|
|
|
8183
9534
|
|
|
8184
9535
|
/***/ }),
|
|
@@ -128150,7 +129501,7 @@ module.exports = {"version":"3.17.0"};
|
|
|
128150
129501
|
/***/ ((module) => {
|
|
128151
129502
|
|
|
128152
129503
|
"use strict";
|
|
128153
|
-
module.exports = /*#__PURE__*/JSON.parse('{"rE":"0.4.
|
|
129504
|
+
module.exports = /*#__PURE__*/JSON.parse('{"rE":"0.4.9-canary-2b6b3af.0","h_":"ckb development network for your first try"}');
|
|
128154
129505
|
|
|
128155
129506
|
/***/ })
|
|
128156
129507
|
|