diff --git a/api/resolvers/wallet.js b/api/resolvers/wallet.js
index dd1d8847..2a468acc 100644
--- a/api/resolvers/wallet.js
+++ b/api/resolvers/wallet.js
@@ -1,32 +1,30 @@
-import { getIdentity, createHodlInvoice, createInvoice, decodePaymentRequest, payViaPaymentRequest, cancelHodlInvoice, getInvoice as getInvoiceFromLnd, getNode, authenticatedLndGrpc, deletePayment, getPayment } from 'ln-service'
+import { createHodlInvoice, createInvoice, decodePaymentRequest, payViaPaymentRequest, cancelHodlInvoice, getInvoice as getInvoiceFromLnd, getNode, deletePayment, getPayment, getIdentity } from 'ln-service'
import { GraphQLError } from 'graphql'
import crypto, { timingSafeEqual } from 'crypto'
import serialize from './serial'
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
import { SELECT, itemQueryWithMeta } from './item'
import { msatsToSats, msatsToSatsDecimal } from '@/lib/format'
-import { amountSchema, ssValidate, withdrawlSchema } from '@/lib/validate'
+import { amountSchema, ssValidate, withdrawlSchema, lnAddrSchema } from '@/lib/validate'
import { ANON_BALANCE_LIMIT_MSATS, ANON_INV_PENDING_LIMIT, USER_ID, BALANCE_LIMIT_MSATS, INVOICE_RETENTION_DAYS, INV_PENDING_LIMIT, USER_IDS_BALANCE_NO_LIMIT } from '@/lib/constants'
import { datePivot } from '@/lib/time'
import assertGofacYourself from './ofac'
import assertApiKeyNotPermitted from './apiKey'
-import { createInvoice as clnCreateInvoice } from '@/lib/cln'
import { bolt11Tags } from '@/lib/bolt11'
import { checkInvoice } from 'worker/wallet'
-import * as lnd from 'wallets/lnd'
-import * as lnAddr from 'wallets/lightning-address'
-import * as cln from 'wallets/cln'
-import { fetchLnAddrInvoice, generateResolverName } from '@/lib/wallet'
-
-export const SERVER_WALLET_DEFS = [lnd, lnAddr, cln]
+import walletDefs from 'wallets/server'
+import { generateResolverName } from '@/lib/wallet'
+import { lnAddrOptions } from '@/lib/lnurl'
function injectResolvers (resolvers) {
console.group('injected GraphQL resolvers:')
for (
- const w of SERVER_WALLET_DEFS) {
+ // FIXME: this throws
+ // TypeError: import_server.default is not iterable
+ const w of walletDefs) {
const {
schema,
- server: { walletType, walletField, testConnect }
+ walletType, walletField, testConnect
// app and worker import file differently
} = w.default || w
const resolverName = generateResolverName(walletField)
@@ -40,10 +38,7 @@ function injectResolvers (resolvers) {
data,
{
me,
- models,
- addWalletLog,
- lnService: { authenticatedLndGrpc, createInvoice },
- cln: { createInvoice: clnCreateInvoice }
+ models
}
)
}, { settings, data }, { me, models })
@@ -726,10 +721,69 @@ export async function sendToLnAddr (parent, { addr, amount, maxFee, comment, ...
{
me,
models,
- lnd,
- lnService: { decodePaymentRequest, getIdentity }
+ lnd
})
// take pr and createWithdrawl
return await createWithdrawal(parent, { invoice: res.pr, maxFee }, { me, models, lnd, headers })
}
+
+export async function fetchLnAddrInvoice (
+ { addr, amount, maxFee, comment, ...payer },
+ {
+ me, models, lnd, autoWithdraw = false
+ }) {
+ const options = await lnAddrOptions(addr)
+ await ssValidate(lnAddrSchema, { addr, amount, maxFee, comment, ...payer }, options)
+
+ if (payer) {
+ payer = {
+ ...payer,
+ identifier: payer.identifier ? `${me.name}@stacker.news` : undefined
+ }
+ payer = Object.fromEntries(
+ Object.entries(payer).filter(([, value]) => !!value)
+ )
+ }
+
+ const milliamount = 1000 * amount
+ const callback = new URL(options.callback)
+ callback.searchParams.append('amount', milliamount)
+
+ if (comment?.length) {
+ callback.searchParams.append('comment', comment)
+ }
+
+ let stringifiedPayerData = ''
+ if (payer && Object.entries(payer).length) {
+ stringifiedPayerData = JSON.stringify(payer)
+ callback.searchParams.append('payerdata', stringifiedPayerData)
+ }
+
+ // call callback with amount and conditionally comment
+ const res = await (await fetch(callback.toString())).json()
+ if (res.status === 'ERROR') {
+ throw new Error(res.reason)
+ }
+
+ // decode invoice
+ try {
+ const decoded = await decodePaymentRequest({ lnd, request: res.pr })
+ const ourPubkey = (await getIdentity({ lnd })).public_key
+ if (autoWithdraw && decoded.destination === ourPubkey && process.env.NODE_ENV === 'production') {
+ // unset lnaddr so we don't trigger another withdrawal with same destination
+ await models.wallet.deleteMany({
+ where: { userId: me.id, type: 'LIGHTNING_ADDRESS' }
+ })
+ throw new Error('automated withdrawals to other stackers are not allowed')
+ }
+ if (!decoded.mtokens || BigInt(decoded.mtokens) !== BigInt(milliamount)) {
+ throw new Error('invoice has incorrect amount')
+ }
+ } catch (e) {
+ console.log(e)
+ throw e
+ }
+
+ return res
+}
diff --git a/api/typeDefs/wallet.js b/api/typeDefs/wallet.js
index 50769b06..b8e9935a 100644
--- a/api/typeDefs/wallet.js
+++ b/api/typeDefs/wallet.js
@@ -1,10 +1,11 @@
import { gql } from 'graphql-tag'
-import { SERVER_WALLET_DEFS } from '@/api/resolvers/wallet'
import { generateResolverName } from '@/lib/wallet'
+import walletDefs from 'wallets/server'
+
function injectTypeDefs (typeDefs) {
console.group('injected GraphQL type defs:')
- const injected = SERVER_WALLET_DEFS.map(
+ const injected = walletDefs.map(
(w) => {
let args = 'id: ID, '
args += w.fields.map(f => {
@@ -15,7 +16,7 @@ function injectTypeDefs (typeDefs) {
return arg
}).join(', ')
args += ', settings: AutowithdrawSettings!'
- const resolverName = generateResolverName(w.server.walletField)
+ const resolverName = generateResolverName(w.walletField)
const typeDef = `${resolverName}(${args}): Boolean`
console.log(typeDef)
return typeDef
diff --git a/components/wallet-logger.js b/components/wallet-logger.js
index 02e8a280..361bb319 100644
--- a/components/wallet-logger.js
+++ b/components/wallet-logger.js
@@ -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 { getWalletByType } from 'wallets'
import { gql, useMutation, useQuery } from '@apollo/client'
import { useMe } from './me'
@@ -128,7 +128,7 @@ export const WalletLoggerProvider = ({ children }) => {
.map(({ createdAt, wallet: walletType, ...log }) => {
return {
ts: +new Date(createdAt),
- wallet: tag(getServerWallet(walletType)),
+ wallet: tag(getWalletByType(walletType)),
...log
}
})
@@ -146,7 +146,7 @@ export const WalletLoggerProvider = ({ children }) => {
{
onCompleted: (_, { variables: { wallet: walletType } }) => {
setLogs((logs) => {
- return logs.filter(l => walletType ? l.wallet !== getServerWallet(walletType).name : false)
+ return logs.filter(l => walletType ? l.wallet !== getWalletByType(walletType).name : false)
})
}
}
diff --git a/lib/wallet.js b/lib/wallet.js
index fba35541..bff1d915 100644
--- a/lib/wallet.js
+++ b/lib/wallet.js
@@ -1,66 +1,3 @@
-import { lnAddrOptions } from './lnurl'
-import { lnAddrSchema, ssValidate } from './validate'
-
-export async function fetchLnAddrInvoice ({ addr, amount, maxFee, comment, ...payer },
- {
- me, models, lnd, autoWithdraw = false,
- lnService: { decodePaymentRequest, getIdentity }
- }) {
- const options = await lnAddrOptions(addr)
- await ssValidate(lnAddrSchema, { addr, amount, maxFee, comment, ...payer }, options)
-
- if (payer) {
- payer = {
- ...payer,
- identifier: payer.identifier ? `${me.name}@stacker.news` : undefined
- }
- payer = Object.fromEntries(
- Object.entries(payer).filter(([, value]) => !!value)
- )
- }
-
- const milliamount = 1000 * amount
- const callback = new URL(options.callback)
- callback.searchParams.append('amount', milliamount)
-
- if (comment?.length) {
- callback.searchParams.append('comment', comment)
- }
-
- let stringifiedPayerData = ''
- if (payer && Object.entries(payer).length) {
- stringifiedPayerData = JSON.stringify(payer)
- callback.searchParams.append('payerdata', stringifiedPayerData)
- }
-
- // call callback with amount and conditionally comment
- const res = await (await fetch(callback.toString())).json()
- if (res.status === 'ERROR') {
- throw new Error(res.reason)
- }
-
- // decode invoice
- try {
- const decoded = await decodePaymentRequest({ lnd, request: res.pr })
- const ourPubkey = (await getIdentity({ lnd })).public_key
- if (autoWithdraw && decoded.destination === ourPubkey && process.env.NODE_ENV === 'production') {
- // unset lnaddr so we don't trigger another withdrawal with same destination
- await models.wallet.deleteMany({
- where: { userId: me.id, type: 'LIGHTNING_ADDRESS' }
- })
- throw new Error('automated withdrawals to other stackers are not allowed')
- }
- if (!decoded.mtokens || BigInt(decoded.mtokens) !== BigInt(milliamount)) {
- throw new Error('invoice has incorrect amount')
- }
- } catch (e) {
- console.log(e)
- throw e
- }
-
- return res
-}
-
export function generateResolverName (walletField) {
const capitalized = walletField[0].toUpperCase() + walletField.slice(1)
return `upsertWallet${capitalized}`
diff --git a/next.config.js b/next.config.js
index 00b51f49..6a6c02ed 100644
--- a/next.config.js
+++ b/next.config.js
@@ -232,7 +232,10 @@ module.exports = withPlausibleProxy()({
})
}
+ // const ignorePlugin = new webpack.IgnorePlugin({ resourceRegExp: /server\.js$/ })
+
config.plugins.push(workboxPlugin)
+ // config.plugins.push(ignorePlugin)
}
config.module.rules.push(
diff --git a/wallets/_example.js b/wallets/_example.js
deleted file mode 100644
index c4a2369d..00000000
--- a/wallets/_example.js
+++ /dev/null
@@ -1,147 +0,0 @@
-import { lnbitsSchema } from '@/lib/validate'
-
-// ~~~
-// AFTER YOU HAVE FILLED OUT THIS TEMPLATE, IMPORT THIS FILE IN components/wallet/index.js
-// AND ADD IT TO THE `WALLET_DEFS` array.
-// DO THE SAME IN api/resolvers/wallet.js WITH THE `SERVER_WALLET_DEFS` ARRAY.
-// (these arrays are separate to avoid backend imports in frontend)
-// ~~~
-
-// This name is used to identify this wallet and thus must be unique.
-// It is used with the useWallet hook to select this wallet, see components/wallet/index.js.
-// [required]
-export const name = 'lnbits-as-an-example'
-
-// The form to configure this wallet is generated from these fields,
-// see the component in pages/settings/wallets/[wallet].js.
-//
-//
-// If not handled otherwise in , field properties are simply
-// passed into or as props (component depends on 'type').
-//
-// For example, the following fields will generate a config in this shape (depending on user inputs):
-// {
-// url: 'https://demo.lnbits.com/',
-// adminKey: 'a47acd6feba4489e9e99b256b4ae9049'
-// }
-// [required]
-export const fields = [
- {
- name: 'url',
- label: 'lnbits url',
- // 'type' can be 'text' or 'password'
- type: 'text'
- },
- {
- name: 'adminKey',
- label: 'admin key',
- type: 'password'
- // see other wallets for more complex fields
- }
-]
-
-// Used to display information about this wallet to the user in the wallet list or during configuration,
-// see components/wallet-card.js and pages/settings/wallets/[wallet].js.
-// [required]
-export const card = {
- title: 'LNbits',
- // subtitle supports markdown
- subtitle: 'use [LNbits](https://lnbits.com/) for payments',
- badges: ['send only', 'non-custodialish']
-}
-
-// The validation schema that will be used on the client and server during save
-// [required]
-export const schema = lnbitsSchema
-
-// This optional function will be called during save to abort the save if the configuration is invalid.
-// It receives the config and context as arguments.
-// It must throw an error if validation fails.
-// [optional]
-export async function validate (config, context) {
- // what the config object will contain is determined by the fields array above
- // const { url, adminKey } = config
-
- // the context includes the logger and other useful stuff, see save method in components/wallet/index.js
- const { logger } = context
-
- // validate should log useful, wallet-specific information for the user
- logger.info('running some wallet-specific validation')
-
- // ...
- // throw error if validation failed
-}
-
-// If this wallet supports payments, you need to implement this function:
-//
-// sendPayment: (bolt11, config, context) => Promise<{ preimage: string }>
-//
-// [required for payments]
-export async function sendPayment (bolt11, config, context) {
- // ...
-}
-
-// If this wallet supports receiving, you need to implement this object.
-// [required for receiving]
-export const server = {
- // This must match a WalletType enum value in the database
- // since it will be used to fetch this wallet using the WALLET_BY_TYPE GraphQL query,
- // see `useServerConfig` in components/wallet/index.js.
- // [required]
- walletType: 'LNBITS',
-
- // This used must match a column of the 'Wallet' table
- // since it will be used to save the wallet configuration.
- // [required]
- walletField: 'walletLNbits',
-
- // Similar to validate above, this function should throw an error if the connection test fails.
- // It is called on save on the server before writing the configuration to the database.
- // As the name suggests, a good idea is to try to connect to the wallet and create an invoice in this function.
- // [required]
- testConnect: async (
- // Wallet configuration as entered by the user
- config,
- // Context object with useful stuff, see `injectResolvers` in pages/api/resolvers/wallet.js.
- {
- me,
- models,
- addWalletLog,
- lnService: { authenticatedLndGrpc, createInvoice },
- cln: { createInvoice: clnCreateInvoice }
- }
- ) => {
-
- // ...
- // throw error if validation failed
- // (logging errors is handled by calling context but you can add custom logging on success here)
- },
-
- // This function is called during autowithdrawals.
- // It should return a bolt11 payment request.
- //
- // createInvoice: ({ amount, maxFee }, config, context) => Promise
- //
- createInvoice: async (
- { amount, maxFee },
- { socket, rune, cert },
- // Context object with useful stuff, see `autowithdraw` function in worker/autowithdraw.js.
- {
- me,
- models,
- // SN LND node instance
- lnd,
- lnService: {
- authenticatedLndGrpc,
- createInvoice: lndCreateInvoice,
- getIdentity,
- decodePaymentRequest
- },
- cln: {
- createInvoice: clnCreateInvoice
- }
- }
- ) => {
- // ... create invoice and return bolt11 that the SN node will pay
- }
-}
diff --git a/wallets/client.js b/wallets/client.js
new file mode 100644
index 00000000..2cfffcec
--- /dev/null
+++ b/wallets/client.js
@@ -0,0 +1,8 @@
+import * as nwc from 'wallets/nwc/client'
+import * as lnbits from 'wallets/lnbits/client'
+import * as lnc from 'wallets/lnc/client'
+import * as lnAddr from 'wallets/lightning-address/client'
+import * as cln from 'wallets/cln/client'
+import * as lnd from 'wallets/lnd/client'
+
+export default [nwc, lnbits, lnc, lnAddr, cln, lnd]
diff --git a/wallets/cln/client.js b/wallets/cln/client.js
new file mode 100644
index 00000000..d9192b05
--- /dev/null
+++ b/wallets/cln/client.js
@@ -0,0 +1 @@
+export * from 'wallets/cln'
diff --git a/wallets/cln/index.js b/wallets/cln/index.js
index 9644ca04..04a3bc5b 100644
--- a/wallets/cln/index.js
+++ b/wallets/cln/index.js
@@ -1,5 +1,4 @@
import { CLNAutowithdrawSchema } from '@/lib/validate'
-import { server } from 'wallets/cln/server'
export const name = 'cln'
@@ -41,5 +40,3 @@ export const card = {
}
export const schema = CLNAutowithdrawSchema
-
-export { server }
diff --git a/wallets/cln/server.js b/wallets/cln/server.js
index 64fe379b..a8ca224f 100644
--- a/wallets/cln/server.js
+++ b/wallets/cln/server.js
@@ -1,39 +1,44 @@
import { ensureB64 } from '@/lib/format'
+import { createInvoice as clnCreateInvoice } from '@/lib/cln'
+import { addWalletLog } from '@/api/resolvers/wallet'
-export const server = {
- walletType: 'CLN',
- walletField: 'walletCLN',
- 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)
+export * from 'wallets/cln'
- 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 const walletType = 'CLN'
+
+export const walletField = 'walletCLN'
+
+export const testConnect = async (
+ { socket, rune, cert },
+ { me, models }
+) => {
+ cert = ensureB64(cert)
+ const inv = await clnCreateInvoice({
+ 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
+}
+
+export const createInvoice = async (
+ { amount },
+ { socket, rune, cert },
+ { me, models, lnd }
+) => {
+ cert = ensureB64(cert)
+
+ const inv = await clnCreateInvoice({
+ socket,
+ rune,
+ cert,
+ description: me.hideInvoiceDesc ? undefined : 'autowithdraw to CLN from SN',
+ msats: amount + 'sat',
+ expiry: 360
+ })
+ return inv.bolt11
}
diff --git a/wallets/index.js b/wallets/index.js
index 05c6ca65..d2665d48 100644
--- a/wallets/index.js
+++ b/wallets/index.js
@@ -5,12 +5,7 @@ import { useWalletLogger } from '@/components/wallet-logger'
import { SSR } from '@/lib/constants'
import { bolt11Tags } from '@/lib/bolt11'
-import * as lnbits from 'wallets/lnbits'
-import * as nwc from 'wallets/nwc'
-import * as lnc from 'wallets/lnc'
-import * as lnd from 'wallets/lnd'
-import * as lnAddr from 'wallets/lightning-address'
-import * as cln from 'wallets/cln'
+import walletDefs from 'wallets/client'
import { gql, useApolloClient, useQuery } from '@apollo/client'
import { REMOVE_WALLET, WALLET_BY_TYPE } from '@/fragments/wallet'
import { autowithdrawInitial } from '@/components/autowithdraw-shared'
@@ -18,9 +13,6 @@ import { useShowModal } from '@/components/modal'
import { useToast } from '../components/toast'
import { generateResolverName } from '@/lib/wallet'
-// wallet definitions
-export const WALLET_DEFS = [lnbits, nwc, lnc, lnd, lnAddr, cln]
-
export const Status = {
Initialized: 'Initialized',
Enabled: 'Enabled',
@@ -249,15 +241,15 @@ function generateMutation (wallet) {
}
export function getWalletByName (name) {
- return WALLET_DEFS.find(def => def.name === name)
+ return walletDefs.find(def => def.name === name)
}
-export function getServerWallet (type) {
- return WALLET_DEFS.find(def => def.server?.walletType === type)
+export function getWalletByType (type) {
+ return walletDefs.find(def => def.server?.walletType === type)
}
export function getEnabledWallet (me) {
- return WALLET_DEFS
+ return walletDefs
.filter(def => !!def.sendPayment)
.map(def => {
// populate definition with properties from useWallet that are required for sorting
@@ -290,7 +282,7 @@ export function walletPrioritySort (w1, w2) {
}
export function useWallets () {
- const wallets = WALLET_DEFS.map(def => useWallet(def.name))
+ const wallets = walletDefs.map(def => useWallet(def.name))
const resetClient = useCallback(async (wallet) => {
for (const w of wallets) {
diff --git a/wallets/lightning-address/client.js b/wallets/lightning-address/client.js
new file mode 100644
index 00000000..004c4e76
--- /dev/null
+++ b/wallets/lightning-address/client.js
@@ -0,0 +1 @@
+export * from 'wallets/lightning-address'
diff --git a/wallets/lightning-address/index.js b/wallets/lightning-address/index.js
index 4543d608..496a248f 100644
--- a/wallets/lightning-address/index.js
+++ b/wallets/lightning-address/index.js
@@ -1,5 +1,4 @@
import { lnAddrAutowithdrawSchema } from '@/lib/validate'
-import { server } from 'wallets/lightning-address/server'
export const name = 'lightning-address'
export const shortName = 'lnAddr'
@@ -20,5 +19,3 @@ export const card = {
}
export const schema = lnAddrAutowithdrawSchema
-
-export { server }
diff --git a/wallets/lightning-address/server.js b/wallets/lightning-address/server.js
index b06099cf..22b184ad 100644
--- a/wallets/lightning-address/server.js
+++ b/wallets/lightning-address/server.js
@@ -1,29 +1,32 @@
+import { fetchLnAddrInvoice } from '@/api/resolvers/wallet'
import { lnAddrOptions } from '@/lib/lnurl'
-import { fetchLnAddrInvoice } from '@/lib/wallet'
-export const server = {
- walletType: 'LIGHTNING_ADDRESS',
- walletField: 'walletLightningAddress',
- testConnect: async (
- { address },
- { me, models, addWalletLog }
- ) => {
- const options = await lnAddrOptions(address)
- await addWalletLog({ wallet: { type: 'LIGHTNING_ADDRESS' }, level: 'SUCCESS', message: 'fetched payment details' }, { me, models })
- return options
- },
- createInvoice: async (
- { amount, maxFee },
- { address },
- { me, models, lnd, lnService }
- ) => {
- const res = await fetchLnAddrInvoice({ addr: address, amount, maxFee }, {
- me,
- models,
- lnd,
- lnService,
- autoWithdraw: true
- })
- return res.pr
- }
+export * from 'wallets/lightning-address'
+
+export const walletType = 'LIGHTNING_ADDRESS'
+
+export const walletField = 'walletLightningAddress'
+
+export const testConnect = async (
+ { address },
+ { me, models, addWalletLog }
+) => {
+ const options = await lnAddrOptions(address)
+ await addWalletLog({ wallet: { type: 'LIGHTNING_ADDRESS' }, level: 'SUCCESS', message: 'fetched payment details' }, { me, models })
+ return options
+}
+
+export const createInvoice = async (
+ { amount, maxFee },
+ { address },
+ { me, models, lnd, lnService }
+) => {
+ const res = await fetchLnAddrInvoice({ addr: address, amount, maxFee }, {
+ me,
+ models,
+ lnd,
+ lnService,
+ autoWithdraw: true
+ })
+ return res.pr
}
diff --git a/wallets/lnbits/client.js b/wallets/lnbits/client.js
index 1cbfa224..8598c574 100644
--- a/wallets/lnbits/client.js
+++ b/wallets/lnbits/client.js
@@ -1,3 +1,5 @@
+export * from 'wallets/lnbits'
+
export async function validate ({ url, adminKey }, { logger }) {
logger.info('trying to fetch wallet')
diff --git a/wallets/lnbits/index.js b/wallets/lnbits/index.js
index 2194bfa6..f3f23aa8 100644
--- a/wallets/lnbits/index.js
+++ b/wallets/lnbits/index.js
@@ -1,5 +1,4 @@
import { lnbitsSchema } from '@/lib/validate'
-import { sendPayment, validate } from 'wallets/lnbits/client'
export const name = 'lnbits'
@@ -23,5 +22,3 @@ export const card = {
}
export const schema = lnbitsSchema
-
-export { sendPayment, validate }
diff --git a/wallets/lnc/client.js b/wallets/lnc/client.js
index 2e6e1266..34f7114e 100644
--- a/wallets/lnc/client.js
+++ b/wallets/lnc/client.js
@@ -6,6 +6,8 @@ import LNC from '@lightninglabs/lnc-web'
import { Mutex } from 'async-mutex'
import { Status } from 'wallets'
+export * from 'wallets/lnc'
+
const XXX_DEFAULT_PASSWORD = 'password'
export async function validate ({ pairingPhrase, password }, { me, logger }) {
diff --git a/wallets/lnc/index.js b/wallets/lnc/index.js
index 20790bfc..db202948 100644
--- a/wallets/lnc/index.js
+++ b/wallets/lnc/index.js
@@ -1,5 +1,4 @@
import { lncSchema } from '@/lib/validate'
-import { sendPayment, validate } from 'wallets/lnc/client'
export const name = 'lnc'
@@ -26,5 +25,3 @@ export const card = {
}
export const schema = lncSchema
-
-export { sendPayment, validate }
diff --git a/wallets/lnd/client.js b/wallets/lnd/client.js
new file mode 100644
index 00000000..2aeb5534
--- /dev/null
+++ b/wallets/lnd/client.js
@@ -0,0 +1 @@
+export * from 'wallets/lnd'
diff --git a/wallets/lnd/index.js b/wallets/lnd/index.js
index c7c872c2..2ecf32ee 100644
--- a/wallets/lnd/index.js
+++ b/wallets/lnd/index.js
@@ -1,5 +1,4 @@
import { LNDAutowithdrawSchema } from '@/lib/validate'
-import { server } from 'wallets/lnd/server'
export const name = 'lnd'
@@ -42,5 +41,3 @@ export const card = {
}
export const schema = LNDAutowithdrawSchema
-
-export { server }
diff --git a/wallets/lnd/server.js b/wallets/lnd/server.js
index 9ba31a41..8d8d4a70 100644
--- a/wallets/lnd/server.js
+++ b/wallets/lnd/server.js
@@ -1,58 +1,63 @@
import { ensureB64 } from '@/lib/format'
import { datePivot } from '@/lib/time'
+import { authenticatedLndGrpc, createInvoice as lndCreateInvoice } from 'ln-service'
+import { addWalletLog } from '@/api/resolvers/wallet'
-export const server = {
- walletType: 'LND',
- walletField: 'walletLND',
- testConnect: async (
- { cert, macaroon, socket },
- { me, models, addWalletLog, lnService: { authenticatedLndGrpc, createInvoice } }
- ) => {
- try {
- cert = ensureB64(cert)
- macaroon = ensureB64(macaroon)
+export * from 'wallets/lnd'
- const { lnd } = await authenticatedLndGrpc({
- cert,
- macaroon,
- socket
- })
+export const walletType = 'LND'
- const inv = await createInvoice({
- description: 'SN connection test',
- lnd,
- tokens: 0,
- expires_at: new Date()
- })
+export const walletField = 'walletLND'
- // 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 })
+export const testConnect = async (
+ { cert, macaroon, socket },
+ { me, models }
+) => {
+ try {
+ cert = ensureB64(cert)
+ macaroon = ensureB64(macaroon)
- 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',
+ const inv = await lndCreateInvoice({
+ description: 'SN connection test',
lnd,
- tokens: amount,
- expires_at: datePivot(new Date(), { seconds: 360 })
+ tokens: 0,
+ expires_at: new Date()
})
- return invoice.request
+ // 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)
}
}
+
+export const createInvoice = async (
+ { amount },
+ { cert, macaroon, socket },
+ { me }
+) => {
+ const { lnd } = await authenticatedLndGrpc({
+ cert,
+ macaroon,
+ socket
+ })
+
+ const invoice = await lndCreateInvoice({
+ description: me.hideInvoiceDesc ? undefined : 'autowithdraw to LND from SN',
+ lnd,
+ tokens: amount,
+ expires_at: datePivot(new Date(), { seconds: 360 })
+ })
+
+ return invoice.request
+}
diff --git a/wallets/nwc/client.js b/wallets/nwc/client.js
index eac7482c..3123d839 100644
--- a/wallets/nwc/client.js
+++ b/wallets/nwc/client.js
@@ -1,6 +1,8 @@
import { parseNwcUrl } from '@/lib/url'
import { Relay, finalizeEvent, nip04 } from 'nostr-tools'
+export * from 'wallets/nwc'
+
export async function validate ({ nwcUrl }, { logger }) {
const { relayUrl, walletPubkey } = parseNwcUrl(nwcUrl)
diff --git a/wallets/nwc/index.js b/wallets/nwc/index.js
index 476eb42b..36ae28aa 100644
--- a/wallets/nwc/index.js
+++ b/wallets/nwc/index.js
@@ -1,5 +1,4 @@
import { nwcSchema } from '@/lib/validate'
-import { sendPayment, validate } from 'wallets/nwc/client'
export const name = 'nwc'
@@ -18,5 +17,3 @@ export const card = {
}
export const schema = nwcSchema
-
-export { sendPayment, validate }
diff --git a/wallets/server.js b/wallets/server.js
new file mode 100644
index 00000000..1b47606e
--- /dev/null
+++ b/wallets/server.js
@@ -0,0 +1,8 @@
+import * as lnd from 'wallets/lnd/server'
+import * as cln from 'wallets/cln/server'
+import * as lnAddr from 'wallets/lightning-address/server'
+
+// worker and app import modules differently
+// const resolveImport = i => i.default || i
+
+export default [lnd, cln, lnAddr]
diff --git a/worker/autowithdraw.js b/worker/autowithdraw.js
index e678e9b1..6b310269 100644
--- a/worker/autowithdraw.js
+++ b/worker/autowithdraw.js
@@ -1,7 +1,6 @@
-import { authenticatedLndGrpc, createInvoice as lndCreateInvoice, getIdentity, decodePaymentRequest } from 'ln-service'
import { msatsToSats, satsToMsats } from '@/lib/format'
-import { createWithdrawal, addWalletLog, SERVER_WALLET_DEFS } from '@/api/resolvers/wallet'
-import { createInvoice as clnCreateInvoice } from '@/lib/cln'
+import { createWithdrawal, addWalletLog } from '@/api/resolvers/wallet'
+import walletDefs from 'wallets/server'
export async function autoWithdraw ({ data: { id }, models, lnd }) {
const user = await models.user.findUnique({ where: { id } })
@@ -48,9 +47,9 @@ export async function autoWithdraw ({ data: { id }, models, lnd }) {
})
for (const wallet of wallets) {
- const w = SERVER_WALLET_DEFS.find(({ default: w }) => w.server.walletType === wallet.type)
+ const w = walletDefs.find(({ default: w }) => w.walletType === wallet.type)
try {
- const { server: { walletType, walletField, createInvoice } } = w.default
+ const { walletType, walletField, createInvoice } = w.default
return await autowithdraw(
{ walletType, walletField, createInvoice },
{ amount, maxFee },
@@ -58,6 +57,9 @@ export async function autoWithdraw ({ data: { id }, models, lnd }) {
)
} catch (error) {
console.error(error)
+
+ // TODO: I think this is a bug, `walletCreateInvoice` in `autowithdraw` should parse the error
+
// LND errors are in this shape: [code, type, { err: { code, details, metadata } }]
const details = error[2]?.err?.details || error.message || error.toString?.()
await addWalletLog({
@@ -99,16 +101,7 @@ async function autowithdraw (
{
me,
models,
- lnd,
- lnService: {
- authenticatedLndGrpc,
- createInvoice: lndCreateInvoice,
- getIdentity,
- decodePaymentRequest
- },
- cln: {
- createInvoice: clnCreateInvoice
- }
+ lnd
})
return await createWithdrawal(null, { invoice: bolt11, maxFee }, { me, models, lnd, walletId: wallet.id })