From 870847127ba0284c8d23414e16d3b5a30fc15e5f Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Tue, 4 Feb 2025 21:33:02 -0300 Subject: [PATCH] checkpoint: implement swapNutzapsToWalletController --- src/app.ts | 2 + src/controllers/api/ditto.ts | 72 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/app.ts b/src/app.ts index 8b3da2c3..dfb07240 100644 --- a/src/app.ts +++ b/src/app.ts @@ -50,6 +50,7 @@ import { nameRequestController, nameRequestsController, statusZapSplitsController, + swapNutzapsToWalletController, updateInstanceController, updateZapSplitsController, } from '@/controllers/api/ditto.ts'; @@ -409,6 +410,7 @@ app.get('/api/v1/ditto/statuses/:id{[0-9a-f]{64}}/zapped_by', zappedByController app.post('/api/v1/ditto/wallet/create', requireSigner, createCashuWalletController); app.post('/api/v1/ditto/nutzap_information/create', requireSigner, createNutzapInformationController); +app.get('/api/v1/ditto/nutzap/swap_to_wallet', requireSigner, swapNutzapsToWalletController); app.post('/api/v1/reports', requireSigner, reportController); app.get('/api/v1/admin/reports', requireSigner, requireRole('admin'), adminReportsController); diff --git a/src/controllers/api/ditto.ts b/src/controllers/api/ditto.ts index def73ffa..9f48f219 100644 --- a/src/controllers/api/ditto.ts +++ b/src/controllers/api/ditto.ts @@ -479,3 +479,75 @@ export const createNutzapInformationController: AppController = async (c) => { return c.json(201); }; + +/** + * Swaps all nutzaps (NIP-61) to the user's wallet (NIP-60) + */ +export const swapNutzapsToWalletController: AppController = async (c) => { + const signer = c.get('signer')!; + const store = c.get('store'); + const pubkey = await signer.getPublicKey(); + const { signal } = c.req.raw; + + const nip44 = signer.nip44; + if (!nip44) { + return c.json({ error: 'Signer does not have nip 44.' }, 400); + } + + const [wallet] = await store.query([{ authors: [pubkey], kinds: [17375] }], { signal }); + if (!wallet) { + return c.json({ error: 'You need to have a wallet to swap the nutzaps into it.' }, 400); + } + + let decryptedContent: string; + try { + decryptedContent = await nip44.decrypt(pubkey, wallet.content); + } catch (e) { + logi({ level: 'error', ns: 'ditto.api', id: wallet.id, kind: wallet.kind, error: errorJson(e) }); + return c.json({ error: 'Could not decrypt wallet content.' }, 400); + } + + let contentTags: string[][]; + try { + contentTags = JSON.parse(decryptedContent); + } catch { + return c.json({ error: 'Could not JSON parse the decrypted wallet content.' }, 400); + } + + const privkey = contentTags.find(([value]) => value === 'privkey')?.[1]; + if (!privkey || !isNostrId(privkey)) { + return c.json({ error: 'Wallet does not contain privkey or privkey is not a valid nostr id.' }, 400); + } + const p2pk = getPublicKey(stringToBytes('hex', privkey)); + + const [nutzapInformation] = await store.query([{ authors: [pubkey], kinds: [10019] }], { signal }); + if (!nutzapInformation) { + return c.json({ error: 'You need to have a nutzap information event so we can get the mints.' }, 400); + } + + const nutzapInformationPubkey = nutzapInformation.tags.find(([name]) => name === 'pubkey')?.[1]; + if (!nutzapInformationPubkey || (nutzapInformationPubkey !== p2pk)) { + return c.json({ + error: + "You do not have a 'pubkey' tag in your nutzap information event or the one you have does not match the one derivated from the wallet.", + }, 400); + } + + const mints = [...new Set(nutzapInformation.tags.filter(([name]) => name === 'mint').map(([_, value]) => value))]; + if (mints.length < 1) { + return c.json({ error: 'You do not have any mints in your nutzap information event.' }, 400); + } + + const nutzapsFilter: NostrFilter = { kinds: [9321], '#p': [pubkey], '#u': mints }; + + const [nutzapHistory] = await store.query([{ kinds: [7376], authors: [pubkey] }], { signal }); + if (nutzapHistory) { + nutzapsFilter.since = nutzapHistory.created_at; + } + + const nutzaps = await store.query([nutzapsFilter], { signal }); + + // TODO: finally start doing the swap + + return c.json(201); +};