@utexo/rgb-sdk 1.0.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENCE +201 -0
  2. package/Readme.md +480 -0
  3. package/cli/README.md +348 -0
  4. package/cli/commands/address.mjs +16 -0
  5. package/cli/commands/blindreceive.mjs +15 -0
  6. package/cli/commands/btcbalance.mjs +11 -0
  7. package/cli/commands/createlightninginvoice.mjs +14 -0
  8. package/cli/commands/createutxos.mjs +13 -0
  9. package/cli/commands/decodergbinvoice.mjs +9 -0
  10. package/cli/commands/generate_keys.mjs +35 -0
  11. package/cli/commands/getlightningreceiverequest.mjs +10 -0
  12. package/cli/commands/getlightningsendrequest.mjs +10 -0
  13. package/cli/commands/getonchainsendstatus.mjs +20 -0
  14. package/cli/commands/listassets.mjs +11 -0
  15. package/cli/commands/listtransfers.mjs +10 -0
  16. package/cli/commands/listunspents.mjs +10 -0
  17. package/cli/commands/onchainreceive.mjs +16 -0
  18. package/cli/commands/onchainsend.mjs +11 -0
  19. package/cli/commands/onchainsendbegin.mjs +9 -0
  20. package/cli/commands/onchainsendend.mjs +9 -0
  21. package/cli/commands/paylightninginvoice.mjs +11 -0
  22. package/cli/commands/paylightninginvoicebegin.mjs +10 -0
  23. package/cli/commands/paylightninginvoiceend.mjs +9 -0
  24. package/cli/commands/refresh.mjs +9 -0
  25. package/cli/commands/send.mjs +31 -0
  26. package/cli/commands/sign-psbt.mjs +12 -0
  27. package/cli/commands/signpsbt.mjs +10 -0
  28. package/cli/commands/witnessreceive.mjs +15 -0
  29. package/cli/data/stage2-receiver.example.json +11 -0
  30. package/cli/data/stage2-sender.example.json +11 -0
  31. package/cli/generate_keys.mjs +66 -0
  32. package/cli/run.mjs +308 -0
  33. package/cli/utils.mjs +220 -0
  34. package/dist/index.cjs +1282 -0
  35. package/dist/index.cjs.map +1 -0
  36. package/dist/index.d.mts +163 -0
  37. package/dist/index.d.ts +163 -0
  38. package/dist/index.mjs +1018 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/package.json +124 -0
@@ -0,0 +1,31 @@
1
+ import { parseFlags, runWithWallet } from '../utils.mjs';
2
+
3
+ export async function run(walletName, flagArgs, options = {}) {
4
+ const opts = parseFlags(flagArgs, {
5
+ required: ['invoice'],
6
+ optional: ['assetId', 'amount', 'mnemonic', 'feeRate', 'minConfirmations', 'witnessData'],
7
+ }, { usage: options.usage });
8
+ await runWithWallet(walletName, async (wallet, walletConfig) => {
9
+ const mnemonic = opts.mnemonic || walletConfig.mnemonic;
10
+ let witnessData;
11
+ if (opts.witnessData) {
12
+ try {
13
+ witnessData = JSON.parse(opts.witnessData);
14
+ if (typeof witnessData.amountSat !== 'number') witnessData.amountSat = parseInt(witnessData.amountSat, 10);
15
+ if (witnessData.blinding != null && typeof witnessData.blinding !== 'number') witnessData.blinding = parseInt(witnessData.blinding, 10);
16
+ } catch (e) {
17
+ throw new Error('--witnessData must be valid JSON, e.g. \'{"amountSat":1000,"blinding":123}\'');
18
+ }
19
+ }
20
+ const request = {
21
+ invoice: opts.invoice,
22
+ ...(opts.assetId && { assetId: opts.assetId }),
23
+ ...(opts.amount && { amount: parseInt(opts.amount, 10) }),
24
+ ...(opts.feeRate && { feeRate: parseInt(opts.feeRate, 10) }),
25
+ ...(opts.minConfirmations && { minConfirmations: parseInt(opts.minConfirmations, 10) }),
26
+ ...(witnessData && { witnessData }),
27
+ };
28
+ const result = await wallet.send(request, mnemonic);
29
+ console.log(JSON.stringify(result, null, 2));
30
+ }, { quiet: true });
31
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Sign a PSBT with mnemonic + network only. No wallet, no goOnline.
3
+ * Usage: utexo sign-psbt --psbt "<base64>" --network <testnet|mainnet|signet|regtest> --mnemonic "<words>"
4
+ */
5
+ import { parseFlags } from '../utils.mjs';
6
+ import { signPsbt } from '../../dist/index.mjs';
7
+
8
+ export async function run(walletName, flagArgs, options = {}) {
9
+ const opts = parseFlags(flagArgs, { required: ['psbt', 'network', 'mnemonic'], optional: [] }, { usage: options.usage });
10
+ const signed = await signPsbt(opts.mnemonic, opts.psbt, opts.network);
11
+ console.log(signed);
12
+ }
@@ -0,0 +1,10 @@
1
+ import { parseFlags, runWithWallet } from '../utils.mjs';
2
+
3
+ export async function run(walletName, flagArgs, options = {}) {
4
+ const opts = parseFlags(flagArgs, { required: ['psbt'], optional: ['mnemonic'] }, { usage: options.usage });
5
+ await runWithWallet(walletName, async (wallet, walletConfig) => {
6
+ const mnemonic = opts.mnemonic || walletConfig.mnemonic;
7
+ const signed = await wallet.signPsbt(opts.psbt, mnemonic);
8
+ console.log(signed);
9
+ }, { quiet: true });
10
+ }
@@ -0,0 +1,15 @@
1
+ import { parseFlags, runWithWallet } from '../utils.mjs';
2
+
3
+ export async function run(walletName, flagArgs, options = {}) {
4
+ const opts = parseFlags(flagArgs, { required: ['amount'], optional: ['assetId', 'minConfirmations', 'durationSeconds'] }, { usage: options.usage });
5
+ const request = {
6
+ amount: parseInt(opts.amount, 10),
7
+ ...(opts.assetId && { assetId: opts.assetId }),
8
+ ...(opts.minConfirmations && { minConfirmations: parseInt(opts.minConfirmations, 10) }),
9
+ ...(opts.durationSeconds && { durationSeconds: parseInt(opts.durationSeconds, 10) }),
10
+ };
11
+ await runWithWallet(walletName, async (wallet) => {
12
+ const result = await wallet.witnessReceive(request);
13
+ console.log(JSON.stringify(result, null, 2));
14
+ }, { quiet: true });
15
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "walletName": "stage2-receiver",
3
+ "network": "signet",
4
+ "mnemonic": "REPLACE_WITH_12_OR_24_WORD_MNEMONIC",
5
+ "xpub": "REPLACE_WITH_XPUB",
6
+ "accountXpubVanilla": "REPLACE_WITH_ACCOUNT_XPUB_VANILLA",
7
+ "accountXpubColored": "REPLACE_WITH_ACCOUNT_XPUB_COLORED",
8
+ "masterFingerprint": "REPLACE_WITH_FINGERPRINT",
9
+ "xpriv": "REPLACE_WITH_XPRIV",
10
+ "createdAt": "REPLACE_WITH_ISO_TIMESTAMP"
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "walletName": "stage2-sender",
3
+ "network": "signet",
4
+ "mnemonic": "REPLACE_WITH_12_OR_24_WORD_MNEMONIC",
5
+ "xpub": "REPLACE_WITH_XPUB",
6
+ "accountXpubVanilla": "REPLACE_WITH_ACCOUNT_XPUB_VANILLA",
7
+ "accountXpubColored": "REPLACE_WITH_ACCOUNT_XPUB_COLORED",
8
+ "masterFingerprint": "REPLACE_WITH_FINGERPRINT",
9
+ "xpriv": "REPLACE_WITH_XPRIV",
10
+ "createdAt": "REPLACE_WITH_ISO_TIMESTAMP"
11
+ }
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Generate Keys Script
5
+ *
6
+ * Generates new wallet keys and saves them to a JSON file.
7
+ *
8
+ * Usage:
9
+ * node generate_keys.mjs <wallet_name> [network]
10
+ *
11
+ * Examples:
12
+ * node generate_keys.mjs mywallet # Uses default network (regtest)
13
+ * node generate_keys.mjs mywallet testnet # Uses testnet
14
+ */
15
+
16
+ import { generateKeys } from '../dist/index.mjs';
17
+ import { saveWalletConfig, handleError } from './utils.mjs';
18
+
19
+ async function main() {
20
+ const args = process.argv.slice(2);
21
+
22
+ if (args.length === 0) {
23
+ console.error('Usage: node generate_keys.mjs <wallet_name> [network]');
24
+ console.error('Example: node generate_keys.mjs mywallet');
25
+ console.error('Example: node generate_keys.mjs mywallet testnet');
26
+ process.exit(1);
27
+ }
28
+
29
+ const walletName = args[0];
30
+ const network = args[1] || 'regtest';
31
+
32
+ console.log(`Generating keys for wallet: ${walletName}`);
33
+ console.log(`Network: ${network}`);
34
+
35
+ try {
36
+ // Generate keys
37
+ const keys = await generateKeys(network);
38
+
39
+ // Create wallet config object
40
+ const walletConfig = {
41
+ walletName,
42
+ network,
43
+ mnemonic: keys.mnemonic,
44
+ xpub: keys.xpub,
45
+ accountXpubVanilla: keys.accountXpubVanilla,
46
+ accountXpubColored: keys.accountXpubColored,
47
+ masterFingerprint: keys.masterFingerprint,
48
+ xpriv: keys.xpriv,
49
+ createdAt: new Date().toISOString(),
50
+ };
51
+
52
+ // Save to JSON file
53
+ const filepath = saveWalletConfig(walletName, walletConfig);
54
+
55
+ console.log(`\n✅ Keys generated successfully!`);
56
+ console.log(`📁 Saved to: ${filepath}`);
57
+ console.log(`\n⚠️ IMPORTANT: Keep your mnemonic safe and secure!`);
58
+ console.log(` Mnemonic: ${keys.mnemonic}`);
59
+ console.log(`\nYou can now use this wallet with: node getaddress.mjs ${walletName}`);
60
+
61
+ } catch (error) {
62
+ handleError(error, 'generating keys');
63
+ }
64
+ }
65
+
66
+ main();
package/cli/run.mjs ADDED
@@ -0,0 +1,308 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Single entrypoint for UTEXO CLI commands.
5
+ * Usage: utexo <command> <wallet_name> [options...]
6
+ */
7
+
8
+ import { handleError } from './utils.mjs';
9
+ import { run as runAddress } from './commands/address.mjs';
10
+ import { run as runBtcbalance } from './commands/btcbalance.mjs';
11
+ import { run as runListassets } from './commands/listassets.mjs';
12
+ import { run as runListtransfers } from './commands/listtransfers.mjs';
13
+ import { run as runRefresh } from './commands/refresh.mjs';
14
+ import { run as runListunspents } from './commands/listunspents.mjs';
15
+ import { run as runGetOnchainSendStatus } from './commands/getonchainsendstatus.mjs';
16
+ import { run as runDecodergbinvoice } from './commands/decodergbinvoice.mjs';
17
+ import { run as runBlindreceive } from './commands/blindreceive.mjs';
18
+ import { run as runWitnessreceive } from './commands/witnessreceive.mjs';
19
+ import { run as runOnchainreceive } from './commands/onchainreceive.mjs';
20
+ import { run as runCreateutxos } from './commands/createutxos.mjs';
21
+ import { run as runOnchainsendbegin } from './commands/onchainsendbegin.mjs';
22
+ import { run as runSignpsbt } from './commands/signpsbt.mjs';
23
+ import { run as runSignPsbtStandalone } from './commands/sign-psbt.mjs';
24
+ import { run as runOnchainsendend } from './commands/onchainsendend.mjs';
25
+ import { run as runOnchainsend } from './commands/onchainsend.mjs';
26
+ import { run as runSend } from './commands/send.mjs';
27
+ import { run as runCreatelightninginvoice } from './commands/createlightninginvoice.mjs';
28
+ import { run as runPaylightninginvoicebegin } from './commands/paylightninginvoicebegin.mjs';
29
+ import { run as runPaylightninginvoice } from './commands/paylightninginvoice.mjs';
30
+ import { run as runPaylightninginvoiceend } from './commands/paylightninginvoiceend.mjs';
31
+ import { run as runGetlightningsendrequest } from './commands/getlightningsendrequest.mjs';
32
+ import { run as runGetlightningreceiverequest } from './commands/getlightningreceiverequest.mjs';
33
+ import { run as runGenerateKeys } from './commands/generate_keys.mjs';
34
+ import { parseFlags, runWithWalletManager } from './utils.mjs';
35
+
36
+ const args = process.argv.slice(2);
37
+ let command = args[0];
38
+ let walletName = args[1];
39
+ let flagArgs = args.slice(2);
40
+ // sign-psbt: no wallet name, only flags (--psbt --network --mnemonic)
41
+ if (command === 'sign-psbt') {
42
+ walletName = null;
43
+ flagArgs = args.slice(1);
44
+ }
45
+
46
+ // WalletManager subcommands: utexo wm <subcommand> <wallet_name> [flags]
47
+ if (command === 'wm') {
48
+ const wmSubcommand = args[1];
49
+ walletName = args[2];
50
+ flagArgs = args.slice(3);
51
+ if (!wmSubcommand || !['address', 'btcbalance', 'refresh', 'sync', 'createutxos', 'blindreceive', 'listassets', 'listtransfers', 'sendbatch', 'sendbtc'].includes(wmSubcommand)) {
52
+ console.error('Usage: utexo wm <address|btcbalance|refresh|sync|createutxos|blindreceive|listassets|listtransfers|sendbatch|sendbtc> <wallet_name> [options...]');
53
+ process.exit(1);
54
+ }
55
+ command = `wm_${wmSubcommand}`;
56
+ }
57
+
58
+ export const USAGE = `Usage: utexo <command> <wallet_name> [options...]
59
+
60
+ Commands (no extra flags): address, btcbalance, listassets, listtransfers, refresh, listunspents
61
+ utexo address <wallet>
62
+ utexo btcbalance <wallet>
63
+ utexo listassets <wallet> [--assetId <id>]
64
+ utexo listtransfers <wallet> [--assetId <id>]
65
+ utexo refresh <wallet>
66
+ utexo listunspents <wallet>
67
+
68
+ Onchain: getonchainsendstatus, onchainreceive, onchainsendbegin, onchainsendend, onchainsend, send
69
+ utexo getonchainsendstatus <wallet> --invoice "<inv>"
70
+ utexo onchainreceive <wallet> --amount <n> [--assetId <id>] [--minConfirmations <n>] [--durationSeconds <n>]
71
+ utexo onchainsendbegin <wallet> --invoice "<inv>"
72
+ utexo onchainsendend <wallet> --invoice "<inv>" --signedPsbt "<psbt>"
73
+ utexo onchainsend <wallet> --invoice "<inv>" [--mnemonic "<mn>"]
74
+ utexo send <wallet> --invoice "<inv>" [--assetId <id>] [--amount <n>] [--witnessData "<json>"] [--mnemonic "<mn>"] [--feeRate <n>] [--minConfirmations <n>]
75
+
76
+ Receive invoices: blindreceive, witnessreceive
77
+ utexo blindreceive <wallet> --amount <n> [--assetId <id>] [--minConfirmations <n>] [--durationSeconds <n>]
78
+ utexo witnessreceive <wallet> --amount <n> [--assetId <id>] [--minConfirmations <n>] [--durationSeconds <n>]
79
+
80
+ Lightning: createlightninginvoice, paylightninginvoicebegin, paylightninginvoice, paylightninginvoiceend, getlightningsendrequest, getlightningreceiverequest
81
+ utexo createlightninginvoice <wallet> --assetId <id> --amount <n> [--amountSats <n>] [--expirySeconds <n>]
82
+ utexo paylightninginvoicebegin <wallet> --lnInvoice "<inv>" [--maxFee <n>]
83
+ utexo paylightninginvoice <wallet> --lnInvoice "<inv>" [--amount <n>] [--assetId <id>] [--maxFee <n>] [--mnemonic "<mn>"]
84
+ utexo paylightninginvoiceend <wallet> --lnInvoice "<inv>" --signedPsbt "<psbt>"
85
+ utexo getlightningsendrequest <wallet> --lnInvoice "<inv>"
86
+ utexo getlightningreceiverequest <wallet> --lnInvoice "<inv>"
87
+
88
+ Other: decodergbinvoice, createutxos, signpsbt, sign-psbt, generate_keys
89
+ utexo decodergbinvoice <wallet> --invoice "<inv>"
90
+ utexo createutxos <wallet> [--num <n>] [--size <n>] [--feeRate <n>] [--upTo]
91
+ utexo signpsbt <wallet> --psbt "<psbt>" [--mnemonic "<mn>"] # uses wallet (init/goOnline)
92
+ utexo sign-psbt --psbt "<psbt>" --network <net> --mnemonic "<mn>" # standalone, no wallet
93
+ utexo generate_keys <wallet_name> [network] # network: regtest (default), testnet, mainnet
94
+
95
+ WalletManager (same keys file, standard RGB wallet):
96
+ utexo wm address <wallet>
97
+ utexo wm btcbalance <wallet>
98
+ utexo wm refresh <wallet>
99
+ utexo wm sync <wallet>
100
+ utexo wm createutxos <wallet> [--num <n>] [--size <n>] [--feeRate <n>] [--upTo]
101
+ utexo wm blindreceive <wallet> --amount <n> [--assetId <id>] [--minConfirmations <n>] [--durationSeconds <n>]
102
+ utexo wm listassets <wallet> # list assets and BTC balance
103
+ utexo wm listtransfers <wallet> [--assetId <id>]
104
+ utexo wm sendbatch <wallet> --assetId <id> --amount <n> --invoices "<inv1>,<inv2>,..." [--feeRate <n>] [--minConfirmations <n>]
105
+ utexo wm sendbtc <wallet> --address <addr> --amount <sats> [--feeRate <n>]
106
+
107
+ Or run script with hardcoded params: node cli/scripts/send-batch-wm.mjs`;
108
+
109
+ function printUsage() {
110
+ console.error(USAGE);
111
+ }
112
+
113
+ const withUsage = (fn) => (walletName, flagArgs) => fn(walletName, flagArgs, { usage: USAGE });
114
+
115
+ async function runWmAddress(walletName, flagArgs) {
116
+ parseFlags(flagArgs, { required: [], optional: [] });
117
+ await runWithWalletManager(walletName, async (wallet) => {
118
+ const address = await wallet.getAddress();
119
+ console.log(`✅ Address: ${address}`);
120
+ }, { quiet: true });
121
+ }
122
+
123
+ async function runWmBtcbalance(walletName, flagArgs) {
124
+ parseFlags(flagArgs, { required: [], optional: [] });
125
+ await runWithWalletManager(walletName, async (wallet) => {
126
+ const balance = await wallet.getBtcBalance();
127
+ console.log('✅ BTC balance:');
128
+ console.log(` Vanilla: settled ${balance.vanilla.settled}, spendable ${balance.vanilla.spendable} sats`);
129
+ console.log(` Colored: settled ${balance.colored.settled}, spendable ${balance.colored.spendable} sats`);
130
+ }, { quiet: true });
131
+ }
132
+
133
+ async function runWmRefresh(walletName, flagArgs) {
134
+ parseFlags(flagArgs, { required: [], optional: [] });
135
+ await runWithWalletManager(walletName, async (wallet) => {
136
+ await wallet.refreshWallet();
137
+ console.log('✅ Wallet refreshed');
138
+ }, { quiet: true });
139
+ }
140
+
141
+ async function runWmSync(walletName, flagArgs) {
142
+ parseFlags(flagArgs, { required: [], optional: [] });
143
+ await runWithWalletManager(walletName, async (wallet) => {
144
+ await wallet.syncWallet();
145
+ console.log('✅ Wallet synced');
146
+ }, { quiet: true });
147
+ }
148
+
149
+ async function runWmCreateutxos(walletName, flagArgs) {
150
+ const opts = parseFlags(flagArgs, { required: [], optional: ['num', 'size', 'feeRate'] });
151
+ const upTo = flagArgs.includes('--upTo');
152
+ const num = opts.num ? parseInt(opts.num, 10) : 5;
153
+ const size = opts.size ? parseInt(opts.size, 10) : 1000;
154
+ const feeRate = opts.feeRate ? parseInt(opts.feeRate, 10) : 1;
155
+ await runWithWalletManager(walletName, async (wallet) => {
156
+ const count = await wallet.createUtxos({ num, size, feeRate, upTo: upTo || undefined });
157
+ console.log(`✅ Created ${count} UTXO(s)`);
158
+ }, { quiet: true });
159
+ }
160
+
161
+ async function runWmBlindreceive(walletName, flagArgs) {
162
+ const opts = parseFlags(flagArgs, { required: ['amount'], optional: ['assetId', 'minConfirmations', 'durationSeconds'] }, { usage: USAGE });
163
+ const request = {
164
+ amount: parseInt(opts.amount, 10),
165
+ ...(opts.assetId && { assetId: opts.assetId }),
166
+ ...(opts.minConfirmations && { minConfirmations: parseInt(opts.minConfirmations, 10) }),
167
+ ...(opts.durationSeconds && { durationSeconds: parseInt(opts.durationSeconds, 10) }),
168
+ };
169
+ await runWithWalletManager(walletName, async (wallet) => {
170
+ const result = await wallet.blindReceive(request);
171
+ console.log(JSON.stringify(result, null, 2));
172
+ }, { quiet: true });
173
+ }
174
+
175
+ async function runWmListassets(walletName, flagArgs) {
176
+ parseFlags(flagArgs, { required: [], optional: [] });
177
+ await runWithWalletManager(walletName, async (wallet) => {
178
+ const [assets, btcBalance] = await Promise.all([wallet.listAssets(), wallet.getBtcBalance()]);
179
+ console.log('BTC balance:');
180
+ console.log(` Vanilla: settled ${btcBalance.vanilla.settled}, spendable ${btcBalance.vanilla.spendable} sats`);
181
+ console.log(` Colored: settled ${btcBalance.colored.settled}, spendable ${btcBalance.colored.spendable} sats`);
182
+ console.log('\nAssets:');
183
+ console.log(JSON.stringify(assets, null, 2));
184
+ const n = (assets.nia?.length || 0) + (assets.uda?.length || 0) + (assets.cfa?.length || 0) + (assets.ifa?.length || 0);
185
+ console.log(`\n✅ Total: ${n} asset(s)`);
186
+ }, { quiet: true });
187
+ }
188
+
189
+ async function runWmListtransfers(walletName, flagArgs) {
190
+ const opts = parseFlags(flagArgs, { required: [], optional: ['assetId'] });
191
+ await runWithWalletManager(walletName, async (wallet) => {
192
+ const transfers = await wallet.listTransfers(opts.assetId);
193
+ console.log(JSON.stringify(transfers, null, 2));
194
+ console.log(`✅ Total: ${Array.isArray(transfers) ? transfers.length : 0} transfer(s)`);
195
+ }, { quiet: true });
196
+ }
197
+
198
+ const DEFAULT_TRANSPORT = 'rpcs://proxy.iriswallet.com/0.2/json-rpc';
199
+
200
+ async function buildRecipientMap(wallet, assetId, amount, invoices) {
201
+ const recipients = [];
202
+ for (const invoiceStr of invoices) {
203
+ const invoiceData = await wallet.decodeRGBInvoice({ invoice: invoiceStr });
204
+ const transportEndpoints =
205
+ invoiceData.transportEndpoints?.length > 0
206
+ ? invoiceData.transportEndpoints
207
+ : [DEFAULT_TRANSPORT];
208
+ recipients.push({
209
+ recipientId: invoiceData.recipientId,
210
+ witnessData: null,
211
+ assignment: { Fungible: amount },
212
+ transportEndpoints,
213
+ });
214
+ }
215
+ return { [assetId]: recipients };
216
+ }
217
+
218
+ async function runWmSendbtc(walletName, flagArgs) {
219
+ const opts = parseFlags(flagArgs, {
220
+ required: ['address', 'amount'],
221
+ optional: ['feeRate', 'skipSync'],
222
+ }, { usage: USAGE });
223
+ const address = opts.address;
224
+ const amount = parseInt(opts.amount, 10);
225
+ const feeRate = opts.feeRate ? parseInt(opts.feeRate, 10) : 1;
226
+ const skipSync = opts.skipSync === 'true' || opts.skipSync === '1';
227
+ await runWithWalletManager(walletName, async (wallet) => {
228
+ const txid = await wallet.sendBtc({ address, amount, feeRate, ...(skipSync && { skipSync }) });
229
+ console.log(`✅ BTC sent. Txid: ${txid}`);
230
+ }, { quiet: true });
231
+ }
232
+
233
+ async function runWmSendbatch(walletName, flagArgs) {
234
+ const opts = parseFlags(flagArgs, {
235
+ required: ['assetId', 'amount', 'invoices'],
236
+ optional: ['feeRate', 'minConfirmations'],
237
+ }, { usage: USAGE });
238
+ const invoices = opts.invoices.split(',').map((s) => s.trim()).filter(Boolean);
239
+ if (invoices.length === 0) {
240
+ console.error('--invoices must contain at least one invoice (comma-separated)');
241
+ process.exit(1);
242
+ }
243
+ const assetId = opts.assetId;
244
+ const amount = parseInt(opts.amount, 10);
245
+ await runWithWalletManager(walletName, async (wallet) => {
246
+ const recipientMap = await buildRecipientMap(wallet, assetId, amount, invoices);
247
+ const result = await wallet.sendBatch({
248
+ recipientMap,
249
+ ...(opts.feeRate && { feeRate: parseInt(opts.feeRate, 10) }),
250
+ ...(opts.minConfirmations && { minConfirmations: parseInt(opts.minConfirmations, 10) }),
251
+ });
252
+ console.log(JSON.stringify(result, null, 2));
253
+ console.log('✅ Batch send completed');
254
+ }, { quiet: true });
255
+ }
256
+
257
+ const commands = {
258
+ address: runAddress,
259
+ btcbalance: runBtcbalance,
260
+ listassets: runListassets,
261
+ listtransfers: runListtransfers,
262
+ refresh: runRefresh,
263
+ listunspents: runListunspents,
264
+ getonchainsendstatus: withUsage(runGetOnchainSendStatus),
265
+ decodergbinvoice: withUsage(runDecodergbinvoice),
266
+ blindreceive: withUsage(runBlindreceive),
267
+ witnessreceive: withUsage(runWitnessreceive),
268
+ onchainreceive: withUsage(runOnchainreceive),
269
+ createutxos: runCreateutxos,
270
+ onchainsendbegin: withUsage(runOnchainsendbegin),
271
+ signpsbt: withUsage(runSignpsbt),
272
+ 'sign-psbt': withUsage(runSignPsbtStandalone),
273
+ onchainsendend: withUsage(runOnchainsendend),
274
+ onchainsend: withUsage(runOnchainsend),
275
+ send: withUsage(runSend),
276
+ createlightninginvoice: withUsage(runCreatelightninginvoice),
277
+ paylightninginvoicebegin: withUsage(runPaylightninginvoicebegin),
278
+ paylightninginvoice: withUsage(runPaylightninginvoice),
279
+ paylightninginvoiceend: withUsage(runPaylightninginvoiceend),
280
+ getlightningsendrequest: withUsage(runGetlightningsendrequest),
281
+ getlightningreceiverequest: withUsage(runGetlightningreceiverequest),
282
+ generate_keys: runGenerateKeys,
283
+ wm_address: runWmAddress,
284
+ wm_btcbalance: runWmBtcbalance,
285
+ wm_refresh: runWmRefresh,
286
+ wm_sync: runWmSync,
287
+ wm_createutxos: runWmCreateutxos,
288
+ wm_blindreceive: runWmBlindreceive,
289
+ wm_listassets: runWmListassets,
290
+ wm_listtransfers: runWmListtransfers,
291
+ wm_sendbatch: runWmSendbatch,
292
+ wm_sendbtc: runWmSendbtc,
293
+ };
294
+
295
+ async function main() {
296
+ if (!command || !commands[command]) {
297
+ printUsage();
298
+ process.exit(1);
299
+ }
300
+
301
+ try {
302
+ await commands[command](walletName, flagArgs);
303
+ } catch (error) {
304
+ handleError(error, `running command '${command}'`);
305
+ }
306
+ }
307
+
308
+ main();