import { computed } from 'vue' import { useNeptuneStore } from '@/stores/neptuneStore' import * as API from '@/api/neptuneApi' import type { GenerateSeedResult, ViewKeyResult } from '@/interface' import initWasm, { generate_seed, get_viewkey, address_from_seed, validate_seed_phrase, decode_viewkey, } from '@neptune/wasm' let wasmInitialized = false let initPromise: Promise | null = null export function useNeptuneWallet() { const store = useNeptuneStore() // ===== WASM METHODS ===== const ensureWasmInitialized = async (): Promise => { if (wasmInitialized) { return } if (initPromise) { return initPromise } initPromise = (async () => { try { store.setLoading(true) store.setError(null) await initWasm() wasmInitialized = true } catch (err) { wasmInitialized = false const errorMsg = 'Failed to initialize Neptune WASM' store.setError(errorMsg) console.error('WASM init error:', err) throw new Error(errorMsg) } finally { store.setLoading(false) } })() return initPromise } const generateWallet = async (): Promise => { try { store.setLoading(true) store.setError(null) await ensureWasmInitialized() const resultJson = generate_seed() const result: GenerateSeedResult = JSON.parse(resultJson) store.setSeedPhrase(result.seed_phrase) store.setReceiverId(result.receiver_identifier) const viewKeyResult = await getViewKeyFromSeed(result.seed_phrase, store.getNetwork) store.setViewKey(viewKeyResult.view_key) store.setAddress(viewKeyResult.address) return result } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Failed to generate wallet' store.setError(errorMsg) throw err } finally { store.setLoading(false) } } const getViewKeyFromSeed = async ( seedPhrase: string[], network: 'mainnet' | 'testnet' ): Promise => { await ensureWasmInitialized() const seedPhraseJson = JSON.stringify(seedPhrase) const resultJson = get_viewkey(seedPhraseJson, network) return JSON.parse(resultJson) } const importWallet = async ( seedPhrase: string[], network: 'mainnet' | 'testnet' = 'testnet' ): Promise => { try { store.setLoading(true) store.setError(null) const isValid = await validateSeedPhrase(seedPhrase) if (!isValid) { throw new Error('Invalid seed phrase') } const result = await getViewKeyFromSeed(seedPhrase, network) store.setSeedPhrase(seedPhrase) store.setReceiverId(result.receiver_identifier) store.setViewKey(result.view_key) store.setAddress(result.address) store.setNetwork(network) return result } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Failed to import wallet' store.setError(errorMsg) throw err } finally { store.setLoading(false) } } const getAddressFromSeed = async ( seedPhrase: string[], network: 'mainnet' | 'testnet' ): Promise => { await ensureWasmInitialized() const seedPhraseJson = JSON.stringify(seedPhrase) return address_from_seed(seedPhraseJson, network) } const validateSeedPhrase = async (seedPhrase: string[]): Promise => { try { await ensureWasmInitialized() const seedPhraseJson = JSON.stringify(seedPhrase) return validate_seed_phrase(seedPhraseJson) } catch (err) { console.error('Validation error:', err) return false } } const decodeViewKey = async (viewKeyHex: string): Promise<{ receiver_identifier: string }> => { await ensureWasmInitialized() const resultJson = decode_viewkey(viewKeyHex) return JSON.parse(resultJson) } const importFromViewKey = async (viewKeyHex: string): Promise<{ receiver_identifier: string }> => { try { store.setLoading(true) store.setError(null) const result = await decodeViewKey(viewKeyHex) store.setViewKey(viewKeyHex) store.setReceiverId(result.receiver_identifier) // Note: When importing from viewkey, we don't have the seed phrase // and address needs to be derived from viewkey return result } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Failed to import from view key' store.setError(errorMsg) throw err } finally { store.setLoading(false) } } // ===== API METHODS ===== const getUtxos = async ( startBlock: number = 0, endBlock: number | null = null, maxSearchDepth: number = 1000 ): Promise => { try { if (!store.getViewKey) { throw new Error('No view key available. Please import or generate a wallet first.') } store.setLoading(true) store.setError(null) const response = await API.getUtxosFromViewKey( store.getViewKey, startBlock, endBlock, maxSearchDepth ) const result = response.data?.result || response.data store.setUtxos(result.utxos || result || []) return result } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Failed to get UTXOs' store.setError(errorMsg) throw err } finally { store.setLoading(false) } } const getBalance = async (): Promise => { try { store.setLoading(true) store.setError(null) const response = await API.getBalance() const result = response.data?.result || response.data store.setBalance(result.balance || result) return result } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Failed to get balance' store.setError(errorMsg) throw err } finally { store.setLoading(false) } } const getBlockHeight = async (): Promise => { try { store.setLoading(true) store.setError(null) const response = await API.getBlockHeight() const result = response.data?.result || response.data return result.height || result } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Failed to get block height' store.setError(errorMsg) throw err } finally { store.setLoading(false) } } const getNetworkInfo = async (): Promise => { try { store.setLoading(true) store.setError(null) const response = await API.getNetworkInfo() const result = response.data?.result || response.data return result } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Failed to get network info' store.setError(errorMsg) throw err } finally { store.setLoading(false) } } const sendTransaction = async ( toAddress: string, amount: string, fee: string ): Promise => { try { store.setLoading(true) store.setError(null) const response = await API.sendTransaction(toAddress, amount, fee) const result = response.data?.result || response.data return result } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Failed to send transaction' store.setError(errorMsg) throw err } finally { store.setLoading(false) } } const setNetwork = async (network: 'mainnet' | 'testnet') => { store.setNetwork(network) if (store.getSeedPhrase) { const viewKeyResult = await getViewKeyFromSeed(store.getSeedPhrase, network) store.setAddress(viewKeyResult.address) store.setViewKey(viewKeyResult.view_key) } } // ===== UTILITY METHODS ===== const clearWallet = () => { store.clearWallet() } return { walletState: computed(() => store.getWallet), isLoading: computed(() => store.getLoading), error: computed(() => store.getError), hasWallet: computed(() => store.hasWallet), initWasm: ensureWasmInitialized, generateWallet, importWallet, importFromViewKey, getViewKeyFromSeed, getAddressFromSeed, validateSeedPhrase, decodeViewKey, getUtxos, getBalance, getBlockHeight, getNetworkInfo, sendTransaction, clearWallet, setNetwork, } }