optimize scan UTXO

This commit is contained in:
draplydo 2025-11-10 15:50:35 +07:00 committed by NguyenAnhQuan
parent 6998ea5982
commit d3c20789e9
30 changed files with 219 additions and 59 deletions

View File

@ -78,12 +78,90 @@ ipcMain.handle('wallet:checkKeystore', async () => {
fs.statSync(path.join(walletDir, a)).mtime.getTime() fs.statSync(path.join(walletDir, a)).mtime.getTime()
)[0] )[0]
if (!newestFile) return { exists: false, filePath: null } if (!newestFile?.length) return { exists: false, filePath: null }
return { exists: true, filePath: path.join(walletDir, newestFile) } const resolvedPath = path.join(walletDir, newestFile)
let minBlockHeight: number | null = null
try {
const json = fs.readFileSync(resolvedPath, 'utf-8')
const data = JSON.parse(json)
const height = data?.minBlockHeight
if (Number.isFinite(height)) minBlockHeight = height
} catch (error) {
console.warn('Unable to read minBlockHeight from keystore:', error)
return { exists: true, filePath: resolvedPath }
}
return { exists: true, filePath: resolvedPath, minBlockHeight }
} catch (error) { } catch (error) {
console.error('Error checking keystore ipc:', error) console.error('Error checking keystore ipc:', error)
return { exists: false, filePath: null, error: String(error) } return { exists: false, filePath: null, minBlockHeight: null, error: String(error) }
}
})
ipcMain.handle(
'wallet:updateMinBlockHeight',
async (_event, filePath: string | null, minBlockHeight: number | null) => {
if (!filePath) {
return { success: false, error: 'No keystore file path provided.' }
}
try {
const normalizedPath = path.isAbsolute(filePath)
? filePath
: path.join(process.cwd(), filePath)
if (!fs.existsSync(normalizedPath)) {
return { success: false, error: 'Keystore file not found.' }
}
const fileContents = fs.readFileSync(normalizedPath, 'utf-8')
const walletJson = JSON.parse(fileContents)
if (minBlockHeight === null || Number.isNaN(minBlockHeight)) {
walletJson.minBlockHeight = null
} else {
walletJson.minBlockHeight = minBlockHeight
}
fs.writeFileSync(normalizedPath, JSON.stringify(walletJson, null, 2), 'utf-8')
return { success: true, minBlockHeight }
} catch (error) {
console.error('Error updating min block height:', error)
return { success: false, error: String(error) }
}
}
)
ipcMain.handle('wallet:getMinBlockHeight', async (_event, filePath: string | null) => {
if (!filePath) {
return { success: false, error: 'No keystore file path provided.', minBlockHeight: null }
}
try {
const normalizedPath = path.isAbsolute(filePath)
? filePath
: path.join(process.cwd(), filePath)
if (!fs.existsSync(normalizedPath)) {
return { success: false, error: 'Keystore file not found.', minBlockHeight: null }
}
const fileContents = fs.readFileSync(normalizedPath, 'utf-8')
const walletJson = JSON.parse(fileContents)
const height = walletJson?.minBlockHeight
if (Number.isFinite(height)) {
return { success: true, minBlockHeight: height }
}
return { success: true, minBlockHeight: null }
} catch (error) {
console.error('Error reading min block height:', error)
return { success: false, error: String(error), minBlockHeight: null }
} }
}) })
@ -97,15 +175,18 @@ ipcMain.handle('wallet:generateKeysFromSeed', async (_event, seedPhrase: string[
} }
}) })
ipcMain.handle('wallet:buildTransactionWithPrimitiveProof', async (_event, args) => { ipcMain.handle('wallet:buildTransaction', async (_event, args) => {
const { spendingKeyHex, inputAdditionRecords, outputAddresses, outputAmounts, fee } = args const { spendingKeyHex, inputAdditionRecords, outputAddresses, outputAmounts, fee } = args
try { try {
const builder = new neptuneNative.SimpleTransactionBuilder() const builder = new neptuneNative.SimpleTransactionBuilder()
const result = await builder.buildTransactionWithPrimitiveProof( const result = await builder.buildTransaction(
import.meta.env.VITE_APP_API, import.meta.env.VITE_APP_API,
spendingKeyHex, spendingKeyHex,
inputAdditionRecords, inputAdditionRecords,
typeof args?.minBlockHeight === 'number' && Number.isFinite(args.minBlockHeight)
? args.minBlockHeight
: 0,
outputAddresses, outputAddresses,
outputAmounts, outputAmounts,
fee fee

View File

@ -12,6 +12,9 @@ contextBridge.exposeInMainWorld('walletApi', {
checkKeystore: () => ipcRenderer.invoke('wallet:checkKeystore'), checkKeystore: () => ipcRenderer.invoke('wallet:checkKeystore'),
generateKeysFromSeed: (seedPhrase: string[]) => generateKeysFromSeed: (seedPhrase: string[]) =>
ipcRenderer.invoke('wallet:generateKeysFromSeed', seedPhrase), ipcRenderer.invoke('wallet:generateKeysFromSeed', seedPhrase),
buildTransactionWithPrimitiveProof: (args: any) => buildTransaction: (args: any) => ipcRenderer.invoke('wallet:buildTransaction', args),
ipcRenderer.invoke('wallet:buildTransactionWithPrimitiveProof', args), updateMinBlockHeight: (filePath: string | null, minBlockHeight: number | null) =>
ipcRenderer.invoke('wallet:updateMinBlockHeight', filePath, minBlockHeight),
getMinBlockHeight: (filePath: string | null) =>
ipcRenderer.invoke('wallet:getMinBlockHeight', filePath),
}) })

View File

@ -4,7 +4,6 @@ export async function encrypt(seed: string, password: string) {
const salt = crypto.randomBytes(16) const salt = crypto.randomBytes(16)
const iv = crypto.randomBytes(12) const iv = crypto.randomBytes(12)
// derive 32-byte key từ password
const key = await new Promise<Buffer>((resolve, reject) => { const key = await new Promise<Buffer>((resolve, reject) => {
crypto.scrypt(password, salt, 32, { N: 16384, r: 8, p: 1 }, (err, derivedKey) => { crypto.scrypt(password, salt, 32, { N: 16384, r: 8, p: 1 }, (err, derivedKey) => {
if (err) reject(err) if (err) reject(err)

Binary file not shown.

View File

@ -3,12 +3,9 @@
/* auto-generated by NAPI-RS */ /* auto-generated by NAPI-RS */
/** Module initialization */
export declare function initNativeModule(): string export declare function initNativeModule(): string
/** Quick VM test (can call immediately) */
export declare function quickVmTest(): string export declare function quickVmTest(): string
export declare function getVersion(): string export declare function getVersion(): string
/** Wallet manager for key generation and transaction signing */
export declare class WalletManager { export declare class WalletManager {
constructor() constructor()
/** /**
@ -64,7 +61,7 @@ export declare class WalletManager {
getStateCall(rpcUrl: string): Promise<string> getStateCall(rpcUrl: string): Promise<string>
/** Call mempool_submitTransaction to broadcast a pre-built transaction */ /** Call mempool_submitTransaction to broadcast a pre-built transaction */
submitTransactionCall(rpcUrl: string, transactionHex: string): Promise<string> submitTransactionCall(rpcUrl: string, transactionHex: string): Promise<string>
getUtxosFromViewKeyCall(rpcUrl: string, viewKeyHex: string, startBlock: number, endBlock: number, maxSearchDepth?: number | undefined | null): Promise<string> getUtxosFromViewKeyCall(rpcUrl: string, viewKeyHex: string, startBlock: number, maxSearchDepth?: number | undefined | null): Promise<string>
getArchivalMutatorSet(rpcUrl: string): Promise<string> getArchivalMutatorSet(rpcUrl: string): Promise<string>
/** /**
* Build JSON-RPC request to find the canonical block that created a UTXO (by addition_record) * Build JSON-RPC request to find the canonical block that created a UTXO (by addition_record)
@ -78,5 +75,5 @@ export declare class WalletManager {
} }
export declare class SimpleTransactionBuilder { export declare class SimpleTransactionBuilder {
constructor() constructor()
buildTransactionWithPrimitiveProof(rpcUrl: string, spendingKeyHex: string, inputAdditionRecords: Array<string>, outputAddresses: Array<string>, outputAmounts: Array<string>, fee: string): Promise<string> buildTransaction(rpcUrl: string, spendingKeyHex: string, inputAdditionRecords: Array<string>, minBlockHeight: number, outputAddresses: Array<string>, outputAmounts: Array<string>, fee: string): Promise<string>
} }

View File

@ -1,6 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { LayoutVue } from '@/components'
const config = { const config = {
token: { token: {
colorPrimary: '#42A5F5', colorPrimary: '#42A5F5',

View File

@ -2,7 +2,7 @@ import { callJsonRpc } from '@/api/request'
export const getUtxosFromViewKey = async ( export const getUtxosFromViewKey = async (
viewKey: string, viewKey: string,
startBlock: number = 0, startBlock: number | null = 0,
endBlock: number | null = null, endBlock: number | null = null,
maxSearchDepth: number = 1000 maxSearchDepth: number = 1000
): Promise<any> => { ): Promise<any> => {
@ -17,7 +17,7 @@ export const getUtxosFromViewKey = async (
export const getBalance = async ( export const getBalance = async (
viewKey: string, viewKey: string,
startBlock: number = 0, startBlock: number | null = 0,
endBlock: number | null = null, endBlock: number | null = null,
maxSearchDepth: number = 1000 maxSearchDepth: number = 1000
): Promise<any> => { ): Promise<any> => {

View File

@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ButtonProps } from '@/interface' import type { ButtonProps } from '@/interface'
import { computed } from 'vue' import { computed } from 'vue'
import { SpinnerCommon } from '@/components'
const props = withDefaults(defineProps<ButtonProps>(), { const props = withDefaults(defineProps<ButtonProps>(), {
type: 'default', type: 'default',

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { ButtonCommon, CardBase, FormCommon } from '@/components'
interface Props { interface Props {
title?: string title?: string

View File

@ -7,6 +7,7 @@ import type {
WalletState, WalletState,
} from '@/interface' } from '@/interface'
import initWasm, { generate_seed, address_from_seed, validate_seed_phrase } from '@neptune/wasm' import initWasm, { generate_seed, address_from_seed, validate_seed_phrase } from '@neptune/wasm'
import { toFiniteNumber } from '@/utils'
let wasmInitialized = false let wasmInitialized = false
let initPromise: Promise<void> | null = null let initPromise: Promise<void> | null = null
@ -125,6 +126,8 @@ export function useNeptuneWallet() {
const addressResult = await getAddressFromSeed(seedPhrase) const addressResult = await getAddressFromSeed(seedPhrase)
store.setAddress(addressResult) store.setAddress(addressResult)
await loadMinBlockHeightFromKeystore()
} catch (err) { } catch (err) {
if ( if (
err instanceof Error && err instanceof Error &&
@ -142,6 +145,7 @@ export function useNeptuneWallet() {
try { try {
const result = await (window as any).walletApi.createKeystore(seed, password) const result = await (window as any).walletApi.createKeystore(seed, password)
store.setKeystorePath(result.filePath) store.setKeystorePath(result.filePath)
store.setMinBlockHeight(null)
return result.filePath return result.filePath
} catch (err) { } catch (err) {
console.error('Error creating keystore:', err) console.error('Error creating keystore:', err)
@ -166,6 +170,10 @@ export function useNeptuneWallet() {
if (!keystoreFile.exists) return false if (!keystoreFile.exists) return false
store.setKeystorePath(keystoreFile.filePath) store.setKeystorePath(keystoreFile.filePath)
if ('minBlockHeight' in keystoreFile) {
const height = keystoreFile.minBlockHeight
store.setMinBlockHeight(toFiniteNumber(height))
}
return true return true
} catch (err) { } catch (err) {
console.error('Error checking keystore:', err) console.error('Error checking keystore:', err)
@ -173,18 +181,73 @@ export function useNeptuneWallet() {
} }
} }
// ===== API METHODS ===== const persistMinBlockHeight = async (utxos: any[]) => {
const keystorePath = store.getKeystorePath
if (!keystorePath) return
try {
const minBlockHeight = utxos.reduce((min, utxo) => {
const h = +(
utxo?.blockHeight ??
utxo?.block_height ??
utxo?.height ??
utxo?.block?.height
)
return Number.isFinite(h) && (min === null || h < min) ? h : min
}, null)
const response = await (window as any).walletApi.updateMinBlockHeight(
keystorePath,
minBlockHeight
)
if (!response.success) throw new Error('Failed to update min block height')
store.setMinBlockHeight(minBlockHeight)
} catch (err) {
console.error('Error saving min block height:', err)
throw err
}
}
const loadMinBlockHeightFromKeystore = async (): Promise<number | null> => {
const keystorePath = store.getKeystorePath
if (!keystorePath) return null
try {
const response = await (window as any).walletApi.getMinBlockHeight(keystorePath)
if (!response?.success) return null
const minBlockHeight = toFiniteNumber(response.minBlockHeight)
store.setMinBlockHeight(minBlockHeight)
return minBlockHeight
} catch (err) {
console.error('Error loading min block height:', err)
throw err
}
}
// ===== API METHODS =====
const getUtxos = async (): Promise<any> => { const getUtxos = async (): Promise<any> => {
try { try {
if (!store.getViewKey) { if (!store.getViewKey) {
throw new Error('No view key available. Please import or generate a wallet first.') throw new Error('No view key available. Please import or generate a wallet first.')
} }
const response = await API.getUtxosFromViewKey(store.getViewKey || '') let startBlock: number | null = store.getMinBlockHeight
if (startBlock == null) startBlock = await loadMinBlockHeightFromKeystore()
const response = await API.getUtxosFromViewKey(
store.getViewKey || '',
toFiniteNumber(startBlock, 0)
)
const result = response?.result || response const result = response?.result || response
store.setUtxos(result.utxos || result || []) const utxos = result?.utxos ?? result
const utxoList = Array.isArray(utxos) ? utxos : []
store.setUtxos(utxoList)
await persistMinBlockHeight(utxoList)
return result return result
} catch (err) { } catch (err) {
console.error('Error getting UTXOs:', err) console.error('Error getting UTXOs:', err)
@ -194,8 +257,18 @@ export function useNeptuneWallet() {
const getBalance = async (): Promise<any> => { const getBalance = async (): Promise<any> => {
try { try {
const response = await API.getBalance(store.getViewKey || '') let startBlock: number | null | undefined = store.getMinBlockHeight
if (startBlock === null || startBlock === undefined) {
startBlock = await loadMinBlockHeightFromKeystore()
}
const response = await API.getBalance(
store.getViewKey || '',
toFiniteNumber(startBlock, 0)
)
const result = response?.result || response const result = response?.result || response
store.setBalance(result?.balance || result) store.setBalance(result?.balance || result)
store.setPendingBalance(result?.pendingBalance || result) store.setPendingBalance(result?.pendingBalance || result)
return { return {
@ -232,17 +305,21 @@ export function useNeptuneWallet() {
} }
} }
const buildTransactionWithPrimitiveProof = async ( const buildTransaction = async (args: PayloadBuildTransaction): Promise<any> => {
args: PayloadBuildTransaction let minBlockHeight: number | null | undefined = store.getMinBlockHeight
): Promise<any> => { if (minBlockHeight === null || minBlockHeight === undefined) {
minBlockHeight = await loadMinBlockHeightFromKeystore()
}
const payload = { const payload = {
spendingKeyHex: store.getSpendingKey, spendingKeyHex: store.getSpendingKey,
inputAdditionRecords: args.inputAdditionRecords, inputAdditionRecords: args.inputAdditionRecords,
minBlockHeight: toFiniteNumber(minBlockHeight, 0),
outputAddresses: args.outputAddresses, outputAddresses: args.outputAddresses,
outputAmounts: args.outputAmounts, outputAmounts: args.outputAmounts,
fee: args.fee, fee: args.fee,
} }
return await (window as any).walletApi.buildTransactionWithPrimitiveProof(payload) return await (window as any).walletApi.buildTransaction(payload)
} }
const broadcastSignedTransaction = async (transactionHex: string): Promise<any> => { const broadcastSignedTransaction = async (transactionHex: string): Promise<any> => {
@ -290,7 +367,7 @@ export function useNeptuneWallet() {
getBalance, getBalance,
getBlockHeight, getBlockHeight,
getNetworkInfo, getNetworkInfo,
buildTransactionWithPrimitiveProof, buildTransaction,
broadcastSignedTransaction, broadcastSignedTransaction,
decryptKeystore, decryptKeystore,
createKeystore, createKeystore,

View File

@ -9,6 +9,7 @@ export interface WalletState {
balance?: string | null balance?: string | null
pendingBalance?: string | null pendingBalance?: string | null
utxos?: Utxo[] utxos?: Utxo[]
minBlockHeight?: number | null
} }
export interface GenerateSeedResult { export interface GenerateSeedResult {

View File

@ -1,6 +1,7 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import type { WalletState } from '@/interface' import type { WalletState } from '@/interface'
import { toFiniteNumber } from '@/utils'
export const useNeptuneStore = defineStore('neptune', () => { export const useNeptuneStore = defineStore('neptune', () => {
const defaultNetwork = (import.meta.env.VITE_NODE_NETWORK || 'mainnet') as 'mainnet' | 'testnet' const defaultNetwork = (import.meta.env.VITE_NODE_NETWORK || 'mainnet') as 'mainnet' | 'testnet'
@ -17,6 +18,7 @@ export const useNeptuneStore = defineStore('neptune', () => {
balance: null, balance: null,
pendingBalance: null, pendingBalance: null,
utxos: [], utxos: [],
minBlockHeight: null,
}) })
const keystorePath = ref<null | string>(null) const keystorePath = ref<null | string>(null)
@ -63,6 +65,10 @@ export const useNeptuneStore = defineStore('neptune', () => {
wallet.value.utxos = utxos wallet.value.utxos = utxos
} }
const setMinBlockHeight = (minBlockHeight: number | null) => {
wallet.value.minBlockHeight = toFiniteNumber(minBlockHeight)
}
const setWallet = (walletData: Partial<WalletState>) => { const setWallet = (walletData: Partial<WalletState>) => {
wallet.value = { ...wallet.value, ...walletData } wallet.value = { ...wallet.value, ...walletData }
} }
@ -83,6 +89,7 @@ export const useNeptuneStore = defineStore('neptune', () => {
balance: null, balance: null,
pendingBalance: null, pendingBalance: null,
utxos: [], utxos: [],
minBlockHeight: null,
} }
} }
@ -99,6 +106,7 @@ export const useNeptuneStore = defineStore('neptune', () => {
const getBalance = computed(() => wallet.value.balance) const getBalance = computed(() => wallet.value.balance)
const getPendingBalance = computed(() => wallet.value.pendingBalance) const getPendingBalance = computed(() => wallet.value.pendingBalance)
const getUtxos = computed(() => wallet.value.utxos) const getUtxos = computed(() => wallet.value.utxos)
const getMinBlockHeight = computed(() => wallet.value.minBlockHeight ?? null)
const hasWallet = computed(() => wallet.value.address !== null) const hasWallet = computed(() => wallet.value.address !== null)
const getKeystorePath = computed(() => keystorePath.value) const getKeystorePath = computed(() => keystorePath.value)
return { return {
@ -114,6 +122,7 @@ export const useNeptuneStore = defineStore('neptune', () => {
getBalance, getBalance,
getPendingBalance, getPendingBalance,
getUtxos, getUtxos,
getMinBlockHeight,
hasWallet, hasWallet,
getKeystorePath, getKeystorePath,
setSeedPhrase, setSeedPhrase,
@ -126,6 +135,7 @@ export const useNeptuneStore = defineStore('neptune', () => {
setBalance, setBalance,
setPendingBalance, setPendingBalance,
setUtxos, setUtxos,
setMinBlockHeight,
setWallet, setWallet,
setKeystorePath, setKeystorePath,
clearWallet, clearWallet,

View File

@ -0,0 +1,3 @@
export function toFiniteNumber(value: number | null, defaultValue?: number): number | null {
return Number.isFinite(value) ? value : (defaultValue ?? null)
}

View File

@ -2,3 +2,4 @@ export * from './constants/code'
export * from './constants/constants' export * from './constants/constants'
export * from './helpers/format' export * from './helpers/format'
export * from './helpers/seedPhrase' export * from './helpers/seedPhrase'
export * from './helpers/helpers'

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import { PasswordForm } from '@/components'
import { useNeptuneWallet } from '@/composables/useNeptuneWallet' import { useNeptuneWallet } from '@/composables/useNeptuneWallet'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/authStore' import { useAuthStore } from '@/stores/authStore'

View File

@ -1,6 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { ButtonCommon } from '@/components'
const emit = defineEmits<{ const emit = defineEmits<{
goToCreate: [] goToCreate: []
goToRecover: [] goToRecover: []

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
import { ButtonCommon } from '@/components'
import { useNeptuneStore } from '@/stores/neptuneStore' import { useNeptuneStore } from '@/stores/neptuneStore'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, computed } from 'vue' import { ref, onMounted, computed } from 'vue'
import { ButtonCommon } from '@/components'
import { useNeptuneStore } from '@/stores/neptuneStore' import { useNeptuneStore } from '@/stores/neptuneStore'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { ButtonCommon, FormCommon } from '@/components'
import { useNeptuneStore } from '@/stores' import { useNeptuneStore } from '@/stores'
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -4,7 +4,6 @@ import { SeedPhraseDisplayComponent, ConfirmSeedComponent } from '..'
import { CreatePasswordStep, WalletCreatedStep } from '.' import { CreatePasswordStep, WalletCreatedStep } from '.'
import { useNeptuneWallet } from '@/composables/useNeptuneWallet' import { useNeptuneWallet } from '@/composables/useNeptuneWallet'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { CardBaseScrollable } from '@/components'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { ButtonCommon } from '@/components'
import { useNeptuneStore } from '@/stores/neptuneStore' import { useNeptuneStore } from '@/stores/neptuneStore'
import { useNeptuneWallet } from '@/composables/useNeptuneWallet' import { useNeptuneWallet } from '@/composables/useNeptuneWallet'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import { ButtonCommon, PasswordForm } from '@/components'
import { RecoverSeedComponent } from '..' import { RecoverSeedComponent } from '..'
import { useNeptuneWallet } from '@/composables/useNeptuneWallet' import { useNeptuneWallet } from '@/composables/useNeptuneWallet'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
import { TabsCommon, TabPaneCommon } from '@/components'
import { WalletTab, NetworkTab, UTXOTab } from './components' import { WalletTab, NetworkTab, UTXOTab } from './components'
import { useNeptuneWallet } from '@/composables/useNeptuneWallet' import { useNeptuneWallet } from '@/composables/useNeptuneWallet'

View File

@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue' import { ref, computed, onMounted, onUnmounted } from 'vue'
import { formatNumberToLocaleString } from '@/utils' import { formatNumberToLocaleString } from '@/utils'
import { CardBase, SpinnerCommon } from '@/components'
import { useNeptuneStore } from '@/stores/neptuneStore' import { useNeptuneStore } from '@/stores/neptuneStore'
import { useNeptuneWallet } from '@/composables/useNeptuneWallet' import { useNeptuneWallet } from '@/composables/useNeptuneWallet'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'

View File

@ -1,24 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted, inject, watch, type ComputedRef } from 'vue'
import { Table, message } from 'ant-design-vue' import { Table, message } from 'ant-design-vue'
import { useNeptuneWallet } from '@/composables/useNeptuneWallet' import { useNeptuneWallet } from '@/composables/useNeptuneWallet'
import { useNeptuneStore } from '@/stores/neptuneStore' import { useNeptuneStore } from '@/stores/neptuneStore'
import { CardBaseScrollable, SpinnerCommon } from '@/components'
import { columns } from '../utils' import { columns } from '../utils'
const { getUtxos } = useNeptuneWallet() const { getUtxos } = useNeptuneWallet()
const neptuneStore = useNeptuneStore() const neptuneStore = useNeptuneStore()
const activeTabKey = inject<ComputedRef<string>>('activeTabKey')
const loading = ref(false) const loading = ref(false)
const utxosList = computed(() => [ const utxosList = computed(() => [
...(neptuneStore.getUtxos || []), ...(neptuneStore.getUtxos || []),
...Array.from({ length: 18 }, (_, i) => ({
additionRecord: `additionRecord${i}`,
amount: `${i}.00000000`,
blockHeight: `blockHeight${i}`,
utxoHash: `utxoHash${i}`,
})),
]) ])
const inUseUtxosCount = computed(() => (utxosList.value?.length ? utxosList.value.length : 0)) const inUseUtxosCount = computed(() => (utxosList.value?.length ? utxosList.value.length : 0))
@ -55,6 +49,13 @@ const loadUtxos = async () => {
onMounted(() => { onMounted(() => {
loadUtxos() loadUtxos()
}) })
watch(
() => activeTabKey?.value,
(newTab) => {
if (newTab === 'UTXOs') loadUtxos()
}
)
</script> </script>
<template> <template>

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { ButtonCommon, ModalCommon } from '@/components'
interface Props { interface Props {
isLoading?: boolean isLoading?: boolean

View File

@ -27,7 +27,9 @@ const props = defineProps<Props>()
<style lang="scss" scoped> <style lang="scss" scoped>
.balance-section { .balance-section {
text-align: center; display: flex;
flex-direction: column;
align-items: center;
margin-bottom: var(--spacing-xl); margin-bottom: var(--spacing-xl);
padding-bottom: var(--spacing-lg); padding-bottom: var(--spacing-lg);
border-bottom: 2px solid var(--border-color); border-bottom: 2px solid var(--border-color);

View File

@ -1,15 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue' import { ref, computed, onMounted, onUnmounted, inject, watch, type ComputedRef } from 'vue'
import { useNeptuneStore } from '@/stores/neptuneStore' import { useNeptuneStore } from '@/stores/neptuneStore'
import { useNeptuneWallet } from '@/composables/useNeptuneWallet' import { useNeptuneWallet } from '@/composables/useNeptuneWallet'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import {
ButtonCommon,
CardBaseScrollable,
ModalCommon,
SpinnerCommon,
PasswordForm,
} from '@/components'
import SeedPhraseDisplayComponent from '@/views/Auth/components/SeedPhraseDisplayComponent.vue' import SeedPhraseDisplayComponent from '@/views/Auth/components/SeedPhraseDisplayComponent.vue'
import SendTransactionComponent from './SendTransactionComponent.vue' import SendTransactionComponent from './SendTransactionComponent.vue'
import { WalletAddress, WalletBalance } from '.' import { WalletAddress, WalletBalance } from '.'
@ -19,10 +12,11 @@ const neptuneStore = useNeptuneStore()
const { const {
getBalance, getBalance,
saveKeystoreAs, saveKeystoreAs,
buildTransactionWithPrimitiveProof, buildTransaction,
broadcastSignedTransaction, broadcastSignedTransaction,
decryptKeystore, decryptKeystore,
} = useNeptuneWallet() } = useNeptuneWallet()
const activeTabKey = inject<ComputedRef<string>>('activeTabKey')
const availableBalance = ref<string>('0.00000000') const availableBalance = ref<string>('0.00000000')
const pendingBalance = ref<string>('0.00000000') const pendingBalance = ref<string>('0.00000000')
@ -78,7 +72,7 @@ const handleSendTransaction = async (data: {
fee: data.fee, fee: data.fee,
} }
const result = await buildTransactionWithPrimitiveProof(payload) const result = await buildTransaction(payload)
if (!result.success) { if (!result.success) {
message.error('Failed to build transaction') message.error('Failed to build transaction')
return return
@ -172,6 +166,13 @@ onMounted(() => {
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', handleResize) window.removeEventListener('resize', handleResize)
}) })
watch(
() => activeTabKey?.value,
(newTab) => {
if (newTab === 'WALLET') loadWalletData()
}
)
</script> </script>
<template> <template>