// Introduction

Lindblad Protocol Documentation

Lindblad Protocol is an open protocol with physics-enforced hardware security. This documentation covers the public components — smart contracts, API reference, protocol specification, and user guides.

All source code, contracts, and specifications are available on GitHub at github.com/lindblad-protocol.


// Base URL
API Endpoint  https://lindblad.io
Explorer      https://lindblad.io/scan
Wallet        https://lindblad.io/wallet

// Smart Contracts — Arbitrum One
LindblabUSDT  0x7e0f53f04dDc48dFdc96DFE93606a73f0dCF56A3
LindblabUSDC  0x1AfC80b30cBBE50E8aBb4585f53ff530c305d416
PYCO          0x16a69CcdA3865a23537d46055dC6564A2813C36B

// Smart Contracts — Polygon
LindblabUSDT  0x17c6d525A8D809fcBe78aBE4FCaE1F9ddb0b8fa8
LindblabUSDC  0x9964c63Af739bf8b4702E243f904570b17F33ab4
// Smart Contracts

Deployed Contracts

All contracts are verified and auditable on-chain. Source code available at github.com/lindblad-protocol/contracts.

ContractAddressNetwork
LindblabUSDT v30x7e0f53f04dDc48dFdc96DFE93606a73f0dCF56A3Arbitrum One
LindblabUSDC v30x1AfC80b30cBBE50E8aBb4585f53ff530c305d416Arbitrum One
PYCO ERC-200x16a69CcdA3865a23537d46055dC6564A2813C36BArbitrum One
LindblabUSDT v30x17c6d525A8D809fcBe78aBE4FCaE1F9ddb0b8fa8Polygon
LindblabUSDC v30x9964c63Af739bf8b4702E243f904570b17F33ab4Polygon
M2MEscrow0xdeaED8e809733667D80a8E6ca40A02366598CA60Arbitrum Sepolia
MockUSDC (M2M demo)0xa6Ee2f4248b447f934Aabf44aA534C6C21654F6cArbitrum Sepolia
M2MEscrow (mirror)0x16a69CcdA3865a23537d46055dC6564A2813C36BRobinhood Chain Testnet

Bridge contracts accept USDT/USDC deposits on Arbitrum One and Polygon, verify P-256 ECDSA signatures from certified hardware nodes, and release funds on withdrawal. PYCO is the native token of the entire network regardless of which chain the deposit originates from. Exit fees are 0.1% in PYCO — 50% burned, 50% distributed to node operators.

M2MEscrow is the smart contract enforcing the M2M Commerce lifecycle (request → accept → attest → settle) on Arbitrum Sepolia. The same logic is mirrored on Robinhood Chain Testnet. See the M2M Commerce Model section for the full architecture.

// Protocol

Lindblad Cryptography Protocol

LCP is a four-layer hardware protocol that simultaneously proves the identity, time, and location of every cryptographic signing event. Full mathematical specification at github.com/lindblad-protocol/spec.

LayerTechnologyProves
L1 — IdentitySRAM PUFWHO signed (silicon fingerprint)
L2 — SigningP-256 ECDSAWHAT was signed (EVM-compatible)
L3 — TimeChua HSCWHEN it was signed (physical entropy)
L4 — ConsensusLindblad Master Eq.Network state (thermodynamic finality)
// Lindblad master equation — L4 consensus
dρ/dt = -i[H,ρ] + Σₖ(LₖρLₖ† - ½{Lₖ†Lₖ,ρ})

// ρ = density matrix (network state)
// Lₖ = dissipation operators (encode irreversibility)
// Thermodynamic dissipation = immutability
// Spectral Ledger

The Spectral Ledger

The Spectral Ledger is the universal token transport layer of the Lindblad network. Internal transfers between LD addresses are instant and free. Bridge exits to Arbitrum require hardware signing and incur the 0.1% PYCO fee.

// Transaction types
INTERNAL   LD-addr → LD-addr          // free, instant
DEPOSIT    Arbitrum/Polygon → LD-addr // on-chain event → Spectral credit
WITHDRAW   LD-addr → Arbitrum/Polygon // hardware sign + 0.1% PYCO fee
// Node Identity

LDXXXXXXX Address Format

Every participant on the Spectral Ledger is identified by their LDXXXXXXX address — derived from the hardware PUF fingerprint of their device.

// Address format
Full PUF      95A8xxxxxxxxxxxx   // 16 hex chars (hardware)
Short ID      LD95A821D           // LD + first 7 (display)
Full address  LD-95A8xxxxxxxxxxxx // used in API calls
// Protocol

RWAFi Model

RWAFi (Real-World Asset Finance) is the architectural pattern enabled by the Lindblad stack: physical attestation, native token minting, and AMM markets unified in a single layer with end-to-end cryptographic verification.

The pattern consists of three sequential primitives, each backed by the same Lindblad Cryptography Protocol:

1. Attest

A physical hardware node measures a real-world value (energy generation, sensor reading, extraction volume) and signs it using its silicon-derived private key. The signature includes a Chua HSC nonce — a non-replayable timestamp from chaotic electrical noise. Verifiable independently via /verify-l2/{signId}.

2. Mint

Once an attestation is recorded, the producer decides what percentage of the attested quantity becomes a liquid token (e.g., 75% of 72,000 kWh → 54,000 GREENKWH tokens). The remainder is registered as physical-use (sold via grid / PPA / self-consumption). Tokens are native to the Spectral Ledger — no bridge required.

The mint percentage can be increased later via recalibration, but never decreased (already-minted tokens cannot be retracted, as downstream holders own a claim).

3. Trade

Minted RWAFi tokens become tradable on LindFi pools paired with stablecoins (e.g., GREENKWH/USDT). The pool establishes a market price through standard constant-product AMM mechanics. External arbitrage anchors the price to real-world markets for the underlying asset (electricity wholesale, commodity spot, etc.).

Pool Categories

LindFi distinguishes two categories of pools, detected automatically from the tokens involved:

DeFi Pools — bridged stablecoins or native cryptocurrencies on both sides (e.g., USDC/USDT)
RWAFi Pools — at least one side is a token minted from a physical attestation (e.g., GREENKWH/USDT)

The current set of RWAFi-native tokens is small but extensible. Adding a new vertical (lithium, carbon credits, agricultural commodities) requires registering its token name in the attestation pipeline.

Live closed-loop example available at /oracle — real attestation, mint, and market data refreshing every 30 seconds.

// Protocol

M2M Commerce Model

M2M Commerce (Machine-to-Machine Commerce) is the second application built on the Lindblad protocol. Two autonomous machines, each with a hardware-attested Lindblad identity, can negotiate a service, deliver it, and settle payment — without any human intermediary or third-party custodian.

The pattern relies on the same foundation as RWAFi: silicon-derived identity (PUF), cryptographic signing (ECDSA P-256), and on-chain verification. The difference is that here the asset being transacted is a service, not a measurement.

Lifecycle

Each M2M transaction passes through five states managed by the M2MEscrow smart contract:

Requested — Client locks payment in escrow, specifies provider + service terms
Accepted — Provider confirms terms, agreement is binding
InProgress — Provider delivers service, attesting milestones on-chain
Delivered — Service complete, payment auto-released to provider
Cancelled — Either party cancels before delivery; funds refund to client

Identity

Both client and provider machines must hold a Lindblad node whose Ethereum address has been registered in M2MEscrow.isNodeRegistered(). The address is derived from the node's public key (keccak256(pubKey[1:])[-20:]) — itself derived from the silicon PUF in real time via BCH(255,139,t=15) fuzzy extractor. The key exists only inside that exact piece of silicon, recovered when needed, never stored.

Settlement

When the provider attests sufficient delivery (configurable threshold), the contract automatically releases the escrowed payment. Partial delivery results in proportional payment plus refund of the remainder. Deadline enforcement ensures stuck transactions can be resolved by either party.

Use Cases

Any service where a measurable unit of work is delivered between autonomous systems:

  • Energy — autonomous EV charging at a hardware-attested station
  • Compute — edge nodes selling CPU/GPU cycles by the second
  • Data — IoT sensors selling data feeds with cryptographic provenance
  • Bandwidth — mesh network nodes selling traffic relay
  • Storage — distributed storage with hardware-attested data integrity

Deployments

M2MEscrow is currently deployed on:

  • Arbitrum Sepolia — primary testnet, contract verified on Arbiscan
  • Robinhood Chain Testnet — mirror deployment for cross-chain validation

Live demos: /m2m (educational walkthrough with real on-chain links) and /m2m-live (live hardware verification with a connected Lindblad node).

// API Reference

Chain & Blocks

Base URL: https://lindblad.io — all endpoints are public, no authentication required.

GET /chain Chain summary
Returns blockCount, latestEpoch, totalMined, totalBurned.

curl https://lindblad.io/chain
GET /blocks Recent blocks
Returns the last 50 blocks with epoch, digest, node count, and transaction count.

curl https://lindblad.io/blocks
GET /block/latest Latest block
Returns the most recent block with full attestation data.

curl https://lindblad.io/block/latest
// API Reference

Accounts & Balances

GET /account/{LD-address} PYCO balance
Returns PYCO balance for the given LD address.

curl https://lindblad.io/account/LD-95A8xxxxxxxxxxxx
GET /token-balance/{LD-address}?token=USDT&network=arbitrum Token balance
Returns balance for USDT, USDC, or PYCO on the specified network. network accepts arbitrum or polygon (default: arbitrum). Amounts in microunits (divide by 1,000,000).

curl "https://lindblad.io/token-balance/LD-95A8xxxxxxxxxxxx?token=USDT&network=polygon"
POST /send-token Internal transfer
Transfer tokens between LD addresses. Free and instant. Requires device signature.

Body: { from, to, token, amount, sig }
GET /activity?address={LD-address}&limit=20 Transaction history
Returns transaction history for an address — sends, receives, deposits, and withdrawals.

curl "https://lindblad.io/activity?address=LD-95A8xxxxxxxxxxxx"
// API Reference

Bridge

GET /node-challenge?nodeId={id} Signing challenge
Returns a challenge for hardware signing before withdrawal. Expires in 60 seconds.

curl "https://lindblad.io/node-challenge?nodeId=LD95A821D"
POST /request-sign Request hardware signature
Queues a signing request for a hardware node. Node responds within 30s.

Body: { nodeId, challenge, amount, token, toAddress }
GET /get-sign?signId={id} Poll for signature
Poll for hardware signing result. Status: pending | complete | expired
// API Reference

Nodes

GET /node-list All nodes
Returns all registered nodes with ID, status (active/idle), and last epoch.

curl https://lindblad.io/node-list
GET /node-status?nodeId={id} Node online status
Returns whether a node is currently online (last seen within 120 seconds).

curl "https://lindblad.io/node-status?nodeId=LD95A821D"
GET /device/nodes?puf={puf} Nodes for a device
Returns all nodes authorized for a given device PUF.

curl "https://lindblad.io/device/nodes?puf=95A8xxxxxxxxxxxx"
// External Verification

Cryptographic Verification

Every PUF-signed operation in Lindblad — pool swaps, liquidity changes, oracle attestations — is mathematically verifiable by anyone, anywhere, without trusting Lindblad. The protocol exposes public endpoints so that any third party can independently confirm a signature was generated by a specific physical node.

This works because Lindblad uses standard ECDSA P-256 signatures backed by silicon-derived private keys. The public keys are public by design — the security comes from the fact that the corresponding private keys live only inside the SRAM PUF of each chip and never leave the hardware.

The Message Contract

When a node signs a challenge, the firmware constructs the message as:

msg = challenge + NODE_ID + str(ts) + chuaNonce_HEX_UPPERCASE
hash = SHA-256(msg)
(r, s) = ECDSA_P256_sign(hash, private_key)

The chuaNonce comes from the Chua HSC chaotic circuit (real electrical noise), making the signature unrepeatable even by the same hardware. The private key is derived from the SRAM PUF via a BCH(255,139,t=15) fuzzy extractor at boot and never persists to flash.

GET /node-keys Public keys of all nodes
Returns all registered node public keys (uncompressed P-256, 130 hex chars with 04 prefix).

curl https://lindblad.io/node-keys
GET /node-keys/{nodeId} Public key for a node
Returns the registered public key, PUF, and capture timestamp for a specific node.

curl https://lindblad.io/node-keys/LD95A821D
GET /verify-l2/{signId} Verify an ECDSA signature
Reconstructs the signed message from the stored components and verifies the ECDSA (r, s) signature against the node's registered public key. Returns verified: true | false | null and the SHA-256 hash of the reconstructed message.

curl https://lindblad.io/verify-l2/0e8029bb
GET /get-sign?signId={id} Get raw signature data
Returns the full signature payload (challenge, ts, r, s, puf, chuaNonce, status) — everything needed to verify the signature offline with any standard ECDSA library.

curl "https://lindblad.io/get-sign?signId=0e8029bb"

Verify Independently in Python

You don't need Lindblad's code. Any standard cryptography library on any platform works. Example with Python's cryptography package:

# pip install cryptography requests
import hashlib, requests
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature
from cryptography.hazmat.primitives import hashes

SIGN_ID = "0e8029bb"
NODE_ID = "LD95A821D"

# 1. Fetch signature data (public endpoint)
sign = requests.get(f"https://lindblad.io/get-sign?signId={SIGN_ID}").json()

# 2. Fetch the node's public key (public endpoint)
key = requests.get(f"https://lindblad.io/node-keys/{NODE_ID}").json()

# 3. Reconstruct the exact message the firmware signed
msg = sign["challenge"] + NODE_ID + str(sign["ts"]) + sign["chuaNonce"].upper()

# 4. Verify with standard ECDSA-P256
pub = ec.EllipticCurvePublicKey.from_encoded_point(
    ec.SECP256R1(), bytes.fromhex(key["public_key"]))
sig = encode_dss_signature(int(sign["r"], 16), int(sign["s"], 16))

pub.verify(sig, msg.encode(), ec.ECDSA(hashes.SHA256()))
print("✅ Signature valid — provably signed by", NODE_ID)

If anything has been tampered with — the value, the timestamp, the device identity — pub.verify() raises InvalidSignature. The check passes only if the signature was actually generated by the private key inside the physical chip whose public key is published at /node-keys/{nodeId}.

Equivalent verification can be implemented in JavaScript (using @noble/curves or Web Crypto API), Go (crypto/ecdsa), Rust (p256 crate), or OpenSSL CLI. The signature format and message contract are identical across all clients.

// API Reference

RWAFi & Energy Attestations

Endpoints for attesting real-world energy generation and minting native GREENKWH tokens. The workflow:

  1. GET /attestations/energy/quote — fetches latest renewable generation from EIA and creates a pending sign request
  2. The hardware node detects the pending sign, signs the challenge with its PUF-derived key
  3. POST /attestations/energy/submit — finalizes the attestation and mints GREENKWH tokens to the producer
GET /attestations/energy/quote Fetch real-time generation data
Query parameters: respondent (default: CAL for California ISO; other values: ERCO, ISNE, MIDA, NW, etc.), fuel (default: SUN for solar), nodeId (required, the LD address of the attesting node).

Returns: the most recent hourly generation value ≥10 MWh in the last 48 hours, plus a signId for the pending signature request.

curl "https://lindblad.io/attestations/energy/quote?respondent=CAL&nodeId=LD95A821D"
POST /attestations/energy/submit Finalize attestation and mint tokens
Body: {signId, mintPercentage, recipient}. mintPercentage is in basis points (0-10000, where 5000 = 50%). recipient is the LD-address that will receive the minted GREENKWH tokens.

Records the attestation with the full signature, mints kwh_total × mintPercentage / 10000 tokens to recipient, and registers the remainder as physical-use. Response includes level2_verified for the ECDSA check.
POST /attestations/energy/recalibrate Increase mint percentage
Body: {attestationId, newMintPercentage, signId}. Requires a fresh PUF signature from the same node that signed the original attestation. Challenge format must be exactly: recalibrate_<attestationId>_<newPct>_<timestamp> — binding the signature to that specific recalibration.

Only upward recalibration is allowed (already-minted tokens cannot be retracted). Mints only the delta to the original recipient and records the change in the audit trail.
GET /attestations/energy List recent energy attestations
Query parameter: limit (default 20). Returns all recorded energy attestations with their kWh values, mint percentages, recipients, and current status.

curl https://lindblad.io/attestations/energy?limit=5
GET /attestations/energy/recalibrations/{attestationId} Audit trail of recalibrations
Returns the chronological history of all recalibrations applied to a specific attestation — each with its old/new mint percentage, delta minted, and signature ID.

curl https://lindblad.io/attestations/energy/recalibrations/394289f25657
GET /tokens/available List tokens by category
Returns all tokens currently active in the system, grouped as defi_tokens (bridged or crypto-native) and rwafi_tokens (minted from physical attestations). Includes total supply per token. Used by the LindFi UI to populate the Create Pool modal.

curl https://lindblad.io/tokens/available
// API Reference

LindFi Pools

AMM endpoints for liquidity pools. Pools are constant-product (x·y=k) with configurable fees in basis points. All operations that change reserves (add, remove, swap) require a PUF-signed authorization from a hardware node.

Pools are automatically categorized as defi or rwafi based on the tokens involved. See the RWAFi Model section for details.

GET /pools List all pools
Returns all pools with reserves, LP supply, fee, price, and category. Sorted by liquidity descending.

curl https://lindblad.io/pools
GET /pool/{poolId} Pool state
Returns full state of a specific pool: tokens, reserves, LP supply, fee, current price.

curl https://lindblad.io/pool/GREENKWH-USDT
POST /pool/create Create a new pool
Body: {tokenA, tokenB, ldAddress, feeBps}. feeBps is the swap fee in basis points (default 5 = 0.05%, typical RWAFi pools use 30 = 0.30%). Category is detected automatically.

Anyone can create a pool, but initial liquidity must be added separately via /pool/add before it becomes tradable.
POST /pool/add Add liquidity (PUF-signed)
Body: {poolId, ldAddress, amountA, amountB, signId}. Amounts in microunits (token × 1,000,000). LP shares minted proportionally to the geometric mean of the deposit. The signId must be a completed PUF signature from a node authorized for the depositor's address.
POST /pool/remove Remove liquidity (PUF-signed)
Body: {poolId, ldAddress, lpAmount, signId}. Burns the specified LP shares and returns the proportional amount of both reserve tokens to the depositor.
POST /pool/swap Swap tokens (PUF-signed)
Body: {poolId, ldAddress, tokenIn, amountIn, signId}. Executes a constant-product swap, applies the pool fee, and distributes the fee proportionally to LP holders based on their PCV-4-weighted share. Response includes level2_verified.
GET /pool-lp/{poolId}?address={addr} LP position
Returns the LP shares held by a specific address, plus the percentage share of the pool.
GET /pool-swaps/{poolId}?limit={n} Recent swaps
Returns the most recent swaps in a pool, with timestamps, input/output amounts, and the executing address.
GET /pool-apr/{poolId}?hours={n} Annualized fee yield
Returns an estimated APR based on swap fees collected in the last N hours, extrapolated to a yearly rate.
// API Reference

M2M Hardware API

Endpoints served directly by Lindblad hardware nodes (e.g., Heltec V3 running the Lindblad firmware). These run locally on the device's HTTP server, typically over the LAN at http://<node-ip>. The node's IP appears on the LCD display at boot. All cryptographic operations are performed inside the node — keys are derived from PUF in real time and never leave the silicon.

GET /api/challenge Fresh challenge from PUF entropy
Returns a unique challenge derived from PUF + Chua HSC oscillator + timestamp. Each call produces a different value — non-replayable by design.

curl http://<node-ip>/api/challenge

Response: {challenge, nodeId, ts, pubKey}. pubKey is the uncompressed ECDSA P-256 public key (130 hex characters, starts with 04). The Ethereum-compatible address can be derived as keccak256(pubKey[1:])[-20:].
POST /api/sign Sign a challenge with PUF-derived key
Signs SHA256(challenge || nodeId || timestamp || chuaNonce) with the node's ECDSA P-256 private key (derived in real time from PUF via BCH fuzzy extractor). The signature is EVM-compatible and verifiable on any chain.

Body: {challenge}. Use Content-Type text/plain to bypass browser CORS preflight (the firmware reads raw body, content-type is informational).

Response: {ecSignature, chuaNonce, pubKey}. ecSignature is the DER-encoded ECDSA signature. chuaNonce is the entropy contribution from the Chua HSC oscillator used in message hashing.
GET /api/status Node operational status
Returns the node's identity, network info, mining status, and PUF coherence indicators. Useful for monitoring and field diagnostics.

curl http://<node-ip>/api/status
// Smart Contract

M2M Escrow Contract

The M2MEscrow contract enforces the M2M Commerce lifecycle on EVM-compatible chains. Currently deployed on Arbitrum Sepolia (0xdeaED8e809733667D80a8E6ca40A02366598CA60) and mirrored on Robinhood Chain Testnet. Source code is verified on Arbiscan and available on GitHub.

Only addresses registered as Lindblad nodes (via isNodeRegistered) can request, accept, or attest. The registry is controlled by the Lindblad Oracle for the duration of the testnet phase. Future iterations will use on-chain PUF signature verification for fully permissionless registration.

VIEW isNodeRegistered(address) Check if a node is authorized
Returns true if the given Ethereum address has been registered as a Lindblad node and is authorized to participate in M2M commerce. Derive the address from the node's pubKey: keccak256(pubKey[1:])[-20:].
CALL requestService(provider, units, pricePerUnit, maxAmount, deadline, serviceType) Client requests service from provider
Locks maxAmount of payment token in escrow. Client must first approve() the contract for at least maxAmount. serviceType is a free-form string identifying the service (e.g., "EV_CHARGE", "COMPUTE_GPU"). Returns a unique contractId.
CALL acceptService(contractId) Provider accepts the request
Provider confirms the agreement. State transitions from Requested to Accepted. Once accepted, both parties are bound until delivery completes or cancellation conditions are met.
CALL attestDelivery(contractId, deliveredAmount, attestationHash) Provider records delivery progress
Provider attests cumulative delivery (in units). attestationHash is the off-chain hash of the delivery proof (e.g., sensor readings, signed delivery receipts). When delivered amount reaches the requested total, payment is auto-released to the provider and state transitions to Delivered.
CALL settlePayment(contractId) Manual settlement after deadline
Either party can force settlement after the deadline has passed. Settles payment proportionally to the amount already attested as delivered. Any remainder is refunded to the client.
VIEW getContract(contractId) Read full contract state
Returns the full contract details: client, provider, payment token, amounts, delivered units, state, and timestamps.
// Guide

Using LindWallet

LindWallet runs at lindblad.io/wallet. No installation required. Your device key is generated from your hardware fingerprint on first visit and stored locally.

Deposit USDT or USDC: Connect MetaMask → Bridge tab → select token → enter amount → Deposit. Funds appear on the Spectral Ledger within 30 seconds.

Send internally: Send tab → enter destination LDXXXXXXX → enter amount → confirm. Instant and free.

Withdraw to Arbitrum or Polygon: Bridge tab → Withdraw → select network → select signer → enter destination → Withdraw. Hardware signs the transaction. 0.1% PYCO fee applies.

Connect a node: My Accounts → + → enter node LDXXXXXXX → enter pairing code → Pair. Pairing code is generated by the node and valid for 5 minutes.

// Guide

Running a Node

Step 1 — Power on: Connect your Lindblad node to power. The hardware boots and generates its unique LDXXXXXXX address from the silicon PUF.

Step 2 — WiFi setup: Connect your phone to "Lindblad-Setup". A captive portal opens — enter your home WiFi credentials. The node joins your network automatically.

Step 3 — Pair with LindWallet: My Accounts → + → enter the node LDXXXXXXX → enter the 6-character pairing code from the node → Pair.

Step 4 — Mining starts: The node begins submitting blocks every ~30 seconds and accumulates PYCO weighted by its Physical Coherence Score. Monitor at lindblad.io/nodes.

// Guide

Bridge Guide

Deposit: Approve USDT/USDC → call deposit() on the bridge contract (Arbitrum One or Polygon) → VPS detects the on-chain event → credits your LD address on the Spectral Ledger.

Withdrawal: Request withdrawal → select target network (Arbitrum One or Polygon) → VPS creates signing challenge → your hardware node signs with PUF+ECDSA → VPS submits to contract → tokens released to your address.

Fee: 0.1% of withdrawal amount in PYCO. 50% burned permanently. 50% to active nodes weighted by CV Score.

// Withdrawal flow
GET  /node-challenge?nodeId=LDXXXXXXX
POST /request-sign  → { signId }
GET  /get-sign?signId=...  → { r, s, v }
// Submit r, s, v to bridge contract on Arbitrum One or Polygon