BoAT MER Guide

Core concepts

Three capabilities, in the order you will use them. Each one stands on the one before it, so a device can stop at identity, add signed data, or go all the way to payments.

Device identity#

On first boot the device generates two keypairs and persists them through the platform layer:

  • Ed25519 signs attestations — fast, compact, chain-neutral.
  • secp256k1 signs payment authorizations and supports ecrecover, so an EVM settlement service can tell which device signed.

From them the device derives a did:mw:… identifier and an EVM address. The keys are not exported, not derived from a server secret, and not shared between the two sides of a payment. A device that loses its storage loses its identity — that is the intended trade.

c
boat_keypair_t kp;
boat_crypto_init(&kp);        /* load, or generate and persist */
printf("%s\n%s\n", kp.did, kp.eth_addr_hex);

Verifiable machine data#

An attestation is a SHA-256 hash of a reading, signed with the device's Ed25519 key. A third party holding the payload and the public key can check later that this device said this, unaltered.

c
boat_attestation_t att;
boat_attest_create(&kp, "{\"kwh\":0.417,\"t\":1756713600}", &att);

Unpaid attestation carries no chain binding. The paid submission path (boat_attest_submit_paid) speaks x402 against an eip155:<chain_id> network.

Note

It proves the device signed the reading and that it has not changed. Whether the reading was accurate still depends on the sensor, its calibration and the device's security.

Machine payments#

A payment authorization is an EIP-3009 transfer authorization over EIP-712 typed data, signed on the device. The device signs; it does not submit. A settlement service verifies the signature and carries it on-chain, often many at once.

c
boat_nano_auth_t auth;        /* 417 micro-USDC */
boat_nano_sign(&kp, payee, 417u, chain_id, verifier,
               "GatewayWalletBatched", "1", NULL, &auth);

uint8_t recovered[20];        /* what settlement does */
boat_nano_verify(&auth, chain_id, verifier,
                 "GatewayWalletBatched", "1", recovered);

The EIP-712 domain binds a signature to one chain and one verifying contract. Presented anywhere else, it does not verify — which is why the Quick Start ends with cross-chain correctly rejected.

Layers and headers#

TIER 4x402boat_x402.h TIER 3Paymentboat_nano.h · boat_pay.h TIER 2Attestationboat_attest.h TIER 1Identityboat_identity.h TIER 0Crypto key lives here boat_crypto.h PALYour portboat_pal.h · esp-idf · linux ENGINES BLE buyer BLE seller canonical 0xEE00 wire include directly #include "boat_mer.h" → tiers 0–4 + PAL
#include "boat_mer.h" pulls in tiers 0–4 and the platform layer. The BLE engine headers are not in that umbrella — include them directly.
TierHeaderWhat it does
0boat_crypto.hEd25519 and secp256k1 keygen, signing, ecrecover, Keccak-256, SHA-256
1boat_identity.hDID generation, device registration
2boat_attest.hSHA-256 + Ed25519, unpaid and paid submission
3boat_nano.h, boat_pay.hEIP-712 typed data, EIP-3009 sign / verify / settle
3boat_lightning.h, boat_hashkey.hadditional payment integrations
4boat_x402.hx402 in both directions: buyer pay, seller offer
—boat_buyer_nanopay.h, boat_seller_nanopay.h, boat_nano_wire.hBLE GATT buyer and seller engines
—boat_pal.hplatform abstraction