Files
xo-cli/src/cli/commands/receive.ts

81 lines
2.8 KiB
TypeScript

import { existsSync, readFileSync } from "fs";
import path from "path";
import { generateTemplateIdentifier } from "@xo-cash/engine";
import { hexToBin, lockingBytecodeToCashAddress } from "@bitauth/libauth";
import { bold, dim } from "../cli-utils.js";
import type { CommandDependencies } from "./types.js";
/**
* Prints the help message for the receive command
*/
export const printReceiveHelp = () => {
console.log(
`
${bold("Usage:")} xo-cli receive <template-file> <output-identifier> [role-identifier]
${bold("Description:")}
Generate a single-use receiving address from a template.
${bold("Arguments:")}
<template-file> ${dim("Path to the template JSON file")}
<output-identifier> ${dim("The output identifier within the template (e.g. 'receiveOutput')")}
[role-identifier] ${dim("The role identifier (e.g. 'receiver'). Auto-selects the first role if omitted.")}
${bold("Options:")}
-h --help ${dim("Show this help message")}
`);
};
/**
* Command which creates a single-use address/lockingScript for a given template and role.
* @param deps - The command dependencies.
* @param args - Positional args after the command name, e.g. ["template.json", "receiveOutput", "receiver"].
* @param options - Parsed option flags.
*/
export const handleReceiveCommand = async (deps: CommandDependencies, args: string[], options: Record<string, string>): Promise<void> => {
const templateFile = args[0];
const outputIdentifier = args[1];
const roleIdentifier = args[2];
deps.verboseLogger(`Receive args - template: ${templateFile}, output: ${outputIdentifier}, role: ${roleIdentifier}`);
if (!templateFile || !outputIdentifier) {
deps.verboseLogger("Missing required arguments");
printReceiveHelp();
return;
}
// Resolve and read the template file
const templatePath = path.resolve(`${process.cwd()}/${templateFile}`);
deps.verboseLogger(`Template path: ${templatePath}`);
if (!existsSync(templatePath)) {
console.error(`Template file does not exist: ${templatePath}`);
printReceiveHelp();
return;
}
const template = readFileSync(templatePath, "utf8");
const templateIdentifier = generateTemplateIdentifier(JSON.parse(template));
deps.verboseLogger(`Template identifier: ${templateIdentifier}`);
// Generate the locking bytecode (returned as a hex string)
const lockingBytecodeHex = await deps.app.engine.generateLockingBytecode(
templateIdentifier,
outputIdentifier,
roleIdentifier,
);
deps.verboseLogger(`Locking bytecode hex: ${lockingBytecodeHex}`);
// Convert the locking bytecode to a BCH cash address
const result = lockingBytecodeToCashAddress({ bytecode: hexToBin(lockingBytecodeHex), prefix: 'bitcoincash' });
if (typeof result === 'string') {
console.error(`Failed to encode address: ${result}`);
return;
}
console.log(result.address);
};