# Prepaid, watermark-idempotent settlement Usage is metered per session and settled on-chain against a prepaid balance. ## Metering Each QUIC connection carries one meter $\mu = (u, d, r, k)$: bytes from the client ($u$), bytes from the target ($d$), a request counter ($r$), and the byte watermark of the last completed billing package ($k$). A *request* is counted when the first client byte arrives on a tunnel; connection retries at the transport level therefore add at most one request per tunnel. The exit reports the meter to every leg on a fixed interval (currently every second). Reports are *cumulative*, so a lost report is subsumed by the next one — the metering stream is loss-tolerant by construction. ### Report folding Each leg folds incoming cumulative reports into its account state independently. Folding is deterministic: a report that closes one or more packages attributes bytes to those packages using the meter's package watermark $k$, and the open package keeps the rest, which becomes overage only beyond its own included allowance. Packages that close in the same fold share one pooled allowance, so a lost intermediate report can change the charge for completed packages, but only downward. Two consequences are worth stating explicitly. First, the account's *settled* charge is monotone — it only grows as packages close. Second, the account's instantaneous debt (settled charge plus the open package) is not monotone across sessions, which is why settlement always targets the monotone quantity. ### Session control A session is cancelled if any single leg orders a cut-off (for example, when the account's balance is exhausted), or if all legs remain unreachable for several consecutive reporting rounds. On cancellation the exit terminates the QUIC connection, which atomically ends every tunnel of the session. The bearer token binding the session to the account has a bounded lifetime (currently 24 h), placing an upper bound on the lifetime of any single authenticated session context. ## Packages and Pricing Billing is denominated in a six-decimal dollar token (on mainnet `USDT.e`, backed 1:1 by USDT), held in a prepaid on-chain balance per account. The unit of charging is the *package*, an account-level aggregate across all of the account's sessions: - a package covers $N_R$ requests (currently 1,000) and includes $B_I$ bytes of transfer (currently 1 GiB); - transfer beyond the included volume is charged per additional block of $B_G$ bytes (currently 1 GiB) started. On mainnet the token is `Bridged PHASE USDT` (symbol `USDT.e`), backed 1:1 by USDT: the bridge mints it only against USDT received at its deposit address, and the 10,000 USDT.e genesis supply is backed by a Phase Labs USDT reserve. The bridge is one-way for now: USDT.e cannot yet be withdrawn back to a source chain. The cost of a package that carried $x$ bytes is $$ C(x) \;=\; P_B \;+\; P_O \cdot \left\lceil \frac{\max(x - B_I,\, 0)}{B_G} \right\rceil, $$ where $P_B$ is the base package price and $P_O$ the overage price per started block (current configuration: $P_B = 0.5$ USDT, $P_O = 1.5$ USDT). A package closes when its request counter is exhausted; bytes only ever add overage to the open package. Prices are operator parameters of each billing service: they are not transmitted on the wire, and different services may price the same traffic independently. ### Worked example Consider an account whose package closes after $N_R = 1{,}000$ requests having carried $x = 3.4$ GiB. The included volume covers the first GiB; the remaining $2.4$ GiB start three overage blocks, so $$ C(3.4\,\text{GiB}) \;=\; 0.5 \;+\; 1.5 \cdot \lceil 2.4 \rceil \;=\; 0.5 + 4.5 \;=\; 5.0 \text{ USDT.} $$ A light account that has issued 200 requests over 50 MiB has not yet closed a package: its settled charge is unchanged, and only the base price of the open package counts toward the final total when the account withdraws. Request-heavy and transfer-heavy workloads therefore both map onto the same two-parameter price surface, and the marginal cost of bulk transfer is bounded by $P_O$ per block. ### Admission A new session is admitted only if the account's available balance covers its outstanding charges plus a deposit headroom $P_D$ (currently $0.5$ USDT). The check is a threshold, not a reservation — funds remain fungible across the account's sessions. Concurrent sessions per account are capped per billing service. ## Settlement The on-chain billing contract tracks, per account: the prepaid balance $P(c)$, the pending withdrawal $\Omega(c)$, and a monotone settlement watermark $k_s(c)$ — the cumulative amount ever settled against the account. A settler process submits batches on a fixed tick via $$ \texttt{settleBatch(address[] accounts, uint256[] targets)}, $$ where each target is the account's *cumulative* charge total. The contract debits $$ \Delta(c, x) \;=\; \begin{cases} \min\bigl(x - k_s(c),\; P(c)\bigr) & \text{if } x > k_s(c),\\[2pt] 0 & \text{otherwise,} \end{cases} $$ and raises the watermark. Because targets are cumulative, settlement is idempotent by construction: resubmitting a batch — or two billing services settling overlapping charges — debits zero the second time. Double-charging is structurally impossible. Watermarks are read at finalized blocks from all configured chain endpoints, taking the maximum, and the local copy only ever moves forward — a temporarily lagging endpoint can never roll a watermark back. Balance and withdrawal state used for admission decisions are read as a coherent snapshot of a single block. A submitted batch is watched through a confirmation window and, if unconfirmed, resubmitted whole; idempotence makes blind resubmission safe. For availability, billing state is persisted through snapshots, and where several settler instances run, a leader-election mechanism ensures a single active submitter at a time. ### Withdrawal An account may request withdrawal of its unspent balance at any time. Before approval, the billing layer settles the account up to its final charge total (including the base price of any open package); approval requires no active session. The remainder is always returnable — prepaid funds are never trapped. ## Exit Registry and Discovery Each billing service maintains an in-memory registry of live exits, keyed by the 32-byte endpoint identifier. Exits register and then heartbeat on a fixed interval (currently 15 s); an entry expires after three missed heartbeats (45 s), so listings only ever contain recently live exits. Registrations may carry an ed25519 signature over a domain-separated message — a fixed domain tag, the endpoint's public key, and a timestamp inside a tight acceptance window, strictly increasing per endpoint to prevent replay. A signature, when present, is always verified; once an endpoint has registered with a signature, unsigned registrations for that identity are rejected. Under registry pressure, signed entries displace unsigned ones. Listings are returned in random order, spreading load across the fleet. How clients dial them: [Discovery and dialing](proxy-protocol.md#discovery-and-dialing).