#!/usr/bin/env python3 """Auto-top-up (sweep): send BTC to IPRoyal when reseller balance is low. SAFETY: DRY-RUN by default — prints what it *would* do, never moves money. To go live you must: 1. set sweep.iproyal_btc_address in config.json (IPRoyal's BTC deposit address), 2. wire the send() function to your source wallet (BTCPay hot wallet / Alby), 3. pass --live, with a hard cap via --cap-sats. """ import argparse import sys import iproyal def main(): ap = argparse.ArgumentParser() ap.add_argument("--live", action="store_true", help="actually send (default: dry-run)") ap.add_argument("--cap-sats", type=int, default=0, help="hard cap on sats to send") args = ap.parse_args() cfg = iproyal.CFG.get("sweep", {}) float_target = float(cfg.get("float_target", 50.0)) max_sats = args.cap_sats or int(cfg.get("max_sats", 75000)) dest = cfg.get("iproyal_btc_address", "") try: bal = iproyal.get_balance() except Exception as e: print(f"balance check failed: {e}") sys.exit(1) if bal >= float_target: print(f"balance ${bal} >= float target ${float_target} — no top-up needed") return shortfall = float_target - bal if not dest: print(f"LOW: balance ${bal} is below float target ${float_target} (shortfall ${shortfall:.2f}). " "Set sweep.iproyal_btc_address in config.json to enable auto-top-up.") return if args.live: print(f"LIVE: balance ${bal} < ${float_target} — would send {max_sats} sats (~${shortfall:.2f}) to {dest}") print("WARNING: send() not yet wired — this is a no-op placeholder.") else: print(f"DRY-RUN: balance ${bal} < float target ${float_target} (shortfall ${shortfall:.2f}) — " f"would top up {max_sats} sats to {dest}") if __name__ == "__main__": main()