global singleton wallet state with single bootstrap in layout
This commit is contained in:
@@ -27,7 +27,7 @@ export const atomicToXmr = (atomic: string): string => {
|
||||
return frac ? `${whole}.${frac}` : `${whole}`
|
||||
}
|
||||
|
||||
export const MoneroWallet = () => {
|
||||
export const createMoneroWallet = () => {
|
||||
let accountType = $state<'monero' | null>(null)
|
||||
let ready = $state(false)
|
||||
let biometricAvailable = $state(false)
|
||||
@@ -105,14 +105,19 @@ export const MoneroWallet = () => {
|
||||
return authed === true
|
||||
}
|
||||
|
||||
let initPromise: Promise<void> | null = null
|
||||
const init = async () => {
|
||||
await checkStatus()
|
||||
if (installed && !running && !downloading) {
|
||||
await start()
|
||||
if (initPromise) return initPromise
|
||||
initPromise = (async () => {
|
||||
await checkStatus()
|
||||
}
|
||||
await checkBiometric()
|
||||
ready = true
|
||||
if (installed && !running && !downloading) {
|
||||
await start()
|
||||
await checkStatus()
|
||||
}
|
||||
await checkBiometric()
|
||||
ready = true
|
||||
})()
|
||||
return initPromise
|
||||
}
|
||||
|
||||
const login = async () => {
|
||||
@@ -671,4 +676,15 @@ export const MoneroWallet = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton: calling MoneroWallet() always returns the same instance, so
|
||||
// no component can ever create a second, disconnected wallet state.
|
||||
type MoneroWalletStore = ReturnType<typeof createMoneroWallet>
|
||||
|
||||
let moneroWalletInstance: MoneroWalletStore | null = null
|
||||
|
||||
export const MoneroWallet = (): MoneroWalletStore => {
|
||||
if (!moneroWalletInstance) moneroWalletInstance = createMoneroWallet()
|
||||
return moneroWalletInstance
|
||||
}
|
||||
|
||||
export const moneroWallet = MoneroWallet()
|
||||
|
||||
@@ -13,7 +13,7 @@ export const xrpNetwork = {
|
||||
explorerAddressUrl: 'https://xrpscan.com/account/',
|
||||
} as const
|
||||
|
||||
export const XrpWallet = () => {
|
||||
export const createXrpWallet = () => {
|
||||
let accountType = $state<'xrp' | null>(null)
|
||||
let ready = $state(false)
|
||||
let biometricAvailable = $state(false)
|
||||
@@ -76,19 +76,24 @@ export const XrpWallet = () => {
|
||||
biometricAvailable = ok === true
|
||||
}
|
||||
|
||||
let initPromise: Promise<void> | null = null
|
||||
const init = async () => {
|
||||
if (!electrobun.rpc) return
|
||||
const [walletList] = await tryCatch(
|
||||
electrobun.rpc.request.xrpListWallets({}),
|
||||
)
|
||||
if (walletList) {
|
||||
wallets = walletList
|
||||
if (walletList.length > 0 && !currentWalletId) {
|
||||
currentWalletId = walletList[0].id
|
||||
if (initPromise) return initPromise
|
||||
initPromise = (async () => {
|
||||
if (!electrobun.rpc) return
|
||||
const [walletList] = await tryCatch(
|
||||
electrobun.rpc.request.xrpListWallets({}),
|
||||
)
|
||||
if (walletList) {
|
||||
wallets = walletList
|
||||
if (walletList.length > 0 && !currentWalletId) {
|
||||
currentWalletId = walletList[0].id
|
||||
}
|
||||
}
|
||||
}
|
||||
await checkBiometric()
|
||||
ready = true
|
||||
await checkBiometric()
|
||||
ready = true
|
||||
})()
|
||||
return initPromise
|
||||
}
|
||||
|
||||
const login = async () => {
|
||||
@@ -480,4 +485,15 @@ export const XrpWallet = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton: calling XrpWallet() always returns the same instance, so no
|
||||
// component can ever create a second, disconnected wallet state.
|
||||
type XrpWalletStore = ReturnType<typeof createXrpWallet>
|
||||
|
||||
let xrpWalletInstance: XrpWalletStore | null = null
|
||||
|
||||
export const XrpWallet = (): XrpWalletStore => {
|
||||
if (!xrpWalletInstance) xrpWalletInstance = createXrpWallet()
|
||||
return xrpWalletInstance
|
||||
}
|
||||
|
||||
export const xrpWallet = XrpWallet()
|
||||
|
||||
@@ -61,8 +61,6 @@
|
||||
|
||||
onMount(() => {
|
||||
frontendLog('dashboard mounted')
|
||||
moneroWallet.init().catch((e) => frontendLogError('moneroWallet.init() failed', e))
|
||||
xrpWallet.init().catch((e) => frontendLogError('xrpWallet.init() failed', e))
|
||||
})
|
||||
|
||||
// Balances live in the stores so they survive navigation; the effects
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
if (!xrpWallet.ready) await xrpWallet.init()
|
||||
if (!moneroWallet.ready) await moneroWallet.init()
|
||||
await Promise.allSettled([
|
||||
xrpWallet.login(),
|
||||
xrpWallet.autoUnlock(),
|
||||
moneroWallet.login(),
|
||||
])
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
let unlocking = $state(false)
|
||||
let unlockError = $state('')
|
||||
|
||||
let initStarted = false
|
||||
|
||||
async function unlockWithPassword() {
|
||||
if (unlocking || !walletPassword.trim()) return
|
||||
unlocking = true
|
||||
@@ -48,16 +46,6 @@
|
||||
}
|
||||
})
|
||||
|
||||
$effect(() => {
|
||||
if (!initStarted) {
|
||||
initStarted = true
|
||||
w.init().then(async () => {
|
||||
if (w.accountType === 'monero') return
|
||||
await w.login()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
$effect(() => {
|
||||
if (w.running && !w.walletOpen && w.wallets.length > 0 && !w.loading && !w.opening) {
|
||||
w.autoUnlock(w.wallets[0])
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
const w = moneroWallet
|
||||
|
||||
let moneroSettingsPw = $state('')
|
||||
|
||||
$effect(() => {
|
||||
w.init()
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="mx-auto max-w-xl">
|
||||
|
||||
@@ -22,18 +22,6 @@
|
||||
let inputUnlockPassword = $state('')
|
||||
let newSeed = $state<string | null>(null)
|
||||
|
||||
let initStarted = false
|
||||
|
||||
$effect(() => {
|
||||
if (!initStarted) {
|
||||
initStarted = true
|
||||
w.init().then(async () => {
|
||||
if (w.accountType === 'xrp') return
|
||||
await w.login()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
$effect(() => {
|
||||
if (w.accountType === 'xrp' && w.currentWalletId && w.seed && !newSeed) {
|
||||
navigate('/xrp/wallet/:id', {
|
||||
|
||||
Reference in New Issue
Block a user