BoAT MER Guide

Streaming payments over BLE

Prepay and the buyer carries the risk; pay afterwards and the seller does. BoAT MER splits a service into measured slices and has the buyer sign for each one before the next is delivered.

One session, slice by slice#

Buyer device Seller device Settlement Stream offer · rate, payee validate offer Session control · start EVERY SLICE · e.g. 10 s of power Slice request · slice #n, amount check policy: rate, cap, window Slice payment · signed EIP-3009 authorization deliver slice forward proofs verify + batch
The buyer signs only what passes its own policy. The seller has no signing interface at all; it forwards.
  1. The seller exposes a stream offer: the rate and the payee.
  2. The buyer validates the offer and opens a session.
  3. The service is divided into measurable slices — ten seconds of power, a block of data, a minute of access.
  4. For each slice, the seller sends a slice request; the buyer checks it against its policy and returns a signed authorization.
  5. The seller delivers the slice, and forwards the signed proofs for off-device settlement, usually batched.

In the eCandle × Bitaxe run, a Bitcoin miner bought solar power this way: 24 slices in four minutes, each about ten seconds at 15 W, for roughly $0.000042 apiece. In the Arc mainnet drone demo the seller asked for a payment every five seconds and batched after six proofs.

The 0xEE00 wire#

The 0xEE00 GATT service is the contract between the buyer and seller engines, specified in ble-protocol.md.

MessageDirectionCarries
Stream offerseller → buyerrate and payee, before anything is delivered
Slice requestseller → buyerthe next measured slice and what it costs
Slice paymentbuyer → sellera signed authorization — or nothing, if refused
Session controleither waystart, pause and stop
Stream statusseller → buyerwhat has been delivered so far

The signed envelope#

Each slice payment is a signed EIP-3009 authorization:

json
{"sig":"0x<r||s||v>","from":"0x..","to":"0x..","value":"<dec>",
 "validAfter":..,"validBefore":..,"nonce":"0x..","slice_id":..}

The seller checks that a proof is present and well-formed, then forwards it. It does not verify the signature on-device — that happens at the settlement layer, or on the device with boat_nano_verify() if you choose. This is deliberate: the seller is a low-trust conduit, with nothing to sign and nothing to be tricked into signing.

A settlement service can carry many of these in one on-chain transaction, which is what makes a payment of a few millionths of a dollar worth sending.

Writing a buyer or a seller#

Careful

boat_buyer_ctx_t carries the replay-guard set and is roughly 32 KB in the current release. On the stack it will overflow a typical embedded task. boat_buyer_init() checks the caller's sizeof and returns BOAT_ERR_INVALID_ARG on a mismatch rather than corrupting memory.