refactor webln
This commit is contained in:
parent
8329da1f56
commit
0f553b1aef
@ -2,6 +2,7 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState }
|
|||||||
import { LNbitsProvider, useLNbits } from './lnbits'
|
import { LNbitsProvider, useLNbits } from './lnbits'
|
||||||
import { NWCProvider, useNWC } from './nwc'
|
import { NWCProvider, useNWC } from './nwc'
|
||||||
import { LNCProvider, useLNC } from './lnc'
|
import { LNCProvider, useLNC } from './lnc'
|
||||||
|
import lnbits from './lnbits2'
|
||||||
|
|
||||||
const WebLNContext = createContext({})
|
const WebLNContext = createContext({})
|
||||||
|
|
||||||
|
22
components/webln/index2.js
Normal file
22
components/webln/index2.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { createContext, useContext, useMemo, useState } from 'react'
|
||||||
|
import lnbits from './lnbits2'
|
||||||
|
|
||||||
|
const storageKey = 'webln:providers'
|
||||||
|
|
||||||
|
const WebLNContext = createContext({})
|
||||||
|
|
||||||
|
export function useWebLN () {
|
||||||
|
const { provider } = useContext(WebLNContext)
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RawWebLNProvider ({ children }) {
|
||||||
|
const [provider, setProvider] = useState()
|
||||||
|
|
||||||
|
const value = useMemo(() => ({ provider, setProvider }), [])
|
||||||
|
return (
|
||||||
|
<WebLNContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</WebLNContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
@ -67,8 +67,7 @@ const getPayment = async (baseUrl, adminKey, paymentHash) => {
|
|||||||
|
|
||||||
export function LNbitsProvider ({ children }) {
|
export function LNbitsProvider ({ children }) {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const [url, setUrl] = useState('')
|
const [config, setConfig] = useState({})
|
||||||
const [adminKey, setAdminKey] = useState('')
|
|
||||||
const [status, setStatus] = useState()
|
const [status, setStatus] = useState()
|
||||||
const { logger } = useWalletLogger(Wallet.LNbits)
|
const { logger } = useWalletLogger(Wallet.LNbits)
|
||||||
|
|
||||||
@ -78,7 +77,7 @@ export function LNbitsProvider ({ children }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getInfo = useCallback(async () => {
|
const getInfo = useCallback(async () => {
|
||||||
const response = await getWallet(url, adminKey)
|
const response = await getWallet(config.url, config.adminKey)
|
||||||
return {
|
return {
|
||||||
node: {
|
node: {
|
||||||
alias: response.name,
|
alias: response.name,
|
||||||
@ -92,9 +91,11 @@ export function LNbitsProvider ({ children }) {
|
|||||||
version: '1.0',
|
version: '1.0',
|
||||||
supports: ['lightning']
|
supports: ['lightning']
|
||||||
}
|
}
|
||||||
}, [url, adminKey])
|
}, [config])
|
||||||
|
|
||||||
const sendPayment = useCallback(async (bolt11) => {
|
const sendPayment = useCallback(async (bolt11) => {
|
||||||
|
const { url, adminKey } = config
|
||||||
|
|
||||||
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}`)
|
||||||
|
|
||||||
@ -111,7 +112,7 @@ export function LNbitsProvider ({ children }) {
|
|||||||
logger.error('payment failed:', `payment_hash=${hash}`, err.message || err.toString?.())
|
logger.error('payment failed:', `payment_hash=${hash}`, err.message || err.toString?.())
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}, [logger, url, adminKey])
|
}, [logger, config])
|
||||||
|
|
||||||
const loadConfig = useCallback(async () => {
|
const loadConfig = useCallback(async () => {
|
||||||
let configStr = window.localStorage.getItem(storageKey)
|
let configStr = window.localStorage.getItem(storageKey)
|
||||||
@ -129,20 +130,17 @@ export function LNbitsProvider ({ children }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const config = JSON.parse(configStr)
|
const config = JSON.parse(configStr)
|
||||||
|
setConfig(config)
|
||||||
const { url, adminKey } = config
|
|
||||||
setUrl(url)
|
|
||||||
setAdminKey(adminKey)
|
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
'loaded wallet config: ' +
|
'loaded wallet config: ' +
|
||||||
'adminKey=****** ' +
|
'adminKey=****** ' +
|
||||||
`url=${url}`)
|
`url=${config.url}`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// validate config by trying to fetch wallet
|
// validate config by trying to fetch wallet
|
||||||
logger.info('trying to fetch wallet')
|
logger.info('trying to fetch wallet')
|
||||||
await getWallet(url, adminKey)
|
await getWallet(config.url, config.adminKey)
|
||||||
logger.ok('wallet found')
|
logger.ok('wallet found')
|
||||||
setStatus(Status.Enabled)
|
setStatus(Status.Enabled)
|
||||||
logger.ok('wallet enabled')
|
logger.ok('wallet enabled')
|
||||||
@ -156,8 +154,7 @@ export function LNbitsProvider ({ children }) {
|
|||||||
|
|
||||||
const saveConfig = useCallback(async (config) => {
|
const saveConfig = useCallback(async (config) => {
|
||||||
// immediately store config so it's not lost even if config is invalid
|
// immediately store config so it's not lost even if config is invalid
|
||||||
setUrl(config.url)
|
setConfig(config)
|
||||||
setAdminKey(config.adminKey)
|
|
||||||
|
|
||||||
// XXX This is insecure, XSS vulns could lead to loss of funds!
|
// XXX This is insecure, XSS vulns could lead to loss of funds!
|
||||||
// -> check how mutiny encrypts their wallet and/or check if we can leverage web workers
|
// -> check how mutiny encrypts their wallet and/or check if we can leverage web workers
|
||||||
@ -186,8 +183,7 @@ export function LNbitsProvider ({ children }) {
|
|||||||
|
|
||||||
const clearConfig = useCallback(() => {
|
const clearConfig = useCallback(() => {
|
||||||
window.localStorage.removeItem(storageKey)
|
window.localStorage.removeItem(storageKey)
|
||||||
setUrl('')
|
setConfig({})
|
||||||
setAdminKey('')
|
|
||||||
setStatus(undefined)
|
setStatus(undefined)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -196,8 +192,8 @@ export function LNbitsProvider ({ children }) {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const value = useMemo(
|
const value = useMemo(
|
||||||
() => ({ name: 'LNbits', url, adminKey, status, saveConfig, clearConfig, getInfo, sendPayment }),
|
() => ({ name: 'LNbits', ...config, status, saveConfig, clearConfig, getInfo, sendPayment }),
|
||||||
[url, adminKey, status, saveConfig, clearConfig, getInfo, sendPayment])
|
[config, status, saveConfig, clearConfig, getInfo, sendPayment])
|
||||||
return (
|
return (
|
||||||
<LNbitsContext.Provider value={value}>
|
<LNbitsContext.Provider value={value}>
|
||||||
{children}
|
{children}
|
||||||
|
112
components/webln/lnbits2.js
Normal file
112
components/webln/lnbits2.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { bolt11Tags } from '@/lib/bolt11'
|
||||||
|
|
||||||
|
export const name = 'LNbits'
|
||||||
|
|
||||||
|
let config, logger
|
||||||
|
|
||||||
|
export function setConfig (_config) {
|
||||||
|
config = _config
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setLogger (_logger) {
|
||||||
|
logger = _logger
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getInfo () {
|
||||||
|
const response = await getWallet(config.url, config.adminKey)
|
||||||
|
return {
|
||||||
|
node: {
|
||||||
|
alias: response.name,
|
||||||
|
pubkey: ''
|
||||||
|
},
|
||||||
|
methods: [
|
||||||
|
'getInfo',
|
||||||
|
'getBalance',
|
||||||
|
'sendPayment'
|
||||||
|
],
|
||||||
|
version: '1.0',
|
||||||
|
supports: ['lightning']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendPayment (bolt11) {
|
||||||
|
const { url, adminKey } = config
|
||||||
|
|
||||||
|
const hash = bolt11Tags(bolt11).payment_hash
|
||||||
|
logger.info('sending payment:', `payment_hash=${hash}`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await postPayment(url, adminKey, bolt11)
|
||||||
|
|
||||||
|
const checkResponse = await getPayment(url, adminKey, response.payment_hash)
|
||||||
|
if (!checkResponse.preimage) {
|
||||||
|
throw new Error('No preimage')
|
||||||
|
}
|
||||||
|
|
||||||
|
const preimage = checkResponse.preimage
|
||||||
|
logger.ok('payment successful:', `payment_hash=${hash}`, `preimage=${preimage}`)
|
||||||
|
return { preimage }
|
||||||
|
} catch (err) {
|
||||||
|
logger.error('payment failed:', `payment_hash=${hash}`, err.message || err.toString?.())
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getWallet = async (baseUrl, adminKey) => {
|
||||||
|
const url = baseUrl.replace(/\/+$/, '')
|
||||||
|
const path = '/api/v1/wallet'
|
||||||
|
|
||||||
|
const headers = new Headers()
|
||||||
|
headers.append('Accept', 'application/json')
|
||||||
|
headers.append('Content-Type', 'application/json')
|
||||||
|
headers.append('X-Api-Key', adminKey)
|
||||||
|
|
||||||
|
const res = await fetch(url + path, { method: 'GET', headers })
|
||||||
|
if (!res.ok) {
|
||||||
|
const errBody = await res.json()
|
||||||
|
throw new Error(errBody.detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
const wallet = await res.json()
|
||||||
|
return wallet
|
||||||
|
}
|
||||||
|
|
||||||
|
async function postPayment (baseUrl, adminKey, bolt11) {
|
||||||
|
const url = baseUrl.replace(/\/+$/, '')
|
||||||
|
const path = '/api/v1/payments'
|
||||||
|
|
||||||
|
const headers = new Headers()
|
||||||
|
headers.append('Accept', 'application/json')
|
||||||
|
headers.append('Content-Type', 'application/json')
|
||||||
|
headers.append('X-Api-Key', adminKey)
|
||||||
|
|
||||||
|
const body = JSON.stringify({ bolt11, out: true })
|
||||||
|
|
||||||
|
const res = await fetch(url + path, { method: 'POST', headers, body })
|
||||||
|
if (!res.ok) {
|
||||||
|
const errBody = await res.json()
|
||||||
|
throw new Error(errBody.detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
const payment = await res.json()
|
||||||
|
return payment
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPayment (baseUrl, adminKey, paymentHash) {
|
||||||
|
const url = baseUrl.replace(/\/+$/, '')
|
||||||
|
const path = `/api/v1/payments/${paymentHash}`
|
||||||
|
|
||||||
|
const headers = new Headers()
|
||||||
|
headers.append('Accept', 'application/json')
|
||||||
|
headers.append('Content-Type', 'application/json')
|
||||||
|
headers.append('X-Api-Key', adminKey)
|
||||||
|
|
||||||
|
const res = await fetch(url + path, { method: 'GET', headers })
|
||||||
|
if (!res.ok) {
|
||||||
|
const errBody = await res.json()
|
||||||
|
throw new Error(errBody.detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
const payment = await res.json()
|
||||||
|
return payment
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user