Improve merchant creation with automatic keypair generation

Enhance the merchant creation process by automatically generating Nostr keypairs
for users who don't have them, and streamline the API interface.

Changes:
- Add CreateMerchantRequest model to simplify merchant creation API
- Auto-generate Nostr keypairs for users without existing keys
- Update merchant creation endpoint to use user account keypairs
- Improve error handling and validation in merchant creation flow
- Clean up frontend JavaScript for merchant creation

This ensures all merchants have proper Nostr keypairs for marketplace
functionality without requiring manual key management from users.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
padreug 2025-09-07 03:25:19 +02:00
parent 4b65ed411a
commit 0b7639adf5
3 changed files with 53 additions and 27 deletions

View file

@ -44,6 +44,10 @@ class MerchantConfig(MerchantProfile):
restore_in_progress: Optional[bool] = False
class CreateMerchantRequest(BaseModel):
config: MerchantConfig = MerchantConfig()
class PartialMerchant(BaseModel):
private_key: str
public_key: str

View file

@ -21,26 +21,18 @@ window.app = Vue.createApp({
},
methods: {
generateKeys: async function () {
const privateKey = nostr.generatePrivateKey()
await this.createMerchant(privateKey)
// No longer need to generate keys here - the backend will use user's existing keypairs
await this.createMerchant()
},
importKeys: async function () {
this.importKeyDialog.show = false
let privateKey = this.importKeyDialog.data.privateKey
if (!privateKey) {
return
}
try {
if (privateKey.toLowerCase().startsWith('nsec')) {
privateKey = nostr.nip19.decode(privateKey).data
}
} catch (error) {
// Import keys functionality removed since we use user's native keypairs
// Show a message that this is no longer needed
this.$q.notify({
type: 'negative',
message: `${error}`
type: 'info',
message: 'Merchants now use your account Nostr keys automatically. Key import is no longer needed.',
timeout: 3000
})
}
await this.createMerchant(privateKey)
},
showImportKeysDialog: async function () {
this.importKeyDialog.show = true
@ -94,12 +86,9 @@ window.app = Vue.createApp({
this.activeChatCustomer = ''
this.showKeys = false
},
createMerchant: async function (privateKey) {
createMerchant: async function () {
try {
const pubkey = nostr.getPublicKey(privateKey)
const payload = {
private_key: privateKey,
public_key: pubkey,
config: {}
}
const {data} = await LNbits.api.request(

View file

@ -4,6 +4,7 @@ from typing import List, Optional
from fastapi import Depends
from fastapi.exceptions import HTTPException
from lnbits.core.crud import get_account, update_account
from lnbits.core.services import websocket_updater
from lnbits.decorators import (
WalletTypeInfo,
@ -11,6 +12,7 @@ from lnbits.decorators import (
require_invoice_key,
)
from lnbits.utils.exchange_rates import currencies
from lnbits.utils.nostr import generate_keypair
from loguru import logger
from . import nostr_client, nostrmarket_ext
@ -59,6 +61,7 @@ from .crud import (
)
from .helpers import normalize_public_key
from .models import (
CreateMerchantRequest,
Customer,
DirectMessage,
DirectMessageType,
@ -90,18 +93,48 @@ from .services import (
@nostrmarket_ext.post("/api/v1/merchant")
async def api_create_merchant(
data: PartialMerchant,
data: CreateMerchantRequest,
wallet: WalletTypeInfo = Depends(require_admin_key),
) -> Merchant:
try:
merchant = await get_merchant_by_pubkey(data.public_key)
assert merchant is None, "A merchant already uses this public key"
# 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"
merchant = await create_merchant(wallet.wallet.user, data)
# 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,
@ -116,7 +149,7 @@ async def api_create_merchant(
await resubscribe_to_all_merchants()
await nostr_client.merchant_temp_subscription(data.public_key)
await nostr_client.merchant_temp_subscription(public_key)
return merchant
except AssertionError as ex: