Module jmcore.confirmation
User confirmation prompts for fund-moving operations.
Functions
def confirm_transaction(operation: str,
amount: int,
destination: str | None = None,
fee: int | None = None,
additional_info: dict[str, Any] | None = None,
skip_confirmation: bool = False) ‑> bool-
Expand source code
def confirm_transaction( operation: str, amount: int, destination: str | None = None, fee: int | None = None, additional_info: dict[str, Any] | None = None, skip_confirmation: bool = False, ) -> bool: """ Prompt user to confirm a transaction that moves funds. Args: operation: Type of operation (e.g., "send", "coinjoin") amount: Amount in satoshis (0 for sweep) destination: Destination address (optional) fee: Total fee in satoshis (optional) additional_info: Additional details to show (e.g., maker fees, counterparties) skip_confirmation: If True, skip prompt (from --yes flag) Returns: True if user confirms, False otherwise Raises: RuntimeError: If in non-interactive mode without skip_confirmation """ # Skip if confirmation disabled if skip_confirmation: return True # Error if non-interactive without --yes if not is_interactive_mode(): raise RuntimeError( "Cannot prompt for confirmation in non-interactive mode. " "Use --yes flag or set NO_INTERACTIVE=1 to skip confirmation." ) # Build transaction summary print("\n" + "=" * 80) print(f"TRANSACTION CONFIRMATION - {operation.upper()}") print("=" * 80) # Amount if amount == 0: print("Amount: SWEEP (all available funds)") else: from jmcore.bitcoin import format_amount print(f"Amount: {format_amount(amount)}") # Destination if destination: if destination == "INTERNAL": print("Destination: INTERNAL (next mixdepth)") else: print(f"Destination: {destination}") # Fee if fee is not None: from jmcore.bitcoin import format_amount print(f"Fee: {format_amount(fee)}") # Additional info if additional_info: for key, value in additional_info.items(): # Format based on type if isinstance(value, int) and key.lower().endswith(("fee", "amount", "value")): from jmcore.bitcoin import format_amount print(f"{key}: {format_amount(value)}".ljust(80)) elif isinstance(value, list): print(f"{key}: {len(value)} item(s)") for i, item in enumerate(value, 1): if isinstance(item, dict): # Show dict items nicely print(f" {i}. {item}") else: print(f" {i}. {item}") else: print(f"{key}: {value}".ljust(80)) print("=" * 80) # Prompt for confirmation try: response = input("\nProceed with this transaction? [y/N]: ").strip().lower() return response in ("y", "yes") except (KeyboardInterrupt, EOFError): print("\n\nTransaction cancelled by user.") return FalsePrompt user to confirm a transaction that moves funds.
Args
operation- Type of operation (e.g., "send", "coinjoin")
amount- Amount in satoshis (0 for sweep)
destination- Destination address (optional)
fee- Total fee in satoshis (optional)
additional_info- Additional details to show (e.g., maker fees, counterparties)
skip_confirmation- If True, skip prompt (from –yes flag)
Returns
True if user confirms, False otherwise
Raises
RuntimeError- If in non-interactive mode without skip_confirmation
def format_maker_summary(makers: list[dict[str, Any]]) ‑> dict[str, typing.Any]-
Expand source code
def format_maker_summary(makers: list[dict[str, Any]]) -> dict[str, Any]: """ Format maker information for confirmation display. Args: makers: List of selected maker dicts with 'nick', 'fee', 'bond_value', etc. Returns: Dict with formatted maker info """ total_maker_fee = sum(m.get("fee", 0) for m in makers) maker_details = [] for m in makers: nick = m.get("nick", "unknown") fee = m.get("fee", 0) bond_value = m.get("bond_value", 0) bond_str = f" [bond: {bond_value:,}]" if bond_value > 0 else " [no bond]" maker_details.append(f"{nick}: {fee:,} sats{bond_str}") return { "Counterparties": len(makers), "Total Maker Fees": total_maker_fee, "Makers": maker_details, }Format maker information for confirmation display.
Args
makers- List of selected maker dicts with 'nick', 'fee', 'bond_value', etc.
Returns
Dict with formatted maker info
def is_interactive_mode() ‑> bool-
Expand source code
def is_interactive_mode() -> bool: """ Check if we're running in interactive mode. Returns False if NO_INTERACTIVE env var is set or if not attached to a TTY. """ if os.environ.get("NO_INTERACTIVE"): return False return sys.stdin.isatty() and sys.stdout.isatty()Check if we're running in interactive mode.
Returns False if NO_INTERACTIVE env var is set or if not attached to a TTY.