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-23 22:17:35 +00:00
|
|
|
import { canReceive, canSend, getStorageKey, isClientField, isServerField } 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 { walletValidate } from '@/lib/validate'
|
|
|
|
import { useWalletLogger } from '@/components/wallet-logger'
|
2024-10-23 22:17:35 +00:00
|
|
|
import { useWallets } from '.'
|
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)
|
|
|
|
|
|
|
|
const _saveToServer = useCallback(async (serverConfig, clientConfig) => {
|
|
|
|
const vaultEntries = []
|
|
|
|
if (clientConfig) {
|
|
|
|
for (const [key, value] of Object.entries(clientConfig)) {
|
|
|
|
vaultEntries.push({ key, value: encrypt(value) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
await upsertWallet({ variables: { ...serverConfig, vaultEntries } })
|
|
|
|
}, [encrypt, isActive])
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
const save = useCallback(async (newConfig, validate = true) => {
|
|
|
|
let clientConfig = extractClientConfig(wallet.def.fields, newConfig)
|
|
|
|
let serverConfig = extractServerConfig(wallet.def.fields, newConfig)
|
|
|
|
|
|
|
|
if (validate) {
|
2024-10-23 22:17:35 +00:00
|
|
|
if (canSend(wallet)) {
|
2024-10-23 00:53:56 +00:00
|
|
|
let transformedConfig = await walletValidate(wallet, clientConfig)
|
|
|
|
if (transformedConfig) {
|
|
|
|
clientConfig = Object.assign(clientConfig, transformedConfig)
|
|
|
|
}
|
2024-10-23 22:17:35 +00:00
|
|
|
if (wallet.def.testSendPayment) {
|
|
|
|
transformedConfig = await wallet.def.testSendPayment(clientConfig, { me, logger })
|
|
|
|
if (transformedConfig) {
|
|
|
|
clientConfig = Object.assign(clientConfig, transformedConfig)
|
|
|
|
}
|
2024-10-23 00:53:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-23 22:17:35 +00:00
|
|
|
if (canReceive(wallet)) {
|
2024-10-23 00:53:56 +00:00
|
|
|
const transformedConfig = await walletValidate(wallet, serverConfig)
|
|
|
|
if (transformedConfig) {
|
|
|
|
serverConfig = Object.assign(serverConfig, transformedConfig)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if vault is active, encrypt and send to server regardless of wallet type
|
|
|
|
if (isActive) {
|
|
|
|
await _saveToServer(serverConfig, clientConfig)
|
|
|
|
} else {
|
2024-10-23 22:17:35 +00:00
|
|
|
if (canSend(wallet)) {
|
2024-10-23 00:53:56 +00:00
|
|
|
await _saveToLocal(clientConfig)
|
|
|
|
}
|
2024-10-23 22:17:35 +00:00
|
|
|
if (canReceive(wallet)) {
|
2024-10-23 00:53:56 +00:00
|
|
|
await _saveToServer(serverConfig)
|
|
|
|
}
|
|
|
|
}
|
2024-10-23 22:17:35 +00:00
|
|
|
}, [wallet, encrypt, isActive])
|
2024-10-23 00:53:56 +00:00
|
|
|
|
|
|
|
const _detachFromServer = useCallback(async () => {
|
|
|
|
await removeWallet({ variables: { id: wallet.config.id } })
|
|
|
|
}, [wallet.config.id])
|
|
|
|
|
|
|
|
const _detachFromLocal = useCallback(async () => {
|
|
|
|
// if vault is not active and has a client config, delete from local storage
|
2024-10-23 22:17:35 +00:00
|
|
|
window.localStorage.removeItem(getStorageKey(wallet.def.name, me?.id))
|
|
|
|
}, [me?.id, wallet.def.name])
|
2024-10-23 00:53:56 +00:00
|
|
|
|
|
|
|
const detach = useCallback(async () => {
|
|
|
|
if (isActive) {
|
|
|
|
await _detachFromServer()
|
|
|
|
} else {
|
|
|
|
if (wallet.config.id) {
|
|
|
|
await _detachFromServer()
|
|
|
|
}
|
|
|
|
|
|
|
|
await _detachFromLocal()
|
|
|
|
}
|
|
|
|
}, [isActive, _detachFromServer, _detachFromLocal])
|
|
|
|
|
2024-10-23 22:17:35 +00:00
|
|
|
return { save, detach }
|
2024-10-23 00:53:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function extractConfig (fields, config, client, includeMeta = true) {
|
|
|
|
return Object.entries(config).reduce((acc, [key, value]) => {
|
|
|
|
const field = fields.find(({ name }) => name === key)
|
|
|
|
|
|
|
|
// filter server config which isn't specified as wallet fields
|
|
|
|
// (we allow autowithdraw members to pass validation)
|
|
|
|
if (client && key === 'id') return acc
|
|
|
|
|
|
|
|
// field might not exist because config.enabled doesn't map to a wallet field
|
|
|
|
if ((!field && includeMeta) || (field && (client ? isClientField(field) : isServerField(field)))) {
|
|
|
|
return {
|
|
|
|
...acc,
|
|
|
|
[key]: value
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return acc
|
|
|
|
}
|
|
|
|
}, {})
|
|
|
|
}
|
|
|
|
|
|
|
|
function extractClientConfig (fields, config) {
|
2024-10-23 22:17:35 +00:00
|
|
|
return extractConfig(fields, config, true, true)
|
2024-10-23 00:53:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function extractServerConfig (fields, config) {
|
|
|
|
return extractConfig(fields, config, false, true)
|
|
|
|
}
|