global singleton wallet state with single bootstrap in layout

This commit is contained in:
2026-08-02 18:59:31 +08:00
parent 20f29faa80
commit 7b4ba84fee
7 changed files with 52 additions and 49 deletions
@@ -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()