* Inject wallet logger interface * Include method in NWC logs * Fix wrong page total * Poll for new logs every second * Fix overlapping pagination * Remove unused total * Better logs for incoming payments * Use _setLogs instead of wrapper * Remove inconsistent receive log * Remove console.log from wallet logger on server * Fix missing 'wallet detached' log * Fix confirm_withdrawl code * Remove duplicate autowithdrawal log * Add context to log * Add more context * Better table styling * Move CSS for wallet logs into one file * remove unused logNav class * rename classes * Align key with second column * Fix TypeError if context empty * Check content-type header before calling res.json() * Fix duplicate 'failed to create invoice' * Parse details from LND error * Fix invalid DOM property 'colspan' * P2P zap logs with context * Remove unnecessary withdrawal error log * the code assignment was broken anyway * we already log withdrawal errors using .catch on payViaPaymentRequest * Don't show outgoing fee to receiver to avoid confusion * Fix typo in comment * Log if invoice was canceled by payer * Automatically populate context from bolt11 * Fix missing context * Fix wrap errors not logged * Only log cancel if client canceled * Remove unused imports * Log withdrawal/forward success/error in payment flow * Fix boss not passed to checkInvoice * Fix TypeError * Fix database timeouts caused by logger The logger shares the same connection pool with any currently running transaction. This means that we enter a classic deadlock when we await logger calls: the logger call is waiting for a connection but the currently running transaction is waiting for the logger call to finish before it can release a connection. * Fix cache returning undefined * Fix typo in comment * Add padding-right to key in log context * Always use 'incoming payment failed:' --------- Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
		
			
				
	
	
		
			95 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { Relay } from '@/lib/nostr'
 | |
| import { parseNwcUrl } from '@/lib/url'
 | |
| import { string } from '@/lib/yup'
 | |
| import { finalizeEvent, nip04, verifyEvent } from 'nostr-tools'
 | |
| 
 | |
| export const name = 'nwc'
 | |
| export const walletType = 'NWC'
 | |
| export const walletField = 'walletNWC'
 | |
| 
 | |
| export const fields = [
 | |
|   {
 | |
|     name: 'nwcUrl',
 | |
|     label: 'connection',
 | |
|     type: 'password',
 | |
|     optional: 'for sending',
 | |
|     clientOnly: true,
 | |
|     requiredWithout: 'nwcUrlRecv',
 | |
|     validate: string().nwcUrl()
 | |
|   },
 | |
|   {
 | |
|     name: 'nwcUrlRecv',
 | |
|     label: 'connection',
 | |
|     type: 'password',
 | |
|     optional: 'for receiving',
 | |
|     serverOnly: true,
 | |
|     requiredWithout: 'nwcUrl',
 | |
|     validate: string().nwcUrl()
 | |
|   }
 | |
| ]
 | |
| 
 | |
| export const card = {
 | |
|   title: 'NWC',
 | |
|   subtitle: 'use Nostr Wallet Connect for payments',
 | |
|   badges: ['send', 'receive', 'budgetable']
 | |
| }
 | |
| 
 | |
| export async function nwcCall ({ nwcUrl, method, params }, { logger, timeout } = {}) {
 | |
|   const { relayUrl, walletPubkey, secret } = parseNwcUrl(nwcUrl)
 | |
| 
 | |
|   const relay = await Relay.connect(relayUrl, { timeout })
 | |
|   logger?.ok(`connected to ${relayUrl}`)
 | |
| 
 | |
|   try {
 | |
|     const payload = { method, params }
 | |
|     const encrypted = await nip04.encrypt(secret, walletPubkey, JSON.stringify(payload))
 | |
| 
 | |
|     const request = finalizeEvent({
 | |
|       kind: 23194,
 | |
|       created_at: Math.floor(Date.now() / 1000),
 | |
|       tags: [['p', walletPubkey]],
 | |
|       content: encrypted
 | |
|     }, secret)
 | |
| 
 | |
|     // we need to subscribe to the response before publishing the request
 | |
|     // since NWC events are ephemeral (20000 <= kind < 30000)
 | |
|     const subscription = relay.fetch([{
 | |
|       kinds: [23195],
 | |
|       authors: [walletPubkey],
 | |
|       '#e': [request.id]
 | |
|     }], { timeout })
 | |
| 
 | |
|     await relay.publish(request, { timeout })
 | |
| 
 | |
|     logger?.info(`published ${method} request`)
 | |
| 
 | |
|     logger?.info(`waiting for ${method} response ...`)
 | |
| 
 | |
|     const [response] = await subscription
 | |
| 
 | |
|     if (!response) {
 | |
|       throw new Error(`no ${method} response`)
 | |
|     }
 | |
| 
 | |
|     logger?.ok(`${method} response received`)
 | |
| 
 | |
|     if (!verifyEvent(response)) throw new Error(`invalid ${method} response: failed to verify`)
 | |
| 
 | |
|     const decrypted = await nip04.decrypt(secret, walletPubkey, response.content)
 | |
|     const content = JSON.parse(decrypted)
 | |
| 
 | |
|     if (content.error) throw new Error(content.error.message)
 | |
|     if (content.result) return content.result
 | |
| 
 | |
|     throw new Error(`invalid ${method} response: missing error or result`)
 | |
|   } finally {
 | |
|     relay?.close()
 | |
|     logger?.info(`closed connection to ${relayUrl}`)
 | |
|   }
 | |
| }
 | |
| 
 | |
| export async function supportedMethods (nwcUrl, { logger, timeout } = {}) {
 | |
|   const result = await nwcCall({ nwcUrl, method: 'get_info' }, { logger, timeout })
 | |
|   return result.methods
 | |
| }
 |