Auto-provision merchant from account keypair on first access

The LNbits user account IS the merchant identity. GET /api/v1/merchant
now auto-creates the merchant record using the account's existing Nostr
keypair if one doesn't exist yet, so the extension is immediately
usable without any setup screen.

- Extract _auto_create_merchant() helper used by both GET and POST
- Remove welcome/key-generation screen (replaced with loading spinner)
- Remove dead frontend code (generateKeys, importKeys dialogs)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-04-27 12:14:40 +02:00
commit 5c38947fc6
3 changed files with 62 additions and 136 deletions

View file

@ -93,6 +93,56 @@ from .services import (
######################################## MERCHANT ######################################
async def _auto_create_merchant(
wallet: WalletTypeInfo,
config: MerchantConfig | None = None,
) -> Merchant:
"""
Provision a merchant record from the user's account keypair.
Called automatically on first GET or explicitly via POST.
"""
account = await get_account(wallet.wallet.user)
assert account, "User account not found"
# In our fork, accounts always have keypairs.
# Generate as fallback only if somehow missing.
if not account.pubkey or not account.prvkey:
private_key, public_key = generate_keypair()
account.pubkey = public_key
account.prvkey = private_key
await update_account(account)
else:
public_key = account.pubkey
private_key = account.prvkey
existing_merchant = await get_merchant_by_pubkey(public_key)
assert existing_merchant is None, "A merchant already uses this public key"
partial_merchant = PartialMerchant(
private_key=private_key,
public_key=public_key,
config=config or MerchantConfig(),
)
merchant = await create_merchant(wallet.wallet.user, partial_merchant)
await create_zone(
merchant.id,
Zone(
id=f"online-{merchant.public_key}",
name="Online",
currency="sat",
cost=0,
countries=["Free (digital)"],
),
)
await resubscribe_to_all_merchants()
await nostr_client.merchant_temp_subscription(public_key)
return merchant
@nostrmarket_ext.post("/api/v1/merchant")
async def api_create_merchant(
data: CreateMerchantRequest,
@ -100,60 +150,10 @@ async def api_create_merchant(
) -> Merchant:
try:
# Check if merchant already exists for this user
merchant = await get_merchant_for_user(wallet.wallet.user)
assert merchant is None, "A merchant already exists for this user"
# Get user's account to access their Nostr keypairs
account = await get_account(wallet.wallet.user)
if not account:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND,
detail="User account not found",
)
# Check if user has Nostr keypairs, generate them if not
if not account.pubkey or not account.prvkey:
# Generate new keypair for user
private_key, public_key = generate_keypair()
# Update user account with new keypairs
account.pubkey = public_key
account.prvkey = private_key
await update_account(account)
else:
public_key = account.pubkey
private_key = account.prvkey
# Check if another merchant is already using this public key
existing_merchant = await get_merchant_by_pubkey(public_key)
assert existing_merchant is None, "A merchant already uses this public key"
# Create PartialMerchant with user's keypairs
partial_merchant = PartialMerchant(
private_key=private_key,
public_key=public_key,
config=data.config
)
merchant = await create_merchant(wallet.wallet.user, partial_merchant)
await create_zone(
merchant.id,
Zone(
id=f"online-{merchant.public_key}",
name="Online",
currency="sat",
cost=0,
countries=["Free (digital)"],
),
)
await resubscribe_to_all_merchants()
await nostr_client.merchant_temp_subscription(public_key)
return merchant
return await _auto_create_merchant(wallet, data.config)
except AssertionError as ex:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST,
@ -170,12 +170,13 @@ async def api_create_merchant(
@nostrmarket_ext.get("/api/v1/merchant")
async def api_get_merchant(
wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> Optional[Merchant]:
) -> Merchant:
try:
merchant = await get_merchant_for_user(wallet.wallet.user)
if not merchant:
return None
# Auto-provision merchant from the user's account keypair
merchant = await _auto_create_merchant(wallet)
merchant = await touch_merchant(wallet.wallet.user, merchant.id)
assert merchant