stacker.news/wallets/config.js

158 lines
5.4 KiB
JavaScript
Raw Normal View History

2024-10-23 00:53:56 +00:00
import { useMe } from '@/components/me'
2024-10-23 17:42:34 +00:00
import useVault from '@/components/vault/use-vault'
2024-10-23 00:53:56 +00:00
import { useCallback } from 'react'
2024-10-24 01:12:43 +00:00
import { canReceive, canSend, getStorageKey } from './common'
2024-10-23 00:53:56 +00:00
import { useMutation } from '@apollo/client'
import { generateMutation } from './graphql'
import { REMOVE_WALLET } from '@/fragments/wallet'
import { useWalletLogger } from '@/components/wallet-logger'
2024-10-23 22:17:35 +00:00
import { useWallets } from '.'
2024-10-25 19:10:37 +00:00
import validateWallet from './validate'
2024-10-23 00:53:56 +00:00
export function useWalletConfigurator (wallet) {
const { me } = useMe()
2024-10-23 22:17:35 +00:00
const { reloadLocalWallets } = useWallets()
2024-10-23 00:53:56 +00:00
const { encrypt, isActive } = useVault()
2024-10-23 17:42:34 +00:00
const { logger } = useWalletLogger(wallet?.def)
const [upsertWallet] = useMutation(generateMutation(wallet?.def))
2024-10-23 00:53:56 +00:00
const [removeWallet] = useMutation(REMOVE_WALLET)
2024-10-24 01:12:43 +00:00
const _saveToServer = useCallback(async (serverConfig, clientConfig, validateLightning) => {
const { serverWithShared, settings, clientOnly } = siftConfig(wallet.def.fields, { ...serverConfig, ...clientConfig })
2024-10-23 00:53:56 +00:00
const vaultEntries = []
2024-10-25 19:10:37 +00:00
if (clientOnly && isActive) {
2024-10-24 01:12:43 +00:00
for (const [key, value] of Object.entries(clientOnly)) {
2024-10-25 19:10:37 +00:00
if (value) {
vaultEntries.push({ key, value: encrypt(value) })
}
2024-10-23 00:53:56 +00:00
}
}
2024-10-25 19:10:37 +00:00
2024-10-24 01:12:43 +00:00
await upsertWallet({ variables: { ...serverWithShared, settings, validateLightning, vaultEntries } })
}, [encrypt, isActive, wallet.def.fields])
2024-10-23 00:53:56 +00:00
const _saveToLocal = useCallback(async (newConfig) => {
2024-10-23 22:17:35 +00:00
window.localStorage.setItem(getStorageKey(wallet.def.name, me?.id), JSON.stringify(newConfig))
reloadLocalWallets()
}, [me?.id, wallet.def.name, reloadLocalWallets])
2024-10-23 00:53:56 +00:00
2024-10-24 01:12:43 +00:00
const _validate = useCallback(async (config, validateLightning = true) => {
const { serverWithShared, clientWithShared } = siftConfig(wallet.def.fields, config)
2024-10-23 00:53:56 +00:00
2024-10-24 01:12:43 +00:00
let clientConfig = clientWithShared
let serverConfig = serverWithShared
2024-10-24 20:30:56 +00:00
if (canSend({ def: wallet.def, config: clientConfig })) {
2024-10-25 19:10:37 +00:00
let transformedConfig = await validateWallet(wallet.def, clientWithShared)
2024-10-24 01:12:43 +00:00
if (transformedConfig) {
clientConfig = Object.assign(clientConfig, transformedConfig)
}
if (wallet.def.testSendPayment && validateLightning) {
transformedConfig = await wallet.def.testSendPayment(clientConfig, { me, logger })
2024-10-23 00:53:56 +00:00
if (transformedConfig) {
clientConfig = Object.assign(clientConfig, transformedConfig)
}
}
2024-10-24 20:30:56 +00:00
} else if (canReceive({ def: wallet.def, config: serverConfig })) {
2024-10-25 19:10:37 +00:00
const transformedConfig = await validateWallet(wallet.def, serverConfig)
2024-10-24 01:12:43 +00:00
if (transformedConfig) {
serverConfig = Object.assign(serverConfig, transformedConfig)
2024-10-23 00:53:56 +00:00
}
2024-10-24 20:30:56 +00:00
} else {
throw new Error('configuration must be able to send or receive')
2024-10-23 00:53:56 +00:00
}
2024-10-24 01:12:43 +00:00
return { clientConfig, serverConfig }
}, [wallet])
2024-10-25 19:10:37 +00:00
const _detachFromServer = useCallback(async () => {
await removeWallet({ variables: { id: wallet.config.id } })
}, [wallet.config?.id])
const _detachFromLocal = useCallback(async () => {
window.localStorage.removeItem(getStorageKey(wallet.def.name, me?.id))
reloadLocalWallets()
}, [me?.id, wallet.def.name, reloadLocalWallets])
2024-10-24 01:12:43 +00:00
const save = useCallback(async (newConfig, validateLightning = true) => {
2024-10-24 20:30:56 +00:00
const { clientConfig, serverConfig } = await _validate(newConfig, validateLightning)
2024-10-24 01:12:43 +00:00
2024-10-23 00:53:56 +00:00
// if vault is active, encrypt and send to server regardless of wallet type
if (isActive) {
2024-10-24 01:12:43 +00:00
await _saveToServer(serverConfig, clientConfig, validateLightning)
2024-10-23 00:53:56 +00:00
} else {
2024-10-24 20:30:56 +00:00
if (canSend({ def: wallet.def, config: clientConfig })) {
2024-10-23 00:53:56 +00:00
await _saveToLocal(clientConfig)
2024-10-25 19:10:37 +00:00
} else {
// if it previously had a client config, remove it
await _detachFromLocal()
2024-10-23 00:53:56 +00:00
}
2024-10-24 20:30:56 +00:00
if (canReceive({ def: wallet.def, config: serverConfig })) {
2024-10-24 01:12:43 +00:00
await _saveToServer(serverConfig, clientConfig, validateLightning)
2024-10-25 19:10:37 +00:00
} else {
// if it previously had a server config, remove it
await _detachFromServer()
2024-10-23 00:53:56 +00:00
}
}
2024-10-25 19:10:37 +00:00
}, [isActive, _saveToServer, _saveToLocal, _validate, _detachFromLocal, _detachFromServer])
2024-10-23 00:53:56 +00:00
const detach = useCallback(async () => {
if (isActive) {
2024-10-24 20:30:56 +00:00
// if vault is active, detach all wallets from server
2024-10-23 00:53:56 +00:00
await _detachFromServer()
} else {
if (wallet.config.id) {
await _detachFromServer()
}
2024-10-24 20:30:56 +00:00
// if vault is not active and has a client config, delete from local storage
2024-10-23 00:53:56 +00:00
await _detachFromLocal()
}
}, [isActive, _detachFromServer, _detachFromLocal])
2024-10-23 22:17:35 +00:00
return { save, detach }
2024-10-23 00:53:56 +00:00
}
2024-10-24 01:12:43 +00:00
function siftConfig (fields, config) {
const sifted = {
clientOnly: {},
serverOnly: {},
shared: {},
serverWithShared: {},
clientWithShared: {},
settings: {}
}
for (const [key, value] of Object.entries(config)) {
if (['id'].includes(key)) {
sifted.serverOnly[key] = value
continue
}
if (['autoWithdrawMaxFeePercent', 'autoWithdrawThreshold', 'autoWithdrawMaxFeeTotal'].includes(key)) {
sifted.serverOnly[key] = value
sifted.settings[key] = value
continue
}
2024-10-23 00:53:56 +00:00
2024-10-24 01:12:43 +00:00
const field = fields.find(({ name }) => name === key)
2024-10-23 00:53:56 +00:00
2024-10-24 01:12:43 +00:00
if (field) {
if (field.serverOnly) {
sifted.serverOnly[key] = value
} else if (field.clientOnly) {
sifted.clientOnly[key] = value
} else {
sifted.shared[key] = value
2024-10-23 00:53:56 +00:00
}
} else {
2024-10-24 01:12:43 +00:00
sifted.shared[key] = value
2024-10-23 00:53:56 +00:00
}
2024-10-24 01:12:43 +00:00
}
2024-10-23 00:53:56 +00:00
2024-10-24 01:12:43 +00:00
sifted.serverWithShared = { ...sifted.shared, ...sifted.serverOnly }
sifted.clientWithShared = { ...sifted.shared, ...sifted.clientOnly }
2024-10-23 00:53:56 +00:00
2024-10-24 01:12:43 +00:00
return sifted
2024-10-23 00:53:56 +00:00
}