diff --git a/electron/ipcHandlers.ts b/electron/ipcHandlers.ts index 3f17a12..1fb2ed4 100644 --- a/electron/ipcHandlers.ts +++ b/electron/ipcHandlers.ts @@ -78,12 +78,90 @@ ipcMain.handle('wallet:checkKeystore', async () => { fs.statSync(path.join(walletDir, a)).mtime.getTime() )[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) { 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 try { const builder = new neptuneNative.SimpleTransactionBuilder() - const result = await builder.buildTransactionWithPrimitiveProof( + const result = await builder.buildTransaction( import.meta.env.VITE_APP_API, spendingKeyHex, inputAdditionRecords, + typeof args?.minBlockHeight === 'number' && Number.isFinite(args.minBlockHeight) + ? args.minBlockHeight + : 0, outputAddresses, outputAmounts, fee diff --git a/electron/preload.ts b/electron/preload.ts index 4b791e0..817977c 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -12,6 +12,9 @@ contextBridge.exposeInMainWorld('walletApi', { checkKeystore: () => ipcRenderer.invoke('wallet:checkKeystore'), generateKeysFromSeed: (seedPhrase: string[]) => ipcRenderer.invoke('wallet:generateKeysFromSeed', seedPhrase), - buildTransactionWithPrimitiveProof: (args: any) => - ipcRenderer.invoke('wallet:buildTransactionWithPrimitiveProof', args), + buildTransaction: (args: any) => ipcRenderer.invoke('wallet:buildTransaction', args), + updateMinBlockHeight: (filePath: string | null, minBlockHeight: number | null) => + ipcRenderer.invoke('wallet:updateMinBlockHeight', filePath, minBlockHeight), + getMinBlockHeight: (filePath: string | null) => + ipcRenderer.invoke('wallet:getMinBlockHeight', filePath), }) diff --git a/electron/utils/keystore.ts b/electron/utils/keystore.ts index ec17d98..aef9d3e 100644 --- a/electron/utils/keystore.ts +++ b/electron/utils/keystore.ts @@ -4,7 +4,6 @@ export async function encrypt(seed: string, password: string) { const salt = crypto.randomBytes(16) const iv = crypto.randomBytes(12) - // derive 32-byte key từ password const key = await new Promise((resolve, reject) => { crypto.scrypt(password, salt, 32, { N: 16384, r: 8, p: 1 }, (err, derivedKey) => { if (err) reject(err) diff --git a/packages/neptune-native-0.1.0.tgz b/packages/neptune-native-0.1.0.tgz deleted file mode 100644 index 7089c75..0000000 Binary files a/packages/neptune-native-0.1.0.tgz and /dev/null differ diff --git a/packages/neptune-native/index.d.ts b/packages/neptune-native/index.d.ts index a5d663b..c59ff10 100644 --- a/packages/neptune-native/index.d.ts +++ b/packages/neptune-native/index.d.ts @@ -3,12 +3,9 @@ /* auto-generated by NAPI-RS */ -/** Module initialization */ export declare function initNativeModule(): string -/** Quick VM test (can call immediately) */ export declare function quickVmTest(): string export declare function getVersion(): string -/** Wallet manager for key generation and transaction signing */ export declare class WalletManager { constructor() /** @@ -64,7 +61,7 @@ export declare class WalletManager { getStateCall(rpcUrl: string): Promise /** Call mempool_submitTransaction to broadcast a pre-built transaction */ submitTransactionCall(rpcUrl: string, transactionHex: string): Promise - getUtxosFromViewKeyCall(rpcUrl: string, viewKeyHex: string, startBlock: number, endBlock: number, maxSearchDepth?: number | undefined | null): Promise + getUtxosFromViewKeyCall(rpcUrl: string, viewKeyHex: string, startBlock: number, maxSearchDepth?: number | undefined | null): Promise getArchivalMutatorSet(rpcUrl: string): Promise /** * 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 { constructor() - buildTransactionWithPrimitiveProof(rpcUrl: string, spendingKeyHex: string, inputAdditionRecords: Array, outputAddresses: Array, outputAmounts: Array, fee: string): Promise + buildTransaction(rpcUrl: string, spendingKeyHex: string, inputAdditionRecords: Array, minBlockHeight: number, outputAddresses: Array, outputAmounts: Array, fee: string): Promise } diff --git a/packages/neptune-native/neptune-native.darwin-arm64.node b/packages/neptune-native/neptune-native.darwin-arm64.node index f561130..46809d2 100755 Binary files a/packages/neptune-native/neptune-native.darwin-arm64.node and b/packages/neptune-native/neptune-native.darwin-arm64.node differ diff --git a/packages/neptune-native/neptune-native.win32-x64-msvc.node b/packages/neptune-native/neptune-native.win32-x64-msvc.node index 2ec83cf..c6188c4 100644 Binary files a/packages/neptune-native/neptune-native.win32-x64-msvc.node and b/packages/neptune-native/neptune-native.win32-x64-msvc.node differ diff --git a/src/App.vue b/src/App.vue index a06885c..66a2a72 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,6 +1,4 @@