Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 187 additions & 0 deletions 23.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
LUD-23: `addressRequest` base spec.
=======================================

`author: Christian Moss aka Mandelduck`

---

## Lightning Address Sharing

A service can request a user's Lightning address without requiring manual text input. This is particularly useful for games, apps, and services that need to pay users (e.g., game rewards, referral bonuses, content creator payouts) where typing an address would create friction.

The service displays a QR code or triggers a URL scheme, the user's wallet prompts for permission, and upon approval sends the Lightning address to the service's callback endpoint.

### User story:

**Conference Gaming Example**: You're at a Bitcoin conference and want to play a kart racing game that streams sats to your wallet as you collect coins on the track.

**Current friction**: You must use a keyboard to manually enter your Lightning address into a UI the game developer built. This is slow, error-prone, and breaks immersion.

**With LUD-23**: You simply scan a QR code displayed on the game screen with your phone, approve the request in your wallet, and start playing immediately. The game streams sats directly to your Lightning address as you collect coins - no typing required.

### Use cases:
- Arcade/kiosk games at conferences that pay players in real-time
- Point-of-sale systems collecting customer Lightning addresses for refunds/rewards
- Interactive installations and experiences that reward participants
- Game developers rewarding players without requiring account creation
- Apps distributing payments to users
- Services onboarding users for payouts
- Any application needing a user's Lightning address without manual input

### Server-side generation of addressRequest URL:

When creating an `addressRequest` handler, `LN SERVICE` must include a `k1` query parameter consisting of randomly generated 32 bytes of data. An example is `https://yourapp.com/share-address?tag=addressRequest&k1=hex(32 bytes of random data)`.

The `k1` serves two purposes:
1. **Request matching**: Allows the service to match the callback response to the specific user/session that initiated the request
2. **Spam prevention**: Prevents random requests to the callback endpoint

`LN SERVICE` must maintain a cache of unused `k1` values and only accept callbacks with valid `k1` values from that cache. Used `k1` values should be removed after successful address submission to prevent replay attacks.

### Server-side choice of subdomain:

While not as critical as with authentication (LUD-04), `LN SERVICE` should still use clear, meaningful domain names since wallets will display the requesting domain to users for approval. For example, `rewards.yourgame.com` is clearer than `api-v2.yourgame.com`.

### Wallet to service interaction flow:

1. `LN WALLET` scans a QR code or receives a URL scheme intent and decodes the URL which contains:
- `tag` query parameter with value `addressRequest`
- `k1` (hex encoded 32 bytes) for request matching
- optional `callback` URL (if different from the base URL)

2. If `callback` is not present in the initial URL, `LN WALLET` makes a GET request to the URL to retrieve details:

```JSON
{
"tag": "addressRequest",
"callback": "https://yourapp.com/receive-address",
"k1": "hex(32 bytes of random data)",
"description": "Share your Lightning address with AwesomeGame to receive rewards"
}
```

The `description` field should be a human-readable explanation of why the address is being requested.

3. `LN WALLET` displays a confirmation dialog which must include:
- The domain name extracted from the callback URL
- The `description` text explaining the request
- A clear indication that the Lightning address will be shared
- Approve/Deny options

4. Once approved by user, `LN WALLET` makes a GET request to the `callback` URL with the following query parameters:

```
GET <callback>?k1=<hex(32 bytes from request)>&address=<user@wallet.com>
```

5. `LN SERVICE` responds with JSON:

```JSON
{"status": "OK"}
```

or

```JSON
{"status": "ERROR", "reason": "error details..."}
```

### URL scheme format (same device):

For same-device interactions, the URL can be formatted as:

```
lightning:addressRequest?callback=https://yourapp.com/receive&k1=hex(32 bytes)&description=Share%20address%20with%20AwesomeGame
```

Or services can implement deep linking to their own app:

```
yourapp://receive-address?address=user@wallet.com
```

### Encoding for QR codes:

For QR code display (cross-device), the URL should be bech32-encoded following LUD-01:

```
lnurl1dp68gurn8ghj7um9wfmxjcm99e5k7... (encodes https://yourapp.com/share?tag=addressRequest&k1=...)
```

When used in QR codes, `LNURL` should be uppercase.

### Security considerations:

1. **Public information**: Lightning addresses are public identifiers meant to be shared. No sensitive authentication material is transmitted.

2. **User consent**: Wallets MUST require explicit user approval before sharing the address. The dialog should clearly show which service is requesting the address.

3. **k1 validation**: Services must validate that the `k1` in the callback matches an unused `k1` from their cache to prevent spam and replay attacks.

4. **HTTPS required**: All callback URLs must use HTTPS (or http:// for Tor v2/v3 onion addresses).

5. **Rate limiting**: Services should implement rate limiting on the callback endpoint to prevent abuse.

6. **No authentication**: This protocol does NOT authenticate the user - it only collects their Lightning address. If authentication is needed, use LUD-04 instead.

### Example implementation (JavaScript):

```javascript
// Server-side: Generate addressRequest
const crypto = require('crypto');

function generateAddressRequest(sessionId) {
const k1 = crypto.randomBytes(32).toString('hex');

// Store k1 with session mapping
sessionCache.set(k1, { sessionId, timestamp: Date.now() });

return {
tag: "addressRequest",
callback: `https://yourgame.com/api/receive-address`,
k1: k1,
description: "Share your Lightning address with AwesomeGame to receive in-game rewards"
};
}

// Server-side: Handle callback
app.get('/api/receive-address', (req, res) => {
const { k1, address } = req.query;

// Validate k1
const session = sessionCache.get(k1);
if (!session) {
return res.json({ status: "ERROR", reason: "Invalid or expired request" });
}

// Validate address format per LUD-16 (lowercase, [a-z0-9\-_.+] local part)
const [localPart, domain] = (address || '').split('@');
if (!localPart || !domain || !/^[a-z0-9\-_.+]+$/.test(localPart)) {
return res.json({ status: "ERROR", reason: "Invalid Lightning address format" });
}

// Store address with user session
userSessions.updateAddress(session.sessionId, address);

// Remove used k1
sessionCache.delete(k1);

res.json({ status: "OK" });
});
```

### Dependencies:

- **LUD-01**: Base LNURL encoding/decoding for QR code support
- **LUD-16**: Understanding Lightning address format (`user@domain.com`)

### Differences from LUD-04 (auth):

Unlike authentication, this protocol:
- Does NOT require signature generation/verification
- Does NOT derive domain-specific keys
- Does NOT authenticate the user's identity
- Only collects a public Lightning address
- Is much simpler to implement

If you need authentication, use LUD-04. If you just need a payment destination, use LUD-23.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ These are all the individual documents describing each small piece of protocol t
| [19][19] | Pay link discoverable from withdraw link. | [Blixt][blixt], [CoinCorner][coincorner], [OBW][obw], [LifPay][lifpay], [LNbits][lnbits] |
| [20][20] | Long payment description for pay protocol. | [Alby][alby], [BitBanana][bitbanana], [Blixt][blixt], [Clams][clams], [cliché][cliche], [Mash][mash], [OneKey][onekey], [Phoenix][phoenix], [Piggy][piggy] |
| [21][21] | `verify` LNURL-pay payments | [Alby][alby], [LifPay][lifpay], [Mutiny][mutiny], [Stacker.News][stacker.news], [Zaprite][zaprite] |
| [22][22] | Request user's Lightning address | _implementation pending_ |

[alby]: https://github.com/getAlby/lightning-browser-extension
[bipa]: https://bipa.app
Expand Down Expand Up @@ -227,6 +228,7 @@ Tools for developers
[19]: 19.md
[20]: 20.md
[21]: 21.md
[22]: 22.md

Dependency Tree
---------------
Expand Down