Put wallets into own folder

This commit is contained in:
ekzyis 2024-07-16 07:54:27 +02:00
parent cba76444dd
commit 7851366cd5
17 changed files with 213 additions and 197 deletions

1
.gitignore vendored
View File

@ -20,7 +20,6 @@ node_modules/
.DS_Store
*.pem
/*.sql
lnbits/
# debug
npm-debug.log*

View File

@ -1,7 +1,7 @@
import { useCallback, useMemo } from 'react'
import { useMe } from './me'
import { gql, useApolloClient, useMutation } from '@apollo/client'
import { useWallet } from '../wallets'
import { useWallet } from 'wallets'
import { FAST_POLL_INTERVAL, JIT_INVOICE_TIMEOUT_MS } from '@/lib/constants'
import { INVOICE } from '@/fragments/wallet'
import Invoice from '@/components/invoice'

View File

@ -2,7 +2,7 @@ import QRCode from 'qrcode.react'
import { CopyInput, InputSkeleton } from './form'
import InvoiceStatus from './invoice-status'
import { useEffect } from 'react'
import { useWallet } from '../wallets'
import { useWallet } from 'wallets'
import Bolt11Info from './bolt11-info'
export default function Qr ({ asIs, value, useWallet: automated, statusVariant, description, status }) {

View File

@ -3,7 +3,7 @@ import styles from '@/styles/wallet.module.css'
import Plug from '@/svgs/plug.svg'
import Gear from '@/svgs/settings-5-fill.svg'
import Link from 'next/link'
import { Status } from '../wallets'
import { Status } from 'wallets'
export default function WalletCard ({ wallet }) {
const { card: { title, badges } } = wallet

View File

@ -5,7 +5,7 @@ import { Button } from 'react-bootstrap'
import { useToast } from './toast'
import { useShowModal } from './modal'
import { WALLET_LOGS } from '@/fragments/wallet'
import { getServerWallet } from '../wallets'
import { getServerWallet } from 'wallets'
import { gql, useMutation, useQuery } from '@apollo/client'
import { useMe } from './me'

View File

@ -1,5 +1,5 @@
import { CLNAutowithdrawSchema } from '@/lib/validate'
import { ensureB64 } from '@/lib/format'
import { server } from 'wallets/cln/server'
export const name = 'cln'
@ -42,41 +42,4 @@ export const card = {
export const schema = CLNAutowithdrawSchema
export const server = {
walletType: 'CLN',
walletField: 'walletCLN',
resolverName: 'upsertWalletCLN',
testConnect: async (
{ socket, rune, cert },
{ me, models, addWalletLog, cln: { createInvoice } }
) => {
cert = ensureB64(cert)
const inv = await createInvoice({
socket,
rune,
cert,
description: 'SN connection test',
msats: 'any',
expiry: 0
})
await addWalletLog({ wallet: { type: 'CLN' }, level: 'SUCCESS', message: 'connected to CLN' }, { me, models })
return inv
},
createInvoice: async (
{ amount },
{ socket, rune, cert },
{ me, models, lnd, cln: { createInvoice } }
) => {
cert = ensureB64(cert)
const inv = await createInvoice({
socket,
rune,
cert,
description: me.hideInvoiceDesc ? undefined : 'autowithdraw to CLN from SN',
msats: amount + 'sat',
expiry: 360
})
return inv.bolt11
}
}
export { server }

40
wallets/cln/server.js Normal file
View File

@ -0,0 +1,40 @@
import { ensureB64 } from '@/lib/format'
export const server = {
walletType: 'CLN',
walletField: 'walletCLN',
resolverName: 'upsertWalletCLN',
testConnect: async (
{ socket, rune, cert },
{ me, models, addWalletLog, cln: { createInvoice } }
) => {
cert = ensureB64(cert)
const inv = await createInvoice({
socket,
rune,
cert,
description: 'SN connection test',
msats: 'any',
expiry: 0
})
await addWalletLog({ wallet: { type: 'CLN' }, level: 'SUCCESS', message: 'connected to CLN' }, { me, models })
return inv
},
createInvoice: async (
{ amount },
{ socket, rune, cert },
{ me, models, lnd, cln: { createInvoice } }
) => {
cert = ensureB64(cert)
const inv = await createInvoice({
socket,
rune,
cert,
description: me.hideInvoiceDesc ? undefined : 'autowithdraw to CLN from SN',
msats: amount + 'sat',
expiry: 360
})
return inv.bolt11
}
}

View File

@ -0,0 +1,24 @@
import { lnAddrAutowithdrawSchema } from '@/lib/validate'
import { server } from 'wallets/lightning-address/server'
export const name = 'lightning-address'
export const shortName = 'lnAddr'
export const fields = [
{
name: 'address',
label: 'lightning address',
type: 'text',
autoComplete: 'off'
}
]
export const card = {
title: 'lightning address',
subtitle: 'autowithdraw to a lightning address',
badges: ['receive only', 'non-custodialish']
}
export const schema = lnAddrAutowithdrawSchema
export { server }

View File

@ -1,27 +1,6 @@
import { lnAddrOptions } from '@/lib/lnurl'
import { lnAddrAutowithdrawSchema } from '@/lib/validate'
import { fetchLnAddrInvoice } from '@/lib/wallet'
export const name = 'lightning-address'
export const shortName = 'lnAddr'
export const fields = [
{
name: 'address',
label: 'lightning address',
type: 'text',
autoComplete: 'off'
}
]
export const card = {
title: 'lightning address',
subtitle: 'autowithdraw to a lightning address',
badges: ['receive only', 'non-custodialish']
}
export const schema = lnAddrAutowithdrawSchema
export const server = {
walletType: 'LIGHTNING_ADDRESS',
walletField: 'walletLightningAddress',

View File

@ -1,26 +1,3 @@
import { lnbitsSchema } from '@/lib/validate'
export const name = 'lnbits'
export const fields = [
{
name: 'url',
label: 'lnbits url',
type: 'text'
},
{
name: 'adminKey',
label: 'admin key',
type: 'password'
}
]
export const card = {
title: 'LNbits',
subtitle: 'use [LNbits](https://lnbits.com/) for payments',
badges: ['send only', 'non-custodialish']
}
export async function validate ({ url, adminKey }, { logger }) {
logger.info('trying to fetch wallet')
@ -30,8 +7,6 @@ export async function validate ({ url, adminKey }, { logger }) {
logger.ok('wallet found')
}
export const schema = lnbitsSchema
export async function sendPayment (bolt11, { url, adminKey }) {
url = url.replace(/\/+$/, '')

27
wallets/lnbits/index.js Normal file
View File

@ -0,0 +1,27 @@
import { lnbitsSchema } from '@/lib/validate'
import { sendPayment, validate } from 'wallets/lnbits/client'
export const name = 'lnbits'
export const fields = [
{
name: 'url',
label: 'lnbits url',
type: 'text'
},
{
name: 'adminKey',
label: 'admin key',
type: 'password'
}
]
export const card = {
title: 'LNbits',
subtitle: 'use [LNbits](https://lnbits.com/) for payments',
badges: ['send only', 'non-custodialish']
}
export const schema = lnbitsSchema
export { sendPayment, validate }

View File

@ -1,35 +1,10 @@
import LNC from '@lightninglabs/lnc-web'
import { Mutex } from 'async-mutex'
import { Form, PasswordInput, SubmitButton } from '@/components/form'
import CancelButton from '@/components/cancel-button'
import { Form, PasswordInput, SubmitButton } from '@/components/form'
import { InvoiceCanceledError, InvoiceExpiredError } from '@/components/payment'
import { bolt11Tags } from '@/lib/bolt11'
import LNC from '@lightninglabs/lnc-web'
import { Mutex } from 'async-mutex'
import { Status } from 'wallets'
import { lncSchema } from '@/lib/validate'
export const name = 'lnc'
export const fields = [
{
name: 'pairingPhrase',
label: 'pairing phrase',
type: 'password',
help: 'We only need permissions for the uri `/lnrpc.Lightning/SendPaymentSync`\n\nCreate a budgeted account with narrow permissions:\n\n```$ litcli accounts create --balance <budget>```\n\n```$ litcli sessions add --type custom --label <your label> --account_id <account_id> --uri /lnrpc.Lightning/SendPaymentSync```\n\nGrab the `pairing_secret_mnemonic` from the output and paste it here.'
},
{
name: 'password',
label: 'password',
type: 'password',
hint: 'encrypts your pairing phrase when stored locally',
optional: true
}
]
export const card = {
title: 'LNC',
subtitle: 'use Lightning Node Connect for LND payments',
badges: ['send only', 'non-custodialish', 'budgetable']
}
const XXX_DEFAULT_PASSWORD = 'password'
@ -49,8 +24,6 @@ export async function validate ({ pairingPhrase, password }, { me, logger }) {
}
}
export const schema = lncSchema
const mutex = new Mutex()
async function unlock ({ password }, { lnc, status, showModal, logger }) {

30
wallets/lnc/index.js Normal file
View File

@ -0,0 +1,30 @@
import { lncSchema } from '@/lib/validate'
import { sendPayment, validate } from 'wallets/lnc/client'
export const name = 'lnc'
export const fields = [
{
name: 'pairingPhrase',
label: 'pairing phrase',
type: 'password',
help: 'We only need permissions for the uri `/lnrpc.Lightning/SendPaymentSync`\n\nCreate a budgeted account with narrow permissions:\n\n```$ litcli accounts create --balance <budget>```\n\n```$ litcli sessions add --type custom --label <your label> --account_id <account_id> --uri /lnrpc.Lightning/SendPaymentSync```\n\nGrab the `pairing_secret_mnemonic` from the output and paste it here.'
},
{
name: 'password',
label: 'password',
type: 'password',
hint: 'encrypts your pairing phrase when stored locally',
optional: true
}
]
export const card = {
title: 'LNC',
subtitle: 'use Lightning Node Connect for LND payments',
badges: ['send only', 'non-custodialish', 'budgetable']
}
export const schema = lncSchema
export { sendPayment, validate }

View File

@ -1,6 +1,5 @@
import { ensureB64 } from '@/lib/format'
import { datePivot } from '@/lib/time'
import { LNDAutowithdrawSchema } from '@/lib/validate'
import { server } from 'wallets/lnd/server'
export const name = 'lnd'
@ -44,59 +43,4 @@ export const card = {
export const schema = LNDAutowithdrawSchema
export const server = {
walletType: 'LND',
walletField: 'walletLND',
resolverName: 'upsertWalletLND',
testConnect: async (
{ cert, macaroon, socket },
{ me, models, addWalletLog, lnService: { authenticatedLndGrpc, createInvoice } }
) => {
try {
cert = ensureB64(cert)
macaroon = ensureB64(macaroon)
const { lnd } = await authenticatedLndGrpc({
cert,
macaroon,
socket
})
const inv = await createInvoice({
description: 'SN connection test',
lnd,
tokens: 0,
expires_at: new Date()
})
// we wrap both calls in one try/catch since connection attempts happen on RPC calls
await addWalletLog({ wallet: { type: 'LND' }, level: 'SUCCESS', message: 'connected to LND' }, { me, models })
return inv
} catch (err) {
// LND errors are in this shape: [code, type, { err: { code, details, metadata } }]
const details = err[2]?.err?.details || err.message || err.toString?.()
throw new Error(details)
}
},
createInvoice: async (
{ amount },
{ cert, macaroon, socket },
{ me, lnService: { authenticatedLndGrpc, createInvoice } }
) => {
const { lnd } = await authenticatedLndGrpc({
cert,
macaroon,
socket
})
const invoice = await createInvoice({
description: me.hideInvoiceDesc ? undefined : 'autowithdraw to LND from SN',
lnd,
tokens: amount,
expires_at: datePivot(new Date(), { seconds: 360 })
})
return invoice.request
}
}
export { server }

59
wallets/lnd/server.js Normal file
View File

@ -0,0 +1,59 @@
import { ensureB64 } from '@/lib/format'
import { datePivot } from '@/lib/time'
export const server = {
walletType: 'LND',
walletField: 'walletLND',
resolverName: 'upsertWalletLND',
testConnect: async (
{ cert, macaroon, socket },
{ me, models, addWalletLog, lnService: { authenticatedLndGrpc, createInvoice } }
) => {
try {
cert = ensureB64(cert)
macaroon = ensureB64(macaroon)
const { lnd } = await authenticatedLndGrpc({
cert,
macaroon,
socket
})
const inv = await createInvoice({
description: 'SN connection test',
lnd,
tokens: 0,
expires_at: new Date()
})
// we wrap both calls in one try/catch since connection attempts happen on RPC calls
await addWalletLog({ wallet: { type: 'LND' }, level: 'SUCCESS', message: 'connected to LND' }, { me, models })
return inv
} catch (err) {
// LND errors are in this shape: [code, type, { err: { code, details, metadata } }]
const details = err[2]?.err?.details || err.message || err.toString?.()
throw new Error(details)
}
},
createInvoice: async (
{ amount },
{ cert, macaroon, socket },
{ me, lnService: { authenticatedLndGrpc, createInvoice } }
) => {
const { lnd } = await authenticatedLndGrpc({
cert,
macaroon,
socket
})
const invoice = await createInvoice({
description: me.hideInvoiceDesc ? undefined : 'autowithdraw to LND from SN',
lnd,
tokens: amount,
expires_at: datePivot(new Date(), { seconds: 360 })
})
return invoice.request
}
}

View File

@ -1,25 +1,6 @@
import { parseNwcUrl } from '@/lib/url'
import { nwcSchema } from '@/lib/validate'
import { Relay, finalizeEvent, nip04 } from 'nostr-tools'
export const name = 'nwc'
export const fields = [
{
name: 'nwcUrl',
label: 'connection',
type: 'password'
}
]
export const card = {
title: 'NWC',
subtitle: 'use Nostr Wallet Connect for payments',
badges: ['send only', 'non-custodialish']
}
export const schema = nwcSchema
export async function validate ({ nwcUrl }, { logger }) {
const { relayUrl, walletPubkey } = parseNwcUrl(nwcUrl)

22
wallets/nwc/index.js Normal file
View File

@ -0,0 +1,22 @@
import { nwcSchema } from '@/lib/validate'
import { sendPayment, validate } from 'wallets/nwc/client'
export const name = 'nwc'
export const fields = [
{
name: 'nwcUrl',
label: 'connection',
type: 'password'
}
]
export const card = {
title: 'NWC',
subtitle: 'use Nostr Wallet Connect for payments',
badges: ['send only', 'non-custodialish']
}
export const schema = nwcSchema
export { sendPayment, validate }