Update documentation and migrate future features to issues
CLAUDE.md updates: - Add new testing commands (test-setup, fund-atm, test-payment, etc.) - Add missing Bitcoin/Lightning commands (lncli-alice, alice-pay, setup-channel) - Fix Related Documentation section (removed non-existent file references) - Add External Resources section with relevant links Migrated docs/future-features.md to Forgejo issues: - #1: Public Cash Availability Display (P1, Low complexity) - #2: Remote Initiation, Local Redemption (P2, Medium complexity) - #3: Hold Invoices for Safe Dispensing (P2, High complexity) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
6d0485bfb5
commit
4bf78e25dc
2 changed files with 20 additions and 357 deletions
|
|
@ -81,9 +81,19 @@ infra-logs # Follow service logs
|
|||
|
||||
# Bitcoin/Lightning (regtest)
|
||||
btccli # Bitcoin CLI
|
||||
lncli # LND CLI
|
||||
lncli # LND CLI (Lightning.Pub's node)
|
||||
lncli-alice # LND CLI (Alice's node for testing payments)
|
||||
mine-blocks # Mine regtest blocks (default: 1)
|
||||
setup-channel # Setup channel between Alice and LND
|
||||
alice-pay # Pay invoice from Alice's node
|
||||
relay-test # Test Nostr relay connection
|
||||
|
||||
# Testing (E2E)
|
||||
test-setup # Validate test environment (services, channels, payments)
|
||||
test-payment # Quick e2e payment test (ATM → customer)
|
||||
fund-atm # Fund ATM account (default: 100k sats)
|
||||
alice-invoice # Create invoice on Alice's node
|
||||
node-info # Show node pubkeys and channel info
|
||||
```
|
||||
|
||||
## Development Infrastructure
|
||||
|
|
@ -282,7 +292,12 @@ When porting:
|
|||
|
||||
## Related Documentation
|
||||
|
||||
- `../docs/implementation-plan.md` - Full implementation roadmap
|
||||
- `../docs/nostr-native-architecture.md` - Architecture details
|
||||
- `../docs/architecture-review.md` - KYC-free vision
|
||||
- `.claude/skills/*.md` - Skill documentation
|
||||
- `packages/lightning/TROUBLESHOOTING.md` - Lightning.Pub integration gotchas (must read!)
|
||||
- `.claude/skills/*.md` - Custom skill documentation
|
||||
|
||||
## External Resources
|
||||
|
||||
- [CLINK Protocol Spec](https://github.com/shocknet/clink)
|
||||
- [Lightning.Pub](https://github.com/shocknet/Lightning.Pub)
|
||||
- [NIP-44 Encryption](https://github.com/nostr-protocol/nips/blob/master/44.md)
|
||||
- [LND Hold Invoices](https://docs.lightning.engineering/lightning-network-tools/lnd/hold-invoices)
|
||||
|
|
|
|||
|
|
@ -1,352 +0,0 @@
|
|||
# Future Features Roadmap
|
||||
|
||||
This document outlines advanced features planned for Lamassu Next that leverage the Nostr-native architecture.
|
||||
|
||||
## 1. Public Cash Availability Display
|
||||
|
||||
**Status**: Fully Achievable
|
||||
**Complexity**: Low
|
||||
**Dependencies**: Service beacon (kind 30078)
|
||||
|
||||
### Overview
|
||||
|
||||
A public website or app can display real-time cash availability for ATMs without requiring any special authentication.
|
||||
|
||||
### Technical Approach
|
||||
|
||||
1. **Machine publishes beacon** (replaceable event kind 30078):
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 30078,
|
||||
"tags": [
|
||||
["d", "machine-status"],
|
||||
["location", "40.7128,-74.0060"],
|
||||
["currency", "USD"]
|
||||
],
|
||||
"content": {
|
||||
"cassettes": [
|
||||
{ "denomination": 20, "count": 45 },
|
||||
{ "denomination": 50, "count": 20 }
|
||||
],
|
||||
"totalCash": 1900,
|
||||
"status": "online",
|
||||
"lastDispense": "2026-01-24T10:30:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Website subscribes** to relay:
|
||||
|
||||
```javascript
|
||||
["REQ", "availability", {"kinds": [30078], "authors": [<machine-pubkeys>]}]
|
||||
```
|
||||
|
||||
3. **Real-time updates**: Replaceable events update in place, website gets live data.
|
||||
|
||||
### Privacy Considerations
|
||||
|
||||
- Location precision can be reduced (city-level vs exact coordinates)
|
||||
- Operators choose what to publish (can omit exact counts)
|
||||
- Machine identity is pseudonymous (pubkey only)
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
- No encryption needed (public data)
|
||||
- Works with any public relay
|
||||
- Multiple machines can publish to same relay for fleet view
|
||||
- Dashboard aggregates for operator, public website shows customer view
|
||||
|
||||
---
|
||||
|
||||
## 2. Remote Initiation, Local Redemption
|
||||
|
||||
**Status**: Fully Achievable
|
||||
**Complexity**: Medium
|
||||
**Dependencies**: CLINK protocol (kinds 21001-21003), signed claims
|
||||
|
||||
### Overview
|
||||
|
||||
Users can initiate a cash-out transaction remotely (from their phone/wallet) and redeem it physically at the ATM later.
|
||||
|
||||
### User Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ REMOTE INITIATION │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. User opens wallet app │
|
||||
│ └─> Selects "Cash Out at ATM" │
|
||||
│ │
|
||||
│ 2. Wallet shows available ATMs (from beacons) │
|
||||
│ └─> User selects ATM and amount ($100) │
|
||||
│ │
|
||||
│ 3. Wallet sends CLINK request to ATM via relay │
|
||||
│ └─> kind 21002 (debit request) │
|
||||
│ │
|
||||
│ 4. ATM responds with signed claim │
|
||||
│ └─> "Bearer of this claim can redeem $100" │
|
||||
│ └─> Includes: amount, expiry, ATM signature, claim_id │
|
||||
│ │
|
||||
│ 5. User pays Lightning invoice (from wallet balance) │
|
||||
│ └─> Payment settles instantly │
|
||||
│ │
|
||||
│ 6. Wallet stores claim locally │
|
||||
│ └─> Claim is valid for 24 hours │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ LOCAL REDEMPTION │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 7. User arrives at ATM (minutes to hours later) │
|
||||
│ └─> Taps "Redeem" on ATM screen │
|
||||
│ │
|
||||
│ 8. ATM displays QR code for claim submission │
|
||||
│ └─> Wallet scans and sends signed claim │
|
||||
│ │
|
||||
│ 9. ATM verifies claim │
|
||||
│ └─> Checks signature (did I sign this?) │
|
||||
│ └─> Checks expiry (still valid?) │
|
||||
│ └─> Checks claim_id (not already redeemed?) │
|
||||
│ │
|
||||
│ 10. ATM dispenses cash │
|
||||
│ └─> Marks claim as redeemed (local DB + Nostr) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Claim Structure
|
||||
|
||||
```typescript
|
||||
interface RedemptionClaim {
|
||||
version: 1
|
||||
claim_id: string // Unique identifier
|
||||
machine_pubkey: string // ATM that will honor this
|
||||
amount_cents: number // Fiat amount to dispense
|
||||
currency: string // "USD"
|
||||
created_at: number // Unix timestamp
|
||||
expires_at: number // Unix timestamp (24h default)
|
||||
payment_preimage: string // Proof of payment
|
||||
user_pubkey?: string // Optional: restrict to specific user
|
||||
signature: string // ATM's signature over above fields
|
||||
}
|
||||
```
|
||||
|
||||
### Security Model
|
||||
|
||||
1. **Claim is bearer token**: Whoever presents valid claim gets cash
|
||||
2. **Single-use**: claim_id tracked to prevent double-redemption
|
||||
3. **Time-limited**: Expires after configurable window
|
||||
4. **User-binding** (optional): Can restrict to specific npub
|
||||
5. **Offline-capable**: ATM can verify signature without network
|
||||
|
||||
### State Sync
|
||||
|
||||
- Redeemed claims published to relay (for dashboard visibility)
|
||||
- Claims stored locally with SQLite for offline redemption
|
||||
- Periodic sync ensures consistency
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
- Claim fits in QR code (< 2KB when base64 encoded)
|
||||
- Works offline after initial payment (ATM doesn't need network to verify)
|
||||
- Natural fit with Cashu tokens (future enhancement)
|
||||
|
||||
---
|
||||
|
||||
## 3. Hold Invoices for Safe Dispensing
|
||||
|
||||
**Status**: Achievable with Hybrid Approach
|
||||
**Complexity**: High
|
||||
**Dependencies**: LND hold invoices, Lightning.Pub extension or direct LND access
|
||||
|
||||
### Overview
|
||||
|
||||
For cash-out, the current flow has a risk window: user pays invoice, but if dispenser jams, user loses funds. Hold invoices solve this by delaying settlement until cash is physically dispensed.
|
||||
|
||||
### Current Flow (Risky)
|
||||
|
||||
```
|
||||
User pays invoice ──> Invoice settles ──> Dispense attempted ──> JAM!
|
||||
│
|
||||
└── User lost funds, ATM owes them
|
||||
```
|
||||
|
||||
### Hold Invoice Flow (Safe)
|
||||
|
||||
```
|
||||
User pays invoice ──> Invoice HELD ──> Dispense attempted ──> Success ──> SETTLE
|
||||
│ │
|
||||
│ └── JAM! ──> CANCEL (funds returned)
|
||||
│
|
||||
└── Funds locked but not settled
|
||||
```
|
||||
|
||||
### Technical Background
|
||||
|
||||
LND supports hold invoices via:
|
||||
|
||||
- `AddHoldInvoice`: Create invoice with known preimage hash
|
||||
- `SettleInvoice`: Release funds (ATM provides preimage)
|
||||
- `CancelInvoice`: Return funds to payer
|
||||
|
||||
### Lightning.Pub Status
|
||||
|
||||
Lightning.Pub's codebase includes LND protobuf definitions for hold invoices:
|
||||
|
||||
```typescript
|
||||
// From Lightning.Pub/proto/lnd/invoices.ts
|
||||
interface AddHoldInvoiceRequest {
|
||||
hash: Uint8Array // SHA256 of preimage we choose
|
||||
value: string // Amount in sats
|
||||
memo: string
|
||||
expiry: string
|
||||
// ...
|
||||
}
|
||||
|
||||
interface SettleInvoiceMsg {
|
||||
preimage: Uint8Array // Reveal to settle
|
||||
}
|
||||
|
||||
interface CancelInvoiceMsg {
|
||||
payment_hash: Uint8Array
|
||||
}
|
||||
```
|
||||
|
||||
**However**: These are not currently exposed in Lightning.Pub's HTTP/Nostr API.
|
||||
|
||||
### Implementation Options
|
||||
|
||||
#### Option A: Lightning.Pub Extension (Recommended)
|
||||
|
||||
Contribute hold invoice support to Lightning.Pub:
|
||||
|
||||
```typescript
|
||||
// New RPC methods needed
|
||||
interface LightningPubExtension {
|
||||
// Create hold invoice (doesn't settle automatically)
|
||||
createHoldInvoice(params: {
|
||||
amount_sats: number
|
||||
memo: string
|
||||
hash: string // We provide the hash
|
||||
}): Promise<{ invoice: string }>
|
||||
|
||||
// Settle after successful dispense
|
||||
settleHoldInvoice(params: { preimage: string }): Promise<void>
|
||||
|
||||
// Cancel if dispense fails
|
||||
cancelHoldInvoice(params: { hash: string }): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
**Pros**: Clean integration, benefits entire ecosystem
|
||||
**Cons**: Requires upstream contribution, timeline uncertain
|
||||
|
||||
#### Option B: Hybrid Approach
|
||||
|
||||
ATM uses Lightning.Pub for accounting but connects to LND directly for hold invoices:
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ ATM Machine │────>│ Lightning.Pub │────>│ LND │
|
||||
│ │ │ (accounting) │ │ (payments) │
|
||||
│ │─────────────────────────────>│ │
|
||||
│ │ direct gRPC for hold │ │
|
||||
└─────────────────┘ invoices └─────────────────┘
|
||||
```
|
||||
|
||||
**Pros**: Works today, no upstream changes needed
|
||||
**Cons**: More complex, two connections to manage
|
||||
|
||||
#### Option C: Escrow Account
|
||||
|
||||
Use Lightning.Pub's internal accounts as escrow:
|
||||
|
||||
1. Create "escrow" account in Lightning.Pub
|
||||
2. User pays to escrow account (instant settlement)
|
||||
3. On successful dispense: transfer escrow → operator
|
||||
4. On failed dispense: transfer escrow → user refund
|
||||
|
||||
**Pros**: Works within Lightning.Pub model
|
||||
**Cons**: Requires user to have Lightning.Pub account for refund
|
||||
|
||||
### Chosen Approach: Lightning.Pub Contribution
|
||||
|
||||
We will contribute hold invoice support directly to Lightning.Pub (Option A). This:
|
||||
|
||||
- Benefits the entire Nostr+Lightning ecosystem
|
||||
- Keeps our architecture clean (single payment backend)
|
||||
- Aligns with the open-source-first philosophy of this project
|
||||
|
||||
**Action Item**: Open PR to Lightning.Pub exposing hold invoice methods via Nostr RPC (kind 21000).
|
||||
|
||||
### Cash-Out Flow with Hold Invoices
|
||||
|
||||
```typescript
|
||||
async function cashOutWithHoldInvoice(amount: number) {
|
||||
// 1. Generate preimage and hash
|
||||
const preimage = crypto.randomBytes(32)
|
||||
const hash = sha256(preimage)
|
||||
|
||||
// 2. Create hold invoice via LND
|
||||
const invoice = await lnd.addHoldInvoice({
|
||||
hash,
|
||||
value: amount,
|
||||
memo: `ATM Cash-Out $${amount / 100}`,
|
||||
expiry: 600, // 10 minutes
|
||||
})
|
||||
|
||||
// 3. Display invoice, wait for payment
|
||||
displayQR(invoice)
|
||||
await waitForHtlcAccepted(hash) // Payment received but not settled
|
||||
|
||||
// 4. Attempt to dispense
|
||||
try {
|
||||
await dispenser.dispense(calculateBills(amount))
|
||||
|
||||
// 5a. Success - settle the invoice
|
||||
await lnd.settleInvoice({ preimage })
|
||||
return { success: true }
|
||||
} catch (error) {
|
||||
// 5b. Failure - cancel the invoice, funds return to user
|
||||
await lnd.cancelInvoice({ payment_hash: hash })
|
||||
return { success: false, error: 'Dispense failed, payment cancelled' }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Timeout Handling
|
||||
|
||||
- Hold invoices have expiry (default 10 minutes)
|
||||
- If ATM crashes mid-transaction, invoice eventually expires
|
||||
- User's funds return automatically after timeout
|
||||
- No manual intervention needed
|
||||
|
||||
---
|
||||
|
||||
## Implementation Priority
|
||||
|
||||
| Feature | Priority | Effort | Value |
|
||||
| ------------------------ | -------- | ------ | ------------------- |
|
||||
| Public Cash Availability | P1 | Low | High |
|
||||
| Remote Initiation | P2 | Medium | High |
|
||||
| Hold Invoices | P2 | High | Critical for safety |
|
||||
|
||||
### Suggested Order
|
||||
|
||||
1. **Phase 1**: Basic ATM flows (cash-in, cash-out with standard invoices)
|
||||
2. **Phase 2**: Public availability beacon + simple dashboard
|
||||
3. **Phase 3**: Remote initiation with signed claims
|
||||
4. **Phase 4**: Hold invoices for production safety
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [CLINK Protocol Spec](https://github.com/shocknet/clink)
|
||||
- [Lightning.Pub](https://github.com/shocknet/Lightning.Pub)
|
||||
- [LND Hold Invoices](https://docs.lightning.engineering/lightning-network-tools/lnd/hold-invoices)
|
||||
- [NIP-44 Encryption](https://github.com/nostr-protocol/nips/blob/master/44.md)
|
||||
Loading…
Add table
Add a link
Reference in a new issue