Mastodon

How a $15 RISC-V Device Built Its Own Lightning Wallet — and Learned to Pay the Internet

This is the era of native machine-to-machine payments: autonomous AI agents that don't just consume information, but pay for it, on the spot, without human intervention, using the internet's own protocol.

Compartilhar
How a $15 RISC-V Device Built Its Own Lightning Wallet — and Learned to Pay the Internet

The internet is entering its third economic era. The first was the era of free information — static pages, banners, the advertising model that turned attention into a commodity. The second was the era of subscriptions and paywalls — SaaS, streaming, the recurring model that trapped revenue inside credit cards and financial intermediaries. The third era is native machine-to-machine payments: autonomous AI agents that don't just consume information, but pay for it, on the spot, without human intervention, using the internet's own protocol.

HTTP status code 402 — "Payment Required" — was reserved in 1997 by Tim Berners-Lee and never implemented. It lay there, dormant, like a prophecy waiting for the infrastructure. Three decades later, the infrastructure arrived: Bitcoin, the Lightning Network, and a protocol called Nostr Wallet Connect (NIP-47) that lets any Lightning wallet communicate with applications through Nostr relays. Add AI agents with autonomous execution capability and you have the recipe for a complete reinvention of how value is exchanged on the internet.

What I'm about to tell you isn't theory. It's the story of how a US$ 15 device running Linux on RISC-V — the LicheeRV Nano, christened Mecha Gerard — built its own Lightning wallet, received its first Bitcoin payment during a live stream, and then learned to pay for APIs across the internet fully autonomously. All in pure Python. No Node.js. No native dependencies. No excuses.

I recently acquired a LicheeRV Nano board (RISC-V) to run some tests with local models and an AI agent — Picoclaw, a "clone" of Openclaw (open-source in Go, cross-compiled) that the manufacturer made available, and which runs with 10 MB of RAM.

I also got a compatible camera (GC4653) to use with a local image analysis model, since the board has a 1 TOPS NPU.

The idea of having a tiny device, found on the market for around US$ 15, running local models and an agent on Linux is deeply interesting because it dismantles all the hype around buying Mac minis "to run API-based models." The cost would definitely be worth the experience.

💡
If you enjoy this content, I'll later detail the journey of training a local model with images of birds here in Estonia, to detect and notify when a crow shows up stealing from our bird feeder — in part 2 and/or 3, using the LicheeRV Nano.

After exploring the compilation of a Linux (Buildroot) for RISC-V, the journey to access the hardware in C++, the camera, enabling native encoders to spin up a streaming service, training and uploading a model to the NPU for real-time detection of people, objects (and birds), and playing around with the native AI agent on it, I decided to give it a body and a power bank so it would have total autonomy.

I present to you, Mecha Gerard:

20260508_220424.gif

I created several skills for the agent — taking photos, enabling streaming, uploading models to identify poses, people, objects, and birds — and the experience of working on a fully autonomous device connected to agentic AIs left me even more curious about the possibilities I could explore.

That's when the chat, during Morning Crypto #950, complained that they couldn't send sats (satoshis) and I discovered that my Lightning Network node (I'm using Alby Hub self-hosted) was down.

After the live stream ended, I jumped into the server to see what had happened and discovered there was an update for Alby Hub, where they had added a skill for AI agents to make Bitcoin payments using the internet's native protocol (status code 402), which has been under development by several initiatives in the cryptocurrency ecosystem. L402 for native Bitcoin payments via the Lightning Network, x402 — promoted and developed by Coinbase for multiple cryptocurrencies and stablecoins (chain-agnostic), and MPP — being developed by Stripe and their Tempo blockchain. I already wrote an article on this topic last year.

Since I've been following the development of these protocols for a while, when I saw the instructions to run the skill on my node, I thought I should test it because I genuinely believe that using status code 402 through protocols like L402 and x402, with automated payments by AI agents, is the future of digital payments.

After getting my Lightning node back online, I imagined how interesting it would be if Mecha Gerard had its own Lightning wallet and made payments autonomously across the internet.

So I created an independent wallet on my node and began the saga of trying to run the skill provided by Alby Hub inside Gerard.

The device doesn't have Node.js (widely used for Openclaw agents). It also has no package manager. And every application needs to be compiled for RISC-V — which is unfortunately a limitation. If we struggle to run certain applications on a Raspberry Pi (RPi) due to the AARCH64 (ARM64) architecture, imagine the scarcity of resources for a processor used almost exclusively for embedded devices. On top of that, Node.js would still require storage and memory that I don't have available on the device.

But since I already have Python running on it, I decided to look for an application that communicates with Lightning using the Nostr Wallet Connect protocol (simple and easy to integrate with Alby Hub and other wallets). That's when I hit another problem: all the Python apps I found import dependencies that compile the entire cryptography layer on the device at install time. The reason is simple: binary code performs far better than interpreted code. However, being an embedded device with severe memory and storage constraints, there wasn't a toolchain available to complete the application installation locally.

So I decided to use the agent inside Mecha Gerard itself to build its own Lightning wallet (inspired by the skill published by Alby Hub) — but entirely in Python, with no dependencies on the cryptography side (rebuilding all necessary cryptographic algorithms from scratch), already accounting for the constrained environment of the embedded RISC-V device.

Then I gathered all the references needed to build everything from scratch: how Bitcoin's cryptographic primitives work (I had already rebuilt RSA from scratch a while back, and also built a proof of concept for using Bitcoin private keys and their cryptographic primitives to encrypt content — among other projects of the kind), and all the specifications I would need.

With the specs in hand — NIP-47 (Nostr Wallet Connect), BIP-340 (Schnorr Signatures), RFC 6979 (Deterministic Nonces), GetAlby Payment Skill, and the Python NWC SDK — I could prepare the project on Picoclaw (the agent inside Mecha Gerard) and start execution.

It was fascinating to watch Gerard building its own wallet during Morning Crypto. Many attempts and errors until all the end-to-end tests passed. With that, it finished its own wallet entirely in Python, which has no external dependencies and can be audited in very little time.

Then I asked Gerard to generate a 1,000 satoshi Lightning invoice, which was voluntarily paid by DevWalker (thank you!). And just like that, Gerard received its first Bitcoin payment — still during the live stream — into the wallet it had just finished building inside the device.

We did a few more send and receive tests and it was a success! Then we had another idea: what if Gerard could browse the internet and pay for things autonomously — make purchases, access paid content, etc.?

I promised that after the live stream I'd think more about how to implement it.

After the live stream, I downloaded the code from inside Gerard to do a code review (because until then we had no idea how the skill had actually worked). And I can say that, although it worked, the code was a disaster. Code review and security assessment are essential for any AI-driven development — beyond the obvious need for constant monitoring and supervision — as I wrote about the risks in this recent article.

So I dug into the specifications for the L402 and x402 protocols and looked up references again in Alby Hub's Node.js payment skill.

With that, I implemented the payment methods in the tool, allowing the AI agent — when navigating to a link and detecting that it requires payment — to make the payment and then gain access to the content or product automatically.

So now you just ask the agent to access a link and it will execute the entire process for you, autonomously, using the resources of its own configured Bitcoin wallet.

You can watch everything in Morning Crypto episodes 950 and 951.


NWC Agent: The Technical Skill

After that post-live code review — where Gerard's code worked but was a structural disaster — came the result: nwc-agent: a Lightning wallet for autonomous AI agents. Zero native dependencies for cryptography. Pure Python. Runs on RISC-V, ARM, x86_64. Works with any NIP-47-compatible wallet (Alby Hub, CoinOS, Rizful, LNCURL).

Why rebuild all the cryptography in Python?

The question everyone asks: why not use an off-the-shelf library? Besides the clear dependency incompatibility, the answer also lies in the supply chain.

Between 2024 and 2026, the open-source software ecosystem went through an unprecedented escalation of supply chain attacks. The backdoor in xz (CVE-2024-3094) nearly compromised SSH across every Linux distribution — it was detected because a Microsoft engineer noticed 500 ms of latency in SSH logins. In March 2025, the GitHub Action tj-actions/changed-files, used by over 23,000 repositories, was compromised and exfiltrated CI/CD secrets in plaintext. Sonatype identified more than 454,600 new malicious packages in 2025 alone. And in March 2026, a coordinated wave compromised five open-source packages in 12 days — including LiteLLM, the LLM API gateway used by AI agents to call OpenAI, Anthropic, and other providers.

Every dependency is an attack surface. When an autonomous agent holds spending power, a compromised dependency doesn't leak data — it drains funds.

nwc-agent solves this with a radical philosophy:

  • 3 dependencies. That's it. pyaes (AES in pure Python), websocket-client, pyyaml. None compile native code. None have C extensions.
  • ~1,400 lines of auditable cryptography. The entire cryptographic stack — secp256k1 elliptic curve arithmetic, BIP-340 Schnorr signatures with RFC 6979 deterministic nonces, ChaCha20-Poly1305 encryption for NIP-44, HKDF derivation, DER encoding for EC keys — is in readable Python, in a single file (nwc_wallet.py). You can read it all in one sitting and verify there are no network calls to unknown hosts, no obfuscated blobs, no auto-updating dependency trees.

Compare that with the alternatives:

| Solution | Dependencies | Native Code | Attack Surface |

|---------|-------------|---------------|---------------------|

| nwc-agent | 3 (pure Python) | 0 lines | Minimal |

| @getalby/sdk (Node.js) | 200+ transitive | native secp256k1 | High |

| python_nwc (reference) | secp256k1 + pycryptodome | C extensions | Medium |

| LND (gRPC) | Full Go toolchain | Entire LND stack | Very High |

Payment Protocols: L402, X402, and MPP

The skill supports three HTTP 402-based protocols. The fetch command does automatic detection — you pass the URL and it figures out which protocol to use:

python3 scripts/nwc_wallet.py fetch https://api.example.com/v1/generate

L402 (Lightning Service Authentication Token): The most common protocol. The server responds with 402 Payment Required + header WWW-Authenticate: L402 token=, invoice=. The client extracts the Bolt11 invoice, pays via NWC, then retries the request with Authorization: L402:. The macaroon + preimage are reusable — pay once and use curl with the authorization header for all subsequent requests to the same proxy.

X402: Alternative promoted by Coinbase. The challenge comes in a PAYMENT-REQUIRED header with base64-encoded JSON. Supports multiple payment methods — the client finds the lightning entry, pays the invoice, and responds with payment-signature. Includes value verification: if the invoice doesn't match what's declared in the challenge, the payment is aborted.

MPP (Multi-Party Payments): Based on the draft-lightning-charge-00 specification, using JCS (JSON Canonicalization Scheme) credentials. The challenge is base64url-encoded.

Detection is fully automatic in the dispatcher (nwc_fetch.py): first checks WWW-Authenticate for "L402", then PAYMENT-REQUIRED (X402), then WWW-Authenticate for "Payment" + "lightning" (MPP). If the server returns 402 without any recognized protocol (e.g., payment in USDC or ETH), the command reports "no supported payment protocol" — only Bitcoin/Lightning are supported.

Commands and Interface

The entire interface is designed for LLM function-calling, not for interactive human use. Every command returns structured JSON to stdout. Every error goes to stderr.

Wallet operations:

| Command | Arguments | Return |

|---------|-----------|---------|

| balance | — | Balance in satoshis |

| pay_invoice | | {"paid": true, "preimage": "..."} |

| pay_invoice_async | | Fire-and-forget (check later) |

| make_invoice | [desc] | Bolt11 Invoice |

| lookup_invoice | | Status and details |

| check_payment | | {"paid": true/false} |

| list_transactions | [type] [limit] [offset] | JSON array of transactions |

| get_info | — | Wallet alias, supported methods |

HTTP 402 payments:

python3 scripts/nwc_wallet.py fetch <url>
python3 scripts/nwc_wallet.py fetch --method POST --body '{"key":"val"}' <url>
python3 scripts/nwc_wallet.py fetch --max-amount 1000 <url>

After a successful first fetch, save the macaroon and preimage and use curl directly — don't call fetch twice for the same proxy; each call triggers a new payment:

curl -s "https://proxy.example.com/resource" \
  -H "Authorization: L402 ${MACAROON}:${PREIMAGE}"

Service discovery:

python3 scripts/nwc_wallet.py discover -q "image generation"
python3 scripts/nwc_wallet.py discover -p x402

The discover command queries 402index.io and returns only services that accept payments via Bitcoin/Lightning.

Fiat/sats conversion (via CoinGecko API, no wallet needed):

python3 scripts/nwc_wallet.py fiat_to_sats 10 USD    # 10 USD → sats
python3 scripts/nwc_wallet.py sats_to_fiat 1000 EUR   # 1000 sats → EUR

Security

The security model is built on a single principle: the NWC URL contains the wallet's private key. This means:

  • The NWC URL is never logged, displayed, or transmitted. Only event IDs and balance values appear in the output.
  • The --debug flag is safe — it prints JSON structure (keys, types, error flags), never secret values or decrypted payloads.
  • RFC 6979 deterministic nonces eliminate reuse risk in Schnorr signatures.
  • Spending limits are enforced server-side by the wallet — you can't override them. The --max-amount flag on fetch adds an extra client-side guard.
  • NIP-44 (ChaCha20-Poly1305) available via --nip44 flag for wallets that support it.
  • Constant-time MAC comparison in Poly1305 verification.
  • WebSocket connections always closed (try/finally on all paths).

Installation

For agents (Hermes, OpenClaw, Claude Code, Codex, etc.):

pipx install pipx-skills
pipx-skills add eddieoz/nwc-agent

Configure your NIP-47 wallet and save the connection URL.

⚠️
Never paste the nostr+walletconnect:// URL into chats or shared channels. Use the terminal directly.

Manual installation:

git clone https://github.com/eddieoz/nwc-agent.git
cd nwc-agent
pip install -r requirements.txt
# Configure .env with your NWC URL
python3 scripts/nwc_wallet.py balance

Only prerequisite: Python 3.8+ and OpenSSL (present in every Linux distribution). No Node.js. No native compilation. If Python runs, the wallet runs.

RISC-V Performance

For reference, on the LicheeRV Nano (1 GHz C906):

| Operation | Time |

|----------|-------|

| secp256k1 point multiplication | ~2 ms |

| BIP-340 Schnorr signature | ~3 ms |

| ECDH (OpenSSL subprocess) | ~15 ms |

| NWC balance request (end-to-end) | ~3 s |

| NIP-44 encrypt/decrypt | ~5 ms |

Availability

The project is open-source (MIT) and available at github.com/eddieoz/nwc-agent. Full documentation — cryptographic stack architecture, attack surface analysis, payment protocol reference, and testing guide — is in the docs/ directory of the repository.

If nwc-agent helped you build something useful, consider sponsoring the project.


The convergence between autonomous agents and native internet payments is no longer theory. It's a US$ 15 device with a camera, a 1 TOPS NPU, and a Lightning wallet it built itself — paying for APIs, accessing paid content, operating as an independent economic actor on the network.

HTTP 402 has awoken. And this time, it came with pure Python.

Send sats if you liked.

⚡️eddieoz@sats4.life