deal with webln unlock in sendPayment

This commit is contained in:
keyan 2024-04-27 20:00:54 -05:00
parent 4a14e0342b
commit b8e153a4be
3 changed files with 50 additions and 48 deletions

View File

@ -1,19 +1,21 @@
import QRCode from 'qrcode.react' import QRCode from 'qrcode.react'
import { CopyInput, InputSkeleton } from './form' import { CopyInput, InputSkeleton } from './form'
import InvoiceStatus from './invoice-status' import InvoiceStatus from './invoice-status'
import { useEffect } from 'react' import { useEffect, useRef } from 'react'
import { useWebLN } from './webln' import { useWebLN } from './webln'
import SimpleCountdown from './countdown' import SimpleCountdown from './countdown'
import Bolt11Info from './bolt11-info' import Bolt11Info from './bolt11-info'
export default function Qr ({ asIs, value, webLn, statusVariant, description, status }) { export default function Qr ({ asIs, value, webLn, statusVariant, description, status }) {
const qrValue = asIs ? value : 'lightning:' + value.toUpperCase() const qrValue = asIs ? value : 'lightning:' + value.toUpperCase()
const provider = useWebLN() const provider = useWebLN()
// XXX antipattern ... we shouldn't be getting multiple renders
const sendPayment = useRef(false)
useEffect(() => { useEffect(() => {
async function effect () { async function effect () {
if (webLn && provider) { if (webLn && provider && !sendPayment.current) {
sendPayment.current = true
try { try {
await provider.sendPayment({ bolt11: value }) await provider.sendPayment({ bolt11: value })
} catch (e) { } catch (e) {

View File

@ -91,9 +91,6 @@ function RawWebLNProvider ({ children }) {
flowId: flowId || hash, flowId: flowId || hash,
type: 'payment', type: 'payment',
onPending: async () => { onPending: async () => {
if (provider.status === Status.Locked) {
await provider.unlock()
}
await provider.sendPayment(bolt11) await provider.sendPayment(bolt11)
}, },
// hash and hmac are only passed for JIT invoices // hash and hmac are only passed for JIT invoices

View File

@ -44,14 +44,57 @@ export function LNCProvider ({ children }) {
return await lnc.lightning.getInfo() return await lnc.lightning.getInfo()
}, [logger, lnc]) }, [logger, lnc])
const unlock = useCallback(async (connect) => {
if (status === Status.Enabled) return config.password
return await new Promise((resolve, reject) => {
const cancelAndReject = async () => {
reject(new Error('password canceled'))
}
showModal(onClose => {
return (
<Form
initial={{
password: ''
}}
onSubmit={async (values) => {
try {
lnc.credentials.password = values?.password
setStatus(Status.Enabled)
setConfig({ pairingPhrase: lnc.credentials.pairingPhrase, password: values.password })
logger.ok('wallet enabled')
onClose()
resolve(values.password)
} catch (err) {
logger.error('failed attempt to unlock wallet', err)
throw err
}
}}
>
<h4 className='text-center mb-3'>Unlock LNC</h4>
<PasswordInput
label='password'
name='password'
/>
<div className='mt-5 d-flex justify-content-between'>
<CancelButton onClick={() => { onClose(); cancelAndReject() }} />
<SubmitButton variant='primary'>unlock</SubmitButton>
</div>
</Form>
)
}, { onClose: cancelAndReject })
})
}, [logger, showModal, setConfig, lnc, status])
const sendPayment = useCallback(async (bolt11) => { const sendPayment = useCallback(async (bolt11) => {
const hash = bolt11Tags(bolt11).payment_hash const hash = bolt11Tags(bolt11).payment_hash
logger.info('sending payment:', `payment_hash=${hash}`) logger.info('sending payment:', `payment_hash=${hash}`)
return await mutex.runExclusive(async () => { return await mutex.runExclusive(async () => {
try { try {
const password = await unlock()
// credentials need to be decrypted before connecting after a disconnect // credentials need to be decrypted before connecting after a disconnect
lnc.credentials.password = config?.password || XXX_DEFAULT_PASSWORD lnc.credentials.password = password || XXX_DEFAULT_PASSWORD
await lnc.connect() await lnc.connect()
const { paymentError, paymentPreimage: preimage } = const { paymentError, paymentPreimage: preimage } =
await lnc.lnd.lightning.sendPaymentSync({ payment_request: bolt11 }) await lnc.lnd.lightning.sendPaymentSync({ payment_request: bolt11 })
@ -89,7 +132,7 @@ export function LNCProvider ({ children }) {
} }
} }
}) })
}, [logger, lnc, config]) }, [logger, lnc, unlock])
const saveConfig = useCallback(async config => { const saveConfig = useCallback(async config => {
setConfig(config) setConfig(config)
@ -119,46 +162,6 @@ export function LNCProvider ({ children }) {
logger.info('cleared config') logger.info('cleared config')
}, [logger, lnc]) }, [logger, lnc])
const unlock = useCallback(async (connect) => {
return await new Promise((resolve, reject) => {
const cancelAndReject = async () => {
reject(new Error('password canceled'))
}
showModal(onClose => {
return (
<Form
initial={{
password: ''
}}
onSubmit={async (values) => {
try {
lnc.credentials.password = values?.password
setStatus(Status.Enabled)
setConfig({ pairingPhrase: lnc.credentials.pairingPhrase, password: values.password })
logger.ok('wallet enabled')
onClose()
resolve()
} catch (err) {
logger.error('failed attempt to unlock wallet', err)
throw err
}
}}
>
<h4 className='text-center mb-3'>Unlock LNC</h4>
<PasswordInput
label='password'
name='password'
/>
<div className='mt-5 d-flex justify-content-between'>
<CancelButton onClick={() => { onClose(); cancelAndReject() }} />
<SubmitButton variant='primary'>unlock</SubmitButton>
</div>
</Form>
)
}, { onClose: cancelAndReject })
})
}, [logger, showModal, setConfig, lnc])
useEffect(() => { useEffect(() => {
(async () => { (async () => {
try { try {