Generate more server wallet code (#1309)

* Generate more code from wallet defs

* generate "type WalletLND { ... }"
* generate "union WalletDetails = WalletLND | ..."
* hardcode function for __resolveType
* add comments where updates are needed if another server wallet is added

* Fix type for LN addresses

* Generate __resolveType from wallet.type column
This commit is contained in:
ekzyis 2024-08-18 11:32:25 -05:00 committed by GitHub
parent d2d04ce141
commit 3d8ae4a7a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 80 additions and 50 deletions

View File

@ -13,7 +13,7 @@ import assertApiKeyNotPermitted from './apiKey'
import { bolt11Tags } from '@/lib/bolt11' import { bolt11Tags } from '@/lib/bolt11'
import { finalizeHodlInvoice } from 'worker/wallet' import { finalizeHodlInvoice } from 'worker/wallet'
import walletDefs from 'wallets/server' import walletDefs from 'wallets/server'
import { generateResolverName } from '@/lib/wallet' import { generateResolverName, walletTypeToResolveType } from '@/lib/wallet'
import { lnAddrOptions } from '@/lib/lnurl' import { lnAddrOptions } from '@/lib/lnurl'
function injectResolvers (resolvers) { function injectResolvers (resolvers) {
@ -349,11 +349,17 @@ const resolvers = {
}) })
} }
}, },
WalletDetails: { Wallet: {
__resolveType (wallet) { wallet: async (wallet) => {
return wallet.address ? 'WalletLNAddr' : wallet.macaroon ? 'WalletLND' : wallet.rune ? 'WalletCLN' : 'WalletLNbits' return {
...wallet.wallet,
__resolveType: walletTypeToResolveType(wallet.type)
}
} }
}, },
WalletDetails: {
__resolveType: wallet => wallet.__resolveType
},
Mutation: { Mutation: {
createInvoice: async (parent, { amount, hodlInvoice = false, expireSecs = 3600 }, { me, models, lnd, headers }) => { createInvoice: async (parent, { amount, hodlInvoice = false, expireSecs = 3600 }, { me, models, lnd, headers }) => {
await ssValidate(amountSchema, { amount }) await ssValidate(amountSchema, { amount })

View File

@ -1,32 +1,59 @@
import { gql } from 'graphql-tag' import { gql } from 'graphql-tag'
import { generateResolverName } from '@/lib/wallet' import { fieldToGqlArg, generateResolverName, generateTypeDefName } from '@/lib/wallet'
import walletDefs from 'wallets/server' import walletDefs from 'wallets/server'
import { isServerField } from 'wallets' import { isServerField } from 'wallets'
function injectTypeDefs (typeDefs) { function injectTypeDefs (typeDefs) {
console.group('injected GraphQL type defs:') const injected = [rawTypeDefs(), mutationTypeDefs()]
const injected = walletDefs.map( return `${typeDefs}\n\n${injected.join('\n\n')}\n`
(w) => { }
let args = 'id: ID, '
args += w.fields function mutationTypeDefs () {
.filter(isServerField) console.group('injected GraphQL mutations:')
.map(f => {
let arg = `${f.name}: String` const typeDefs = walletDefs.map((w) => {
if (!f.optional) { let args = 'id: ID, '
arg += '!' args += w.fields
} .filter(isServerField)
return arg .map(fieldToGqlArg).join(', ')
}).join(', ') args += ', settings: AutowithdrawSettings!'
args += ', settings: AutowithdrawSettings!' const resolverName = generateResolverName(w.walletField)
const resolverName = generateResolverName(w.walletField) const typeDef = `${resolverName}(${args}): Boolean`
const typeDef = `${resolverName}(${args}): Boolean` console.log(typeDef)
console.log(typeDef) return typeDef
return typeDef })
})
console.groupEnd() console.groupEnd()
return `${typeDefs}\n\nextend type Mutation {\n${injected.join('\n')}\n}` return `extend type Mutation {\n${typeDefs.join('\n')}\n}`
}
function rawTypeDefs () {
console.group('injected GraphQL type defs:')
const typeDefs = walletDefs.map((w) => {
const args = w.fields
.filter(isServerField)
.map(fieldToGqlArg)
.map(s => ' ' + s)
.join('\n')
const typeDefName = generateTypeDefName(w.walletField)
const typeDef = `type ${typeDefName} {\n${args}\n}`
console.log(typeDef)
return typeDef
})
let union = 'union WalletDetails = '
union += walletDefs.map((w) => {
const typeDefName = generateTypeDefName(w.walletField)
return typeDefName
}).join(' | ')
console.log(union)
console.groupEnd()
return typeDefs.join('\n\n') + union
} }
const typeDefs = ` const typeDefs = `
@ -61,29 +88,6 @@ const typeDefs = `
wallet: WalletDetails! wallet: WalletDetails!
} }
type WalletLNAddr {
address: String!
}
type WalletLND {
socket: String!
macaroon: String!
cert: String
}
type WalletCLN {
socket: String!
rune: String!
cert: String
}
type WalletLNbits {
url: String!
invoiceKey: String!
}
union WalletDetails = WalletLNAddr | WalletLND | WalletCLN | WalletLNbits
input AutowithdrawSettings { input AutowithdrawSettings {
autoWithdrawThreshold: Int! autoWithdrawThreshold: Int!
autoWithdrawMaxFeePercent: Float! autoWithdrawMaxFeePercent: Float!

View File

@ -107,6 +107,7 @@ mutation removeWallet($id: ID!) {
} }
` `
// XXX [WALLET] this needs to be updated if another server wallet is added
export const WALLET = gql` export const WALLET = gql`
query Wallet($id: ID!) { query Wallet($id: ID!) {
wallet(id: $id) { wallet(id: $id) {
@ -116,7 +117,7 @@ export const WALLET = gql`
type type
wallet { wallet {
__typename __typename
... on WalletLNAddr { ... on WalletLightningAddress {
address address
} }
... on WalletLND { ... on WalletLND {
@ -138,6 +139,7 @@ export const WALLET = gql`
} }
` `
// XXX [WALLET] this needs to be updated if another server wallet is added
export const WALLET_BY_TYPE = gql` export const WALLET_BY_TYPE = gql`
query WalletByType($type: String!) { query WalletByType($type: String!) {
walletByType(type: $type) { walletByType(type: $type) {
@ -148,7 +150,7 @@ export const WALLET_BY_TYPE = gql`
type type
wallet { wallet {
__typename __typename
... on WalletLNAddr { ... on WalletLightningAddress {
address address
} }
... on WalletLND { ... on WalletLND {

View File

@ -1,4 +1,22 @@
export function fieldToGqlArg (field) {
let arg = `${field.name}: String`
if (!field.optional) {
arg += '!'
}
return arg
}
export function generateResolverName (walletField) { export function generateResolverName (walletField) {
const capitalized = walletField[0].toUpperCase() + walletField.slice(1) const capitalized = walletField[0].toUpperCase() + walletField.slice(1)
return `upsert${capitalized}` return `upsert${capitalized}`
} }
export function generateTypeDefName (walletField) {
return walletField[0].toUpperCase() + walletField.slice(1)
}
export function walletTypeToResolveType (walletType) {
// wallet type is in UPPER_CASE but __resolveType requires PascalCase
const PascalCase = walletType.split('_').map(s => s[0].toUpperCase() + s.slice(1)).join()
return `Wallet${PascalCase}`
}