Skip to content

Commit

Permalink
Generate more server wallet code (#1309)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ekzyis authored Aug 18, 2024
1 parent d2d04ce commit 3d8ae4a
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 49 deletions.
14 changes: 10 additions & 4 deletions api/resolvers/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import assertApiKeyNotPermitted from './apiKey'
import { bolt11Tags } from '@/lib/bolt11'
import { finalizeHodlInvoice } from 'worker/wallet'
import walletDefs from 'wallets/server'
import { generateResolverName } from '@/lib/wallet'
import { generateResolverName, walletTypeToResolveType } from '@/lib/wallet'
import { lnAddrOptions } from '@/lib/lnurl'

function injectResolvers (resolvers) {
Expand Down Expand Up @@ -349,11 +349,17 @@ const resolvers = {
})
}
},
WalletDetails: {
__resolveType (wallet) {
return wallet.address ? 'WalletLNAddr' : wallet.macaroon ? 'WalletLND' : wallet.rune ? 'WalletCLN' : 'WalletLNbits'
Wallet: {
wallet: async (wallet) => {
return {
...wallet.wallet,
__resolveType: walletTypeToResolveType(wallet.type)
}
}
},
WalletDetails: {
__resolveType: wallet => wallet.__resolveType
},
Mutation: {
createInvoice: async (parent, { amount, hodlInvoice = false, expireSecs = 3600 }, { me, models, lnd, headers }) => {
await ssValidate(amountSchema, { amount })
Expand Down
90 changes: 47 additions & 43 deletions api/typeDefs/wallet.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,59 @@
import { gql } from 'graphql-tag'
import { generateResolverName } from '@/lib/wallet'
import { fieldToGqlArg, generateResolverName, generateTypeDefName } from '@/lib/wallet'

import walletDefs from 'wallets/server'
import { isServerField } from 'wallets'

function injectTypeDefs (typeDefs) {
const injected = [rawTypeDefs(), mutationTypeDefs()]
return `${typeDefs}\n\n${injected.join('\n\n')}\n`
}

function mutationTypeDefs () {
console.group('injected GraphQL mutations:')

const typeDefs = walletDefs.map((w) => {
let args = 'id: ID, '
args += w.fields
.filter(isServerField)
.map(fieldToGqlArg).join(', ')
args += ', settings: AutowithdrawSettings!'
const resolverName = generateResolverName(w.walletField)
const typeDef = `${resolverName}(${args}): Boolean`
console.log(typeDef)
return typeDef
})

console.groupEnd()

return `extend type Mutation {\n${typeDefs.join('\n')}\n}`
}

function rawTypeDefs () {
console.group('injected GraphQL type defs:')
const injected = walletDefs.map(
(w) => {
let args = 'id: ID, '
args += w.fields
.filter(isServerField)
.map(f => {
let arg = `${f.name}: String`
if (!f.optional) {
arg += '!'
}
return arg
}).join(', ')
args += ', settings: AutowithdrawSettings!'
const resolverName = generateResolverName(w.walletField)
const typeDef = `${resolverName}(${args}): Boolean`
console.log(typeDef)
return typeDef
})

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}\n\nextend type Mutation {\n${injected.join('\n')}\n}`
return typeDefs.join('\n\n') + union
}

const typeDefs = `
Expand Down Expand Up @@ -61,29 +88,6 @@ const typeDefs = `
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 {
autoWithdrawThreshold: Int!
autoWithdrawMaxFeePercent: Float!
Expand Down
6 changes: 4 additions & 2 deletions fragments/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -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`
query Wallet($id: ID!) {
wallet(id: $id) {
Expand All @@ -116,7 +117,7 @@ export const WALLET = gql`
type
wallet {
__typename
... on WalletLNAddr {
... on WalletLightningAddress {
address
}
... on WalletLND {
Expand All @@ -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`
query WalletByType($type: String!) {
walletByType(type: $type) {
Expand All @@ -148,7 +150,7 @@ export const WALLET_BY_TYPE = gql`
type
wallet {
__typename
... on WalletLNAddr {
... on WalletLightningAddress {
address
}
... on WalletLND {
Expand Down
18 changes: 18 additions & 0 deletions lib/wallet.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
export function fieldToGqlArg (field) {
let arg = `${field.name}: String`
if (!field.optional) {
arg += '!'
}
return arg
}

export function generateResolverName (walletField) {
const capitalized = walletField[0].toUpperCase() + walletField.slice(1)
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}`
}

0 comments on commit 3d8ae4a

Please sign in to comment.