Community

Apps

NWC Enclaved

This is not a wallet app for ordinary users to download. It is a developer and operator project that tries to make tiny Lightning balances and zappable Nostr profiles easier to provision by combining NWC, a TEE deployment model, service discovery, phoenixd liquidity and a custom invoice-for-another-pubkey flow.

NWC Enclaved visual
NWC Enclaved icon
Apps The product layer Clients, signers, publishing tools, wallets and useful experiments.
Back to Nostr
Apps

Apps shelf

Apps pages collect clients, signers, tools, developer libraries and product research without turning the app into the whole network.

Apps29 min readExperimental NWC wallet-service architecture for small custodial Lightning wallets inside trusted execution environments

NWC Enclaved

This is not a wallet app for ordinary users to download. It is a developer and operator project that tries to make tiny Lightning balances and zappable Nostr profiles easier to provision by combining NWC, a TEE deployment model, service discovery, phoenixd liquidity and a custom invoice-for-another-pubkey flow.

The quick readNWC Enclaved is an experimental nostr.band project named `nwc-enclaved`. Its own README calls it a custodial NWC wallet for TEE and says it is under active development. The goal is not to give you another wallet interface. The goal is to let app and agent developers create tiny Lightning wallets and zappable Nostr profiles without forcing every new user to set up a full self-custodial Lightning stack or sign up for a conventional custodial service. The architecture uses Nostr Wallet Connect for wallet operations, runs a reproducible Docker container intended for AWS Nitro Enclaves through the `enclaved` app server, uses phoenixd as the Lightning backend, publishes service announcements as kind 13196 events, exposes fees and limits, and relies on attestation tags that can be checked with `nostr-enclaves`. Its companion library `nwc-enclaved-utils` discovers valid services, creates an NWC connection string, returns a Zap.Land Lightning Address and can publish a Nostr profile. The sharp edges are equally important: the project is young, custodial, operator legality is explicitly out of scope, TEE does not remove every trust problem, phoenixd fees and liquidity constraints shape the product, and `make_invoice_for` is a project-specific extension rather than normal NIP-47 behavior. Treat any instance as infrastructure to verify, not a place to park meaningful funds casually.

Start with the shape

NWC Enclaved is not a normal app surface. You do not evaluate it the way you would evaluate a mobile wallet, a social client or a checkout button. It is a server-side wallet-service experiment from the nostr.band ecosystem, built around Nostr Wallet Connect, small Lightning balances and trusted execution environments.

The repository name is `nostrband/nwc-enclaved`. Its README describes the project as a custodial NWC wallet for TEE. That phrase contains the whole tension. It is custodial, because a service instance is operating wallet infrastructure for users. It is NWC, because access is exposed through Nostr Wallet Connect methods. It is TEE-oriented, because the project tries to reduce operator trust by running inside an isolated environment with reproducible builds and attestation.

That makes the project interesting and risky at the same time. It is trying to solve a real onboarding problem: a Nostr app can make zaps feel natural only if the user has a Lightning receiving path. But it is doing that by building a new style of custodial service, not by removing custody from the problem entirely.

The right reader posture is therefore practical skepticism. If you are building an app, NWC Enclaved is a possible infrastructure pattern. If you are evaluating a live instance, it is a service to verify. If you are an end user, the important question is not whether the name sounds secure. The important question is who operates the instance, what code is running, what limits apply, how you can withdraw or abandon it, and how much value you are willing to expose.

The problem it tries to solve

Nostr has made Lightning feel social through zaps, streaming payments, small tips and paid app actions. The user experience still has a gap. New users may arrive with a Nostr key but no Lightning wallet, no node, no channel, no inbound liquidity and no interest in learning the whole Lightning stack before they receive their first few sats.

Conventional custodial wallets can solve onboarding, but they add familiar problems: privacy loss, account requirements, regional restrictions, legal exposure for the operator and rug-pull risk for the user. Self-custodial Lightning can reduce custody, but it is often too heavy for a user or agent that only needs a tiny balance and many small payment events.

The README frames NWC Enclaved as a way to improve that custodial setup rather than pretend custody disappears. It aims to let app and agent developers provide zappable Lightning wallets without signup, KYC or upfront payments. A user or agent can generate a Nostr key, discover a service instance and receive a wallet-like NWC connection.

That is a useful goal for Nostr products. A social app, AI agent, publishing tool or small service might want every new profile to receive zaps immediately. NWC Enclaved says: use a common NWC API, discover service instances on relays, and reduce operator power through TEE isolation, transparent code, reproducible builds and attestation. Whether that is enough depends on verification and real-world operations.

What TEE changes and what it does not

TEE stands for trusted execution environment. In this project, the README points to AWS Nitro Enclaves and to the `enclaved` application server. The design goal is to run the wallet service in an isolated environment so the service operator cannot casually inspect user data, extract wallet keys or alter the running code without detection.

That is a meaningful design direction, but it is not magic. A TEE can help with isolation and attestation. It does not automatically prove that an operator is solvent, competent, lawful, well-monitored or protected against every deployment mistake. It also does not turn a custodial Lightning service into self-custody for the user.

The project is unusually clear about this boundary. Its README says legal risks for service operators are out of scope and need more research. It also says shotgun-KYC risk is harder to tackle and that the project will share more when that research is complete. Those are not footnotes. They are central to whether a real instance can operate safely.

A careful builder should treat TEE as one layer in a trust model. You still need to know the operator, the build, the attestation root, the current image hash, the source version, the limits, the liquidity state, the withdrawal or termination plan, the monitoring story and the user's intended balance. The enclave reduces some attack paths; it does not erase product risk.

How wallet creation works

Standard NWC usually starts with a wallet service creating a connection for an app. The wallet shows a pairing string or QR code, and the app receives a secret that authorizes specific wallet methods. That model assumes the user already has a wallet service and can manually approve the connection.

NWC Enclaved turns that around. The README says clients can generate NWC keys themselves, and the service accepts NWC queries from any key. Actual wallet state appears only when an invoice is paid and the pubkey receives a non-zero balance. In plain terms, a generated Nostr key plus a discovered service instance can become a small wallet identity.

That is powerful for onboarding. It means an app can create a profile, an NWC connection string and a Lightning Address path without sending the user through a wallet signup flow first. The companion `nwc-enclaved-utils` library wraps that flow: it discovers services, generates wallet key material, returns an NWC string and returns an `lnAddress` that can be used in a Nostr profile.

It also changes the security burden. If an app generates the NWC connection, the app must protect the secret. If the app publishes a profile with the generated Lightning Address, it should explain to the user where sats will land and what service is behind the address. A one-click wallet is only friendly if the user also gets a one-click way to understand, limit and abandon it.

NWC is the access layer

The wallet operations are built around Nostr Wallet Connect. NWC defines request events, response events, wallet-service info, connection strings, methods such as `pay_invoice`, `make_invoice`, `lookup_invoice`, `list_transactions`, `get_balance` and `get_info`, plus encrypted communication over relays.

The NWC Enclaved source declares support for methods including `pay_invoice`, `make_invoice`, `make_invoice_for`, `lookup_invoice`, `list_transactions`, `get_balance`, `get_info`, `add_pubkey` and notifications. It processes kind 23194 requests, replies with kind 23195 events and publishes wallet-service info. The code also detects NIP-04-style payloads while using NIP-44 support as part of the intended modern path.

That protocol choice matters because it keeps the app boundary familiar to Nostr builders. A product does not need a bespoke REST wallet API to talk to an instance. It can use NWC semantics, relay events and Nostr pubkeys. The user-facing product can still use an NWC client library, Alby SDK, Alby Go or another NWC-aware interface if the connection is compatible.

The same choice also means a builder must respect normal NWC discipline. The NWC string is sensitive. Method permissions matter. Wallet info should be checked. Expiration, relays, encryption, notifications and error codes need testing. A TEE-backed service does not make an overpowered NWC connection safe.

The make invoice for extension

The most distinctive protocol idea is `make_invoice_for`. Normal NWC `make_invoice` is a wallet-owner operation: the connected wallet creates an invoice for itself. NWC Enclaved needs something different because a Zap.Land or LNURL address provider may need to create an invoice for another user's pubkey.

The README introduces `make_invoice_for` as a new method that behaves like `make_invoice` but can be called by any pubkey and adds a required target `pubkey` plus an optional stringified NIP-57 zap request. The server-side code validates that `pubkey` exists and checks zap requests before creating the invoice path.

This extension is the bridge between one-click NWC wallets and zappable Nostr profiles. A third-party LNURL server can receive an LNURL callback, identify the user pubkey and service pubkey, call `make_invoice_for`, and return a BOLT11 invoice that pays the user's wallet state behind the service.

The caveat is interoperability. `make_invoice_for` is not a normal NIP-47 method you can assume every NWC wallet supports. It belongs to this architecture and to compatible services. If your app depends on it, document that dependency plainly, test the exact service instance and avoid presenting it as generic NWC behavior.

Zap Land is the address layer

Zap.Land is the companion piece that makes the wallet visible as a Lightning Address and zap target. Its repository describes it as an LN and zap-address provider for NWC, relying on the `make_invoice_for` method. The live site presents a one-click wallet creation idea built on NWC Enclaved.

The practical address pattern is visible in the utils and Zap.Land example code: a generated client npub is paired with a service npub under `zap.land`. The `nwc-enclaved-utils` code returns an address shaped like `client-npub@service-npub.zap.land`, while the main NWC Enclaved README also describes the same relationship as a mapping between user pubkey and service pubkey. The exact provider mapping is an implementation detail that should be checked in the code you deploy.

When someone pays the Lightning Address, the LNURL server handles the `/.well-known/lnurlp/` flow. It can advertise Nostr zap support, include the wallet service pubkey as the `nostrPubkey`, accept a NIP-57 zap request and call `make_invoice_for` so the invoice pays the target pubkey's wallet.

For users, the result is simple: a profile can have a `lud16` address and receive zaps. For builders, the result is many moving parts: LUD-16, LUD-06, NIP-57, NWC, the service announcement, relay reachability, method support, invoice expiry and wallet state creation. A good integration hides complexity from the user but does not hide it from the operator.

Discovery uses Nostr events

NWC Enclaved service instances publish announcement events so clients can find them. The README describes a kind 13196 service announcement containing tags such as relay URL, minimum and maximum sendable amounts and maximum balance. The source also publishes metadata about fees, environment and TEE certificates.

The companion utils library queries relays for recent kind 13196 events, filters for open services and environment tags, normalizes service relays and avoids unsafe local addresses. It then uses attestation validation before suggesting an instance. That is the happy path: discovery is not a hardcoded list; it is a Nostr-native service market.

This is a clever fit for Nostr. A wallet service can announce itself on relays, clients can discover candidates, and developers can build selection logic around operator, fees, limits, relay path, attestation and environment. It is closer to an infrastructure directory than to an app store listing.

The risk is stale or misleading discovery. A kind 13196 event can be old, a service can be down, a relay can filter events, an environment tag can say development, and an attestation check can fail. A production app should not blindly choose the first service. It should show or enforce a policy: which environments, which roots, which maximum balance, which operators and which relays are acceptable.

Attestation is a verification step

The TEE story depends on attestation. The README says attestation information is included in kind 13196 tags as `tee_root` and `tee_cert`, with verification through `nostr-enclaves` and the NEC-01 root format. The utils library imports `nostr-enclaves` and validates discovered services before returning them.

Attestation is meant to answer a specific question: is this service instance running code that corresponds to a known build in an expected enclave environment? That is valuable because the whole design claims privacy and key isolation from the service operator. Without verification, a service announcement is just a claim.

The repository includes a Docker build flow and a `docker.json` file with container image digests. The Dockerfile downloads phoenixd 0.5.1, checks a SHA256 hash for that package and labels the container with repository and signer metadata. The README tells builders to run the Docker build and compare hashes to `docker.json`.

For an app, this means attestation cannot be a decorative badge. Decide whether failed attestation blocks wallet creation. Decide how roots are trusted. Decide how upgrades are accepted. Decide how to handle a service that was valid yesterday but publishes a different certificate today. If the product cannot answer those questions, it should not market enclave-backed custody as proven safety.

phoenixd is the Lightning backend

Under the NWC service sits phoenixd, ACINQ's server-oriented Phoenix daemon. The NWC Enclaved README says phoenixd provides automatic liquidity management and also notes that it is not perfect because liquidity and payment fees can be significant. The Dockerfile pulls phoenixd 0.5.1 and runs it as a separate `phoenix` user.

That backend choice is pragmatic. Running Lightning at scale for many small wallets is difficult. phoenixd gives the project a route to automatic channel and liquidity behavior instead of forcing the service author to build every Lightning node concern from scratch.

But phoenixd's economics become product economics. The README names additional phoenix payment fees of 4 sats plus 0.4 percent, with details around when the percentage applies. It also says liquidity fees are paid by the service on channel extension at 1 percent of channel amount plus mining fees, and then allocated to customer wallets through a virtual channel and fee credit model.

That means an instance may be excellent for tiny onboarding balances and still unsuitable for heavy wallet use. The goal is not cheapest possible payments. The non-goals explicitly include cheapest payments or wallet maintenance, on-chain withdrawals or topups and keysend. If your app needs a serious wallet, NWC Enclaved is probably the wrong abstraction. If your app needs small zappable balances, the economics may fit.

Fees and limits are part of safety

NWC Enclaved uses limits and fees as abuse protection. The README lists limits on wallet count, unpaid invoices, balance, payment amounts and transaction history. The source constants include a default maximum balance of 100,000 sats, a maximum wallet count, invoice limits, transaction age limits and concurrent payment controls.

Fees are intentionally small but not invisible. The README says non-empty wallets pay a 1 sat wallet fee every 24 hours, and every payment has a 1 sat payment fee in addition to phoenix and liquidity-related fees. The service also tracks mining fee recovery so it does not drift into partial reserves when auto-liquidity costs arrive later.

This is where the project feels more like infrastructure than a demo. Empty unused wallets should cost almost nothing. Dormant non-empty wallets should not accumulate forever without contributing to operations. Outgoing payments should carry the costs that keep the service alive. Those are reasonable goals for a public small-balance service.

The user risk is misunderstanding. A profile may show a Lightning Address, but the underlying wallet is not a free permanent bank account. Balances, invoice creation, payment fees, liquidity constraints and service limits all matter. Any app that creates these wallets should show a plain explanation of max balance, fees, custody and service identity before users rely on it.

The utils package is the developer door

`nwc-enclaved-utils` is the library most app builders would touch first. Its README shows `createWallet`, which returns an `nwcString` and `lnAddress`. It also shows using the NWC string with the Alby SDK and publishing a Nostr profile with the returned Lightning Address.

The code discovers services, validates them, generates a new wallet private key, derives the client public key, selects the service relay and builds a `nostr+walletconnect://` URI with a `lud16` parameter. The result can be handed to an NWC client or stored by the app, depending on the product flow.

That is a smooth developer experience, and it is exactly why the project deserves careful writing. A helper that creates a wallet in one function call can hide decisions that should be explicit: which service was chosen, what environment it advertises, what attestation root was accepted, what max balance applies and where the secret will live.

Use the utils package as a doorway, not as a substitute for review. Read the discovery filters. Pin dependency versions. Check `nostr-enclaves` validation behavior. Decide whether development services are allowed. Protect the returned NWC string as a wallet credential. Test the resulting LN address before putting it into a live user profile.

A development instance is not production

There is public testing context around Zap.Land and NWC Enclaved, including posts that invite people to try a development instance with a tiny maximum balance and explicit toy-like warnings. That kind of test is valuable because the architecture needs real relay, NWC, LNURL and Lightning behavior to be exercised.

It also shows how easily readers can confuse a demo with a product. A live web page that creates a wallet and returns an address feels finished. But the underlying service may be a development instance, capped at a small balance, intended to be shut down, or running with debug assumptions.

The main repository itself ends with an active-development warning. That should shape every integration decision. Do not route real user value into an instance merely because a helper function worked once. Do not assume the public service you tested will be available forever. Do not assume future versions will keep the same event tags, methods or fee policy.

For production, you either operate and verify your own instance, or you make a deliberate choice about a third-party instance and explain that dependency. A developer preview can teach the flow. It should not silently become your users' wallet infrastructure.

Operator risk is still real

If you operate an NWC Enclaved instance, you are not merely hosting a static app. You are operating a custodial Lightning service, even if the code runs in an enclave and even if balances are small. That brings operational, legal, financial and support responsibilities.

The README is honest that operator legal risk is out of scope. That does not mean it is unimportant. A real operator needs to consider jurisdiction, user limits, compliance exposure, abuse, sanctions risk, service shutdown, dispute handling, logs, privacy promises and what happens when a user cannot access a balance.

Operationally, the service has to watch phoenixd, channel state, liquidity, relays, NWC request processing, event publication, attestation, Docker image upgrades, database persistence and the safe handling of unpaid invoices. A TEE can make some compromise paths harder, but it does not answer support tickets or keep liquidity balanced by itself.

The safest public story is narrow. This architecture is for tiny balances, zaps, agents and experimental app onboarding. It is not a replacement for a user's main Lightning wallet. Operators should set low limits, publish clear metadata, keep upgrade paths boring and design termination before they invite users in.

What to verify before using it

Start with the instance announcement. Check kind 13196 freshness, relays, max balance, min and max sendable values, fee tags, environment and whether attestation tags are present. If a service announces development or debug status, treat it as a test target, not a production wallet.

Then verify the build story. Compare the announced service with the GitHub repository, Docker image digest, `docker.json`, attestation root and certificate. Review the Dockerfile and source version. If your app accepts only specific roots or signers, enforce that policy in code rather than relying on a human to notice a mismatch.

Next test NWC behavior. Use a disposable key, create an NWC string, call `get_info`, request a tiny invoice, pay it from a test wallet, check balance, list transactions if permitted, attempt a tiny outgoing payment and check failure responses. Test relay downtime, revoked or malformed secrets, expired requests and unpaid invoice cleanup.

Finally test the Zap.Land path. Publish a test profile with the generated `lud16`, fetch the LNURL metadata, confirm `allowsNostr`, send a tiny zap, inspect the NIP-57 receipt and confirm the resulting wallet state. If any step cannot be explained, do not scale the integration yet.

Where it fits in the ecosystem

NWC Enclaved belongs in Developer Tools & Libraries because it is primarily an architecture and codebase for builders and operators. It touches wallets, Lightning backends, zaps and Nostr identity, but it is not a consumer wallet UI and not a simple payment button.

Its Nostr relationship is deep. Service discovery uses Nostr events. Wallet access uses NWC. Zaps use NIP-57. Encryption touches NIP-44 and legacy NIP-04 compatibility. Profiles can receive a `lud16` address. The whole point is to make Nostr identities and app-generated wallets cooperate.

Its Lightning relationship is equally specific. phoenixd does the backend wallet and liquidity work, while the service layers per-pubkey wallet state, invoice creation, fee accounting and NWC access above it. That is different from running one full node per user and different from a standard custodial web account.

The project is therefore a signpost for where Nostr infrastructure is going. It asks whether small custodial balances can become more transparent, more discoverable and more programmable through Nostr and TEE attestations. That is worth watching, even if the answer is not yet mature enough for broad trust.

The practical close

NWC Enclaved is one of the more concrete attempts to solve the tiny-wallet problem for Nostr. It gives builders a path to create NWC-controlled Lightning wallets, attach Zap.Land addresses to profiles and discover wallet services through Nostr events without asking every new user to become a Lightning operator first.

Its strengths are specific: NWC as a known app boundary, phoenixd as a managed Lightning backend, a TEE-oriented deployment model, attestation tags, reproducible build intent, service discovery, fees and limits for abuse protection, and a companion utils package that makes the flow approachable.

Its risks are just as specific: custody remains, legal and operator questions remain, TEE verification must be real, public instances may be experimental, fees and liquidity can surprise users, `make_invoice_for` is not generic NWC, and a leaked NWC string is still a wallet credential within its permissions.

Use it with small balances, explicit service selection, verified attestation, pinned code, clear user copy and a shutdown plan. In that lane, NWC Enclaved is a serious developer experiment. Outside that lane, it can become a neat one-click wallet that hides too much of the trust model.

Useful Nostr context

Read these next when you want to separate the wallet-service idea from the relay, zap and Lightning backend layers.

Sources worth opening

Open the main README, source modules, utils library and Zap.Land code first, then compare NIP-47, NIP-44, NIP-57, LUD-16, phoenixd and AWS Nitro Enclaves so the custody model and protocol extensions stay visible.

Back to the Crays Nostr page
Apps route visual cue 1
Apps route visual cue 2
Apps route visual cue 3
Apps route visual cue 4
Apps route visual cue 5

How to use this page

Keep the product map close.

Search the wider app shelf when you want another client, tool, protocol reference or source trail beside this page.

AppsBrowse Apps pagesApps pages stay availableProducts, tools, communities and source trails.Browse pages
Apps contribution visual cue 1
Apps contribution visual cue 2
Apps contribution visual cue 3
Apps contribution visual cue 4
Apps contribution visual cue 5

Bring something back

Ask, suggest, submit or nominate.

Ask a question, send a source, suggest a fix, submit a project or nominate a public Nostr account. The page stays stable; your contribution gets reviewed beside it.