97 lines
3.2 KiB
TypeScript
97 lines
3.2 KiB
TypeScript
import { generateTemplateIdentifier } from "@xo-cash/engine";
|
|
import { hexToBin, lockingBytecodeToCashAddress } from "@bitauth/libauth";
|
|
|
|
import { bold, dim } from "../utils.js";
|
|
import type { CommandDependencies, CommandIO } from "./types.js";
|
|
import { CommandError } from "./types.js";
|
|
|
|
import { resolveTemplate } from "../utils.js";
|
|
|
|
/**
|
|
* Prints the help message for the receive command
|
|
*/
|
|
export const printReceiveHelp = (io: CommandIO): void => {
|
|
io.out(
|
|
`
|
|
${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.
|
|
* Throws CommandError on failure, returns address data on success.
|
|
*
|
|
* @param deps - The command dependencies.
|
|
* @param args - Positional args after the command name, e.g. ["template.json", "receiveOutput", "receiver"].
|
|
* @param options - Parsed option flags.
|
|
* @returns The address data.
|
|
* @throws CommandError if the command fails.
|
|
*/
|
|
export const handleReceiveCommand = async (
|
|
deps: CommandDependencies,
|
|
args: string[],
|
|
_options: Record<string, string>,
|
|
): Promise<{ address: string }> => {
|
|
// Get the template query, output identifier, and role identifier from the arguments
|
|
const templateQuery = args[0];
|
|
const outputIdentifier = args[1];
|
|
const roleIdentifier = args[2];
|
|
|
|
// Log the receive args
|
|
deps.io.verbose(
|
|
`Receive args - template: ${templateQuery}, output: ${outputIdentifier}, role: ${roleIdentifier}`,
|
|
);
|
|
|
|
// If no template query or output identifier is provided, print the help message and throw an error
|
|
if (!templateQuery || !outputIdentifier) {
|
|
deps.io.verbose("Missing required arguments");
|
|
printReceiveHelp(deps.io);
|
|
throw new CommandError(
|
|
"receive.arguments.missing",
|
|
"Missing required arguments",
|
|
);
|
|
}
|
|
|
|
// Resolve and read the template file
|
|
const template = await resolveTemplate(deps, templateQuery);
|
|
const templateIdentifier = generateTemplateIdentifier(template);
|
|
deps.io.verbose(`Template identifier: ${templateIdentifier}`);
|
|
|
|
// Generate the locking bytecode (returned as a hex string)
|
|
const lockingBytecodeHex = await deps.app.engine.generateLockingBytecode(
|
|
templateIdentifier,
|
|
outputIdentifier,
|
|
roleIdentifier,
|
|
);
|
|
deps.io.verbose(`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") {
|
|
deps.io.err(`Failed to encode address: ${result}`);
|
|
throw new CommandError(
|
|
"receive.address.encode_failed",
|
|
`Failed to encode address: ${result}`,
|
|
);
|
|
}
|
|
|
|
deps.io.out(result.address);
|
|
return { address: result.address };
|
|
};
|