BoAT MER Guide

Quick Start

Part A runs on your laptop in about five minutes and needs no hardware. Part B puts the same code on two ESP32 boards that pay each other over Bluetooth.

Part A · On your laptop#

You need git, CMake, a C compiler, and the OpenSSL and curl development libraries — the host build links them. Linux and macOS are both verified.

1

Clone and build

The host build is the same code path a device runs, with the Linux platform layer underneath.

bash
git clone https://github.com/TLAY-IO/boat-mer.git
cd boat-mer
cmake -B build && cmake --build build
2

Run the quickstart

One program walks through the three things the runtime does, then checks the result the way a settlement service would.

bash
./build/quickstart
01 · IDENTITY Make its keys Generated on the device, kept there. did:mw:… · 0x76eb… 02 · ATTEST Sign a reading SHA-256, then Ed25519. Anyone can check it later. {"kwh":0.417,…} 03 · PAY $ Authorize a payment EIP-3009, signed on the device. Not submitted. 417 micro-USDC 04 · VERIFY Check it, like settlement The signature recovers to this device — on one chain only. OK · cross-chain rejected
What examples/quickstart/main.c does, in order. Nothing in it touches a network.
3

Read the output

Your keys and nonce will differ; the shape will not.

./build/quickstart
=== 1. device identity ===
DID          did:mw:8b798b7da1e57ccf43f4bb0168afa2d673f28b79811d327a64c5fb2e9ca4b7f4
EVM address  0x76ebfd227d9fa763035fc31372f5923b52e014b3

=== 2. attestation ===
payload      {"kwh":0.417,"t":1756713600}
sha-256      0xd253d2df2e033c0df20a054355c3c8c09a2d7fe411b95db2f5d07c2058e24732
ed25519 sig  0x568383f3c05e845afa9c3b9208109aeb

=== 3. payment authorization ===
value        417 micro-USDC
validAfter   0 (0 = no lower bound)
validBefore  1789042260
min window   BOAT_MIN_AUTH_VALIDITY_SECS = 604900 s

=== verification (what a settlement service does) ===
recovered    0x76ebfd227d9fa763035fc31372f5923b52e014b3
expected     0x76ebfd227d9fa763035fc31372f5923b52e014b3
result       OK — signature recovers to this device
cross-chain  correctly rejected
  • device identity — a keypair made on first run and stored by the platform layer. Run it again and it prints loaded from storage and the same DID.
  • attestation — a hash of the reading, signed with the device's Ed25519 key. Anyone with the payload and public key can check it later.
  • payment authorization — an EIP-3009 authorization for 417 micro-USDC ($0.000417), signed on the device and not submitted anywhere.
  • cross-chain correctly rejected — the same signature presented for a different chain does not verify. That domain separation is what stops a signature being replayed where it was never meant to go.
4

Run the tests

More than 60 checks across crypto, EIP-712, identity, attestation, payments, x402, Lightning and the nanopayment path.

bash
./build/test_all
./build/test_buyer    # the buyer engine, including the replay guard
Tip

You have a device identity, a signed reading and a verified payment authorization — the whole runtime, minus the radio. Part B adds the boards and the Bluetooth link.

Part B · Two boards paying each other#

This part reproduces the buyer-and-seller flow from the Arc mainnet drone demo, using the public arc-drone-show-demo repository at tag v1.0.0. One board plays the drone that buys power; the other plays the charging station that sells it.

BUYER · apps/drone C3 ESP32-C3 holds its own key Checks each request against its policy, then signs. SELLER · apps/ecandle C3 ESP32-C3 meters and forwards Asks for a payment every 5 s. Signs nothing itself. SliceRequest · amount, payee, window SliceProof · signed EIP-3009 authorization BLE · 0xEE00 MQTT YOUR LAPTOP · docker compose up broker mosquitto settle- worker web UI :3000 settlement service batched
What you are building: two ESP32-C3 boards over BLE, and a broker, settlement worker and demo UI in Docker on your laptop.

You need two ESP32-C3 boards and USB data cables, ESP-IDF (built against 5.5.x), Node.js 20+, Docker, and an Arc test wallet.

1

Clone the demo

bash
git clone --branch v1.0.0 --depth 1 https://github.com/TLAY-IO/arc-drone-show-demo
cd arc-drone-show-demo

apps/drone is the buyer firmware, apps/ecandle the seller firmware, and cloud/ holds the broker, the settlement worker and the demo UI.

2

Start the laptop side

The broker generates its own passwords; paste the two MQTT_URL_* lines it prints into cloud/.env, and keep the device password for the seller.

bash
cp cloud/.env.example cloud/.env
cd cloud
./mosquitto/gen-passwd.sh
docker compose up

Set MQTT_BIND_IP in cloud/.env to your LAN address so the seller board can reach the broker. Then open http://localhost:3000/demo?live=1 — without ?live=1 the page plays a simulation on mock data.

3

Flash the seller

Set the broker URI in menuconfig to mqtt://device:<device-password>@<your-LAN-IP>:1883, then flash.

bash
cd apps/ecandle
idf.py set-target esp32c3
idf.py menuconfig
idf.py -p /dev/ttyUSB0 flash monitor
seller serial monitor
boat-mer v1.0.1 seller initialized
BLE adv mfg_data[5] = 0 (IDLE, ready to connect)
4

Flash the buyer

The buyer makes its own key on first boot and prints only its address.

bash
cd apps/drone
idf.py set-target esp32c3
idf.py -B build-testnet -DDRONE_CHAIN_ID=5042002 build
idf.py -p /dev/ttyUSB1 flash monitor
buyer serial monitor
boat-mer v1.0.1 buyer initialized
EOA: 0x…
BLE scan started, looking for IDLE seller...
Careful

It wipes the board's storage, makes a new key, and orphans anything deposited against the old address. A plain idf.py flash keeps the key.

5

Watch the slices arrive

Power both boards. The buyer finds the seller, checks its offer against its own policy, and the session opens. Every five seconds the seller asks for a payment, the buyer signs one, and a new slice appears in the UI. After six proofs or 30 seconds the seller sends a batch to settlement.

Note

Troubleshooting, the EIP-712 domain check, the separate Arc step and how to swap energy for your own resource are in From git clone to a two-device machine-payment flow.

Next#