@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
package/cli/utils.mjs ADDED
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Shared utilities for UTEXO test scripts
5
+ */
6
+
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ import { UTEXOWallet, createWalletManager } from '../dist/index.mjs';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+
15
+ /** Directory name for wallet config files (relative to cli) */
16
+ const WALLET_DATA_DIR = 'data';
17
+
18
+ /**
19
+ * Map wallet network (e.g. from generate_keys) to UTEXOWallet preset.
20
+ * UTEXOWallet only supports 'mainnet' | 'testnet'; regtest/signet/testnet4 map to 'testnet'.
21
+ * @param {string} network - Network from wallet config (mainnet, testnet, regtest, signet, testnet4)
22
+ * @returns {'mainnet'|'testnet'}
23
+ */
24
+ export function getNetworkPreset(network) {
25
+ return network === 'mainnet' ? 'mainnet' : 'testnet';
26
+ }
27
+
28
+ /**
29
+ * Get the directory path for wallet config files (cli/data)
30
+ */
31
+ export function getWalletDir() {
32
+ return path.join(__dirname, WALLET_DATA_DIR);
33
+ }
34
+
35
+ /**
36
+ * Get the full path to a wallet config file
37
+ * @param {string} walletName - Name of the wallet
38
+ * @returns {string} Full path to the wallet config file
39
+ */
40
+ export function getWalletPath(walletName) {
41
+ const filename = `${walletName}.json`;
42
+ return path.join(getWalletDir(), filename);
43
+ }
44
+
45
+ /**
46
+ * Load wallet configuration from file
47
+ * @param {string} walletName - Name of the wallet
48
+ * @returns {object} Wallet configuration object
49
+ * @throws {Error} If wallet file doesn't exist or is invalid
50
+ */
51
+ export function loadWalletConfig(walletName) {
52
+ const filepath = getWalletPath(walletName);
53
+
54
+ if (!fs.existsSync(filepath)) {
55
+ throw new Error(`Wallet config not found: ${filepath}`);
56
+ }
57
+
58
+ const configContent = fs.readFileSync(filepath, 'utf8');
59
+ return JSON.parse(configContent);
60
+ }
61
+
62
+ /**
63
+ * Save wallet configuration to file
64
+ * @param {string} walletName - Name of the wallet
65
+ * @param {object} config - Wallet configuration object
66
+ */
67
+ export function saveWalletConfig(walletName, config) {
68
+ const dir = getWalletDir();
69
+ if (!fs.existsSync(dir)) {
70
+ fs.mkdirSync(dir, { recursive: true });
71
+ }
72
+ const filepath = getWalletPath(walletName);
73
+ fs.writeFileSync(filepath, JSON.stringify(config, null, 2));
74
+ return filepath;
75
+ }
76
+
77
+ /**
78
+ * Check if wallet config exists
79
+ * @param {string} walletName - Name of the wallet
80
+ * @returns {boolean} True if wallet config exists
81
+ */
82
+ export function walletExists(walletName) {
83
+ return fs.existsSync(getWalletPath(walletName));
84
+ }
85
+
86
+ /**
87
+ * Handle script errors with consistent formatting
88
+ * @param {Error} error - Error object
89
+ * @param {string} action - Action that failed (e.g., "generating keys", "getting address")
90
+ */
91
+ export function handleError(error, action) {
92
+ console.error(`❌ Error ${action}:`, error.message);
93
+ if (error.stack) {
94
+ console.error(error.stack);
95
+ }
96
+ process.exit(1);
97
+ }
98
+
99
+ /**
100
+ * Parse flag args (e.g. after command and wallet name) into an options object.
101
+ * Flags are --key value (next arg). Does not include wallet name.
102
+ * @param {string[]} flagArgs - Args to parse (e.g. process.argv.slice(2) for rest after wallet)
103
+ * @param {{ required?: string[], optional?: string[] }} spec - Flag names (without --). required = must be present.
104
+ * @param {{ usage?: string }} options - If usage is set and validation fails, print it and exit
105
+ * @returns {{ [k: string]: string }} Parsed options (e.g. { invoice: 'rgb:...', assetId: '...' })
106
+ */
107
+ export function parseFlags(flagArgs, spec = {}, options = {}) {
108
+ const required = spec.required ?? [];
109
+ const optional = spec.optional ?? [];
110
+ const allNames = [...new Set([...required, ...optional])];
111
+ const result = {};
112
+
113
+ for (let i = 0; i < flagArgs.length; i++) {
114
+ const arg = flagArgs[i];
115
+ if (!arg.startsWith('--')) continue;
116
+ const name = arg.slice(2);
117
+ if (!allNames.includes(name)) continue;
118
+ const value = flagArgs[i + 1];
119
+ if (value === undefined || value.startsWith('--')) {
120
+ if (options.usage) {
121
+ console.error(options.usage);
122
+ process.exit(1);
123
+ }
124
+ throw new Error(`Missing value for --${name}`);
125
+ }
126
+ result[name] = value;
127
+ i++;
128
+ }
129
+
130
+ for (const name of required) {
131
+ if (result[name] === undefined || result[name] === '') {
132
+ if (options.usage) {
133
+ console.error(options.usage);
134
+ process.exit(1);
135
+ }
136
+ throw new Error(`Missing required --${name}`);
137
+ }
138
+ }
139
+ return result;
140
+ }
141
+
142
+ /**
143
+ * Load wallet, create UTEXOWallet, initialize, call action, then dispose. Central error handling.
144
+ * @param {string} walletName - Name of the wallet (must exist in data/)
145
+ * @param {(wallet: UTEXOWallet, walletConfig: object) => Promise<void>} action - Async callback; receives initialized wallet and config
146
+ * @param {{ actionName?: string, quiet?: boolean }} options - actionName for errors; quiet=true skips loading/init logs
147
+ */
148
+ export async function runWithWallet(walletName, action, options = {}) {
149
+ if (!walletName) {
150
+ console.error('❌ Missing wallet name');
151
+ process.exit(1);
152
+ }
153
+ if (!walletExists(walletName)) {
154
+ console.error(`❌ Wallet config not found: ${walletName}.json`);
155
+ console.error(` Please generate keys first: npm run generate_keys -- ${walletName}`);
156
+ process.exit(1);
157
+ }
158
+
159
+ const walletConfig = loadWalletConfig(walletName);
160
+ const wallet = new UTEXOWallet(walletConfig.mnemonic, {
161
+ network: getNetworkPreset(walletConfig.network),
162
+ });
163
+
164
+ try {
165
+ if (!options.quiet) {
166
+ console.log(`Loading wallet: ${walletConfig.walletName}`);
167
+ console.log(`Network: ${walletConfig.network}`);
168
+ console.log('Initializing wallet...');
169
+ }
170
+ await wallet.initialize();
171
+ await action(wallet, walletConfig);
172
+ } finally {
173
+ await wallet.dispose();
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Load wallet config, create WalletManager (from stored generate_keys JSON), run action, then dispose.
179
+ * Same flow as runWithWallet but for standard RGB WalletManager instead of UTEXOWallet.
180
+ * @param {string} walletName - Name of the wallet (must exist in data/)
181
+ * @param {(wallet: import('../dist/index.mjs').WalletManager, walletConfig: object) => Promise<void>} action
182
+ * @param {{ actionName?: string, quiet?: boolean, indexerUrl?: string, transportEndpoint?: string, dataDir?: string }} options
183
+ */
184
+ export async function runWithWalletManager(walletName, action, options = {}) {
185
+ if (!walletName) {
186
+ console.error('❌ Missing wallet name');
187
+ process.exit(1);
188
+ }
189
+ if (!walletExists(walletName)) {
190
+ console.error(`❌ Wallet config not found: ${walletName}.json`);
191
+ console.error(` Please generate keys first: node run.mjs generate_keys ${walletName} [network]`);
192
+ process.exit(1);
193
+ }
194
+
195
+ const walletConfig = loadWalletConfig(walletName);
196
+ const dataDir = options.dataDir ?? path.join(process.cwd(), '.rgb-wallet', String(walletConfig.network), walletConfig.masterFingerprint);
197
+ const wallet = createWalletManager({
198
+ xpubVan: walletConfig.accountXpubVanilla,
199
+ xpubCol: walletConfig.accountXpubColored,
200
+ masterFingerprint: walletConfig.masterFingerprint,
201
+ mnemonic: walletConfig.mnemonic,
202
+ network: walletConfig.network,
203
+ dataDir,
204
+ transportEndpoint: options.transportEndpoint ?? process.env.RGB_TRANSPORT_ENDPOINT,
205
+ indexerUrl: options.indexerUrl ?? process.env.RGB_INDEXER_URL,
206
+ });
207
+
208
+ try {
209
+ if (!options.quiet) {
210
+ console.log(`Loading wallet (WalletManager): ${walletConfig.walletName ?? walletName}`);
211
+ console.log(`Network: ${walletConfig.network}`);
212
+ }
213
+ if (options.indexerUrl ?? process.env.RGB_INDEXER_URL) {
214
+ await wallet.goOnline(options.indexerUrl ?? process.env.RGB_INDEXER_URL);
215
+ }
216
+ await action(wallet, walletConfig);
217
+ } finally {
218
+ await wallet.dispose();
219
+ }
220
+ }