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.
Clone and build
The host build is the same code path a device runs, with the Linux platform layer underneath.
git clone https://github.com/TLAY-IO/boat-mer.git
cd boat-mer
cmake -B build && cmake --build buildRun the quickstart
One program walks through the three things the runtime does, then checks the result the way a settlement service would.
./build/quickstartexamples/quickstart/main.c does, in order. Nothing in it touches a network.Read the output
Your keys and nonce will differ; the shape will not.
=== 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 storageand 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.
Run the tests
More than 60 checks across crypto, EIP-712, identity, attestation, payments, x402, Lightning and the nanopayment path.
./build/test_all
./build/test_buyer # the buyer engine, including the replay guardYou 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.
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.
Clone the demo
git clone --branch v1.0.0 --depth 1 https://github.com/TLAY-IO/arc-drone-show-demo
cd arc-drone-show-demoapps/drone is the buyer firmware, apps/ecandle the seller firmware, and cloud/ holds the broker, the settlement worker and the demo UI.
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.
cp cloud/.env.example cloud/.env
cd cloud
./mosquitto/gen-passwd.sh
docker compose upSet 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.
Flash the seller
Set the broker URI in menuconfig to mqtt://device:<device-password>@<your-LAN-IP>:1883, then flash.
cd apps/ecandle
idf.py set-target esp32c3
idf.py menuconfig
idf.py -p /dev/ttyUSB0 flash monitorboat-mer v1.0.1 seller initialized BLE adv mfg_data[5] = 0 (IDLE, ready to connect)
Flash the buyer
The buyer makes its own key on first boot and prints only its address.
cd apps/drone
idf.py set-target esp32c3
idf.py -B build-testnet -DDRONE_CHAIN_ID=5042002 build
idf.py -p /dev/ttyUSB1 flash monitorboat-mer v1.0.1 buyer initialized EOA: 0x… BLE scan started, looking for IDLE seller...
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.
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.
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.