LaWallet NWC
Getting Started

Getting Started

Quick start guide for deploying and using LaWallet NWC.

Prerequisites

  • Node.js 20+
  • pnpm
  • PostgreSQL database

Quick Start

  1. Clone the repository:
git clone https://github.com/lawalletio/lawallet-nwc.git
cd lawallet-nwc
  1. Install dependencies:
pnpm install
  1. Configure environment:
cp .env.example .env.local
  1. Set up the database:
npx prisma migrate dev
  1. Start the development server:
pnpm dev

Deployment Options

OptionBest forSetup time
VercelCommunities that want instant deploy2 minutes
DockerServers and VPS5 minutes
Umbrel / Start9Node runners5 minutes

See the Docker guide for container-based deployment.

Try It: Lightning Address Resolution

Explore how LUD-16 lightning address resolution works interactively:

import { useState } from "react";

// Simulates LUD-16 lightning address resolution
async function resolveLightningAddress(address: string) {
const [username, domain] = address.split("@");
if (!username || !domain) throw new Error("Invalid address format");

// Simulates GET /.well-known/lnurlp/{username}
await new Promise(r => setTimeout(r, 600));

return {
  status: "OK",
  tag: "payRequest",
  callback: "https://" + domain + "/api/lnurlp/" + username + "/callback",
  minSendable: 1000,
  maxSendable: 100000000,
  metadata: JSON.stringify([
    ["text/plain", "Pay " + username + "@" + domain],
    ["text/identifier", address],
  ]),
  commentAllowed: 255,
  allowsNostr: true,
  nostrPubkey: "npub1" + "a".repeat(58),
};
}

export default function App() {
const [address, setAddress] = useState("alice@yourdomain.com");
const [result, setResult] = useState<any>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");

const resolve = async () => {
  setLoading(true);
  setError("");
  try {
    const data = await resolveLightningAddress(address);
    setResult(data);
  } catch (e: any) {
    setError(e.message);
  }
  setLoading(false);
};

return (
  <div style={{ fontFamily: "system-ui", padding: 20 }}>
    <h3>LUD-16 Address Resolution</h3>
    <p style={{ color: "#6b7280", fontSize: 14 }}>
      Enter a lightning address to see the LNURL-pay response.
    </p>
    <div style={{ display: "flex", gap: 8, marginBottom: 16 }}>
      <input
        value={address}
        onChange={e => setAddress(e.target.value)}
        placeholder="user@domain.com"
        style={{
          flex: 1, padding: "8px 12px", borderRadius: 6,
          border: "1px solid #d1d5db", fontSize: 14,
        }}
      />
      <button onClick={resolve} disabled={loading} style={{
        padding: "8px 16px", borderRadius: 6,
        background: "#f97316", color: "white",
        border: "none", cursor: loading ? "wait" : "pointer",
      }}>
        {loading ? "Resolving..." : "Resolve"}
      </button>
    </div>
    {error && <div style={{ color: "#ef4444", marginBottom: 8 }}>{error}</div>}
    {result && (
      <pre style={{
        background: "#1e1e2e", color: "#a6e3a1",
        padding: 16, borderRadius: 8, fontSize: 12,
        overflow: "auto",
      }}>
{JSON.stringify(result, null, 2)}
      </pre>
    )}
  </div>
);
}

Next Steps

On this page