Skip to content

jmwalletd.legacy_schedule

jmwalletd.legacy_schedule

Project a tumbler :class:~tumbler.plan.Plan into the legacy schedule format.

The reference implementation's GET /session returns the running tumble as taker.schedule: a list of 7-element entries that JAM parses in scheduleUtils.ts::

[mixdepth, amount, counterparties, destination, wait_minutes, rounding, flag]

where

  • amount is a fraction in (0, 1) for non-sweeps or 0 for sweeps (absolute satoshi amounts are also accepted -- JAM only requires a number);
  • destination is a bitcoin address or the sentinel "INTERNAL";
  • wait_minutes is the delay after this entry completes, before the next entry starts;
  • rounding is the significant-figures rounding applied to the amount (16 means "no rounding" in the reference implementation);
  • flag is 0 (not yet broadcast), the txid string (broadcast, waiting for confirmations), or 1 (confirmed).

jm-ng plans may interleave :class:~tumbler.plan.MakerSessionPhase phases, which have no legacy equivalent. Their expected duration and inter-phase wait are folded into the preceding taker entry's wait time so JAM's progress bar and ETA remain meaningful.

Attributes

NO_ROUNDING = 16 module-attribute

ScheduleEntry = list[str | int | float] module-attribute

Functions:

plan_to_legacy_schedule(plan: Plan) -> list[ScheduleEntry]

Render plan as a reference-format schedule (list of 7-element lists).

Maker-session phases are not representable as legacy entries; their expected duration (duration_seconds when time-bounded) and their wait_seconds are added to the preceding taker entry's wait time. A maker session before the first taker phase is dropped entirely (the legacy format has no way to express a delay before the first entry).

Source code in jmwalletd/src/jmwalletd/legacy_schedule.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
def plan_to_legacy_schedule(plan: Plan) -> list[ScheduleEntry]:
    """Render ``plan`` as a reference-format schedule (list of 7-element lists).

    Maker-session phases are not representable as legacy entries; their
    expected duration (``duration_seconds`` when time-bounded) and their
    ``wait_seconds`` are added to the preceding taker entry's wait time.
    A maker session before the first taker phase is dropped entirely (the
    legacy format has no way to express a delay before the first entry).
    """
    schedule: list[ScheduleEntry] = []
    for phase in plan.phases:
        if isinstance(phase, TakerCoinjoinPhase):
            amount: int | float
            if phase.amount_fraction is not None:
                amount = phase.amount_fraction
            else:
                amount = phase.amount or 0
            schedule.append(
                [
                    phase.mixdepth,
                    amount,
                    phase.counterparty_count,
                    phase.destination,
                    phase.wait_seconds / 60.0,
                    phase.rounding_sigfigs if phase.rounding_sigfigs is not None else NO_ROUNDING,
                    _phase_flag(phase, plan),
                ]
            )
        elif isinstance(phase, MakerSessionPhase) and schedule:
            extra_seconds = (phase.duration_seconds or 0.0) + phase.wait_seconds
            entry = schedule[-1]
            entry[4] = float(entry[4]) + extra_seconds / 60.0
    return schedule