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#
- The seller exposes a stream offer: the rate and the payee.
- The buyer validates the offer and opens a session.
- The service is divided into measurable slices — ten seconds of power, a block of data, a minute of access.
- For each slice, the seller sends a slice request; the buyer checks it against its policy and returns a signed authorization.
- 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.
| Message | Direction | Carries |
|---|---|---|
| Stream offer | seller → buyer | rate and payee, before anything is delivered |
| Slice request | seller → buyer | the next measured slice and what it costs |
| Slice payment | buyer → seller | a signed authorization — or nothing, if refused |
| Session control | either way | start, pause and stop |
| Stream status | seller → buyer | what has been delivered so far |
The signed envelope#
Each slice payment is a signed EIP-3009 authorization:
{"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#
0xEE00, pushes slice requests and forwards proofs.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.