2025-11-05 04:14:37 +07:00
|
|
|
import { ipcMain, dialog, app } from 'electron'
|
2025-10-31 21:56:47 +07:00
|
|
|
import fs from 'fs'
|
|
|
|
|
import path from 'path'
|
2025-11-05 04:14:37 +07:00
|
|
|
import { encrypt, fromEncryptedJson } from './utils/keystore'
|
2025-10-31 01:22:35 +07:00
|
|
|
|
2025-11-07 18:27:37 +07:00
|
|
|
const neptuneNative = require('@neptune/native')
|
|
|
|
|
|
2025-11-05 04:14:37 +07:00
|
|
|
// Create keystore into default wallets directory
|
2025-10-31 01:22:35 +07:00
|
|
|
ipcMain.handle('wallet:createKeystore', async (_event, seed, password) => {
|
2025-10-31 21:56:47 +07:00
|
|
|
try {
|
2025-11-05 04:14:37 +07:00
|
|
|
const keystore = await encrypt(seed, password)
|
2025-10-31 01:22:35 +07:00
|
|
|
|
2025-10-31 21:56:47 +07:00
|
|
|
const savePath = path.join(process.cwd(), 'wallets')
|
|
|
|
|
fs.mkdirSync(savePath, { recursive: true })
|
2025-10-31 01:22:35 +07:00
|
|
|
|
2025-11-05 04:14:37 +07:00
|
|
|
// Use timestamp for filename
|
|
|
|
|
const timestamp = Date.now()
|
|
|
|
|
const fileName = `neptune-wallet-${timestamp}.json`
|
|
|
|
|
const filePath = path.join(savePath, fileName)
|
2025-10-31 21:56:47 +07:00
|
|
|
fs.writeFileSync(filePath, keystore)
|
2025-10-31 01:22:35 +07:00
|
|
|
|
2025-11-05 04:14:37 +07:00
|
|
|
return { filePath }
|
2025-10-31 21:56:47 +07:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error creating keystore:', error)
|
2025-11-05 04:14:37 +07:00
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// New handler: let user choose folder and filename to save keystore
|
|
|
|
|
ipcMain.handle('wallet:saveKeystoreAs', async (_event, seed: string, password: string) => {
|
|
|
|
|
try {
|
|
|
|
|
const keystore = await encrypt(seed, password)
|
|
|
|
|
|
|
|
|
|
// Use timestamp for default filename
|
|
|
|
|
const timestamp = Date.now()
|
|
|
|
|
const defaultName = `neptune-wallet-${timestamp}.json`
|
|
|
|
|
const { canceled, filePath } = await dialog.showSaveDialog({
|
|
|
|
|
title: 'Save Keystore File',
|
|
|
|
|
defaultPath: path.join(app.getPath('documents'), defaultName),
|
|
|
|
|
filters: [{ name: 'JSON', extensions: ['json'] }],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (canceled || !filePath) return { filePath: null }
|
|
|
|
|
|
|
|
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
|
|
|
|
fs.writeFileSync(filePath, keystore)
|
|
|
|
|
|
|
|
|
|
return { filePath }
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error saving keystore (Save As):', error)
|
|
|
|
|
throw error
|
2025-10-31 21:56:47 +07:00
|
|
|
}
|
|
|
|
|
})
|
2025-10-31 01:22:35 +07:00
|
|
|
|
|
|
|
|
ipcMain.handle('wallet:decryptKeystore', async (_event, filePath, password) => {
|
2025-10-31 21:56:47 +07:00
|
|
|
try {
|
|
|
|
|
const json = fs.readFileSync(filePath, 'utf-8')
|
2025-11-05 04:14:37 +07:00
|
|
|
const phrase = await fromEncryptedJson(json, password)
|
2025-10-31 21:56:47 +07:00
|
|
|
|
2025-11-05 04:14:37 +07:00
|
|
|
return { phrase }
|
2025-10-31 21:56:47 +07:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error decrypting keystore ipc:', error)
|
2025-11-05 04:14:37 +07:00
|
|
|
throw error
|
2025-10-31 21:56:47 +07:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('wallet:checkKeystore', async () => {
|
|
|
|
|
try {
|
|
|
|
|
const walletDir = path.join(process.cwd(), 'wallets')
|
2025-11-05 04:14:37 +07:00
|
|
|
if (!fs.existsSync(walletDir)) return { exists: false, filePath: null }
|
2025-10-31 21:56:47 +07:00
|
|
|
|
2025-11-07 18:27:37 +07:00
|
|
|
const newestFile = fs
|
|
|
|
|
.readdirSync(walletDir)
|
|
|
|
|
.filter((f) => f.endsWith('.json'))
|
|
|
|
|
.sort(
|
|
|
|
|
(a, b) =>
|
|
|
|
|
fs.statSync(path.join(walletDir, b)).mtime.getTime() -
|
|
|
|
|
fs.statSync(path.join(walletDir, a)).mtime.getTime()
|
|
|
|
|
)[0]
|
|
|
|
|
|
|
|
|
|
if (!newestFile) return { exists: false, filePath: null }
|
2025-10-31 21:56:47 +07:00
|
|
|
|
2025-11-07 18:27:37 +07:00
|
|
|
return { exists: true, filePath: path.join(walletDir, newestFile) }
|
2025-10-31 21:56:47 +07:00
|
|
|
} catch (error) {
|
2025-11-07 18:27:37 +07:00
|
|
|
console.error('Error checking keystore ipc:', error)
|
2025-10-31 21:56:47 +07:00
|
|
|
return { exists: false, filePath: null, error: String(error) }
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-11-07 18:27:37 +07:00
|
|
|
|
|
|
|
|
ipcMain.handle('wallet:generateKeysFromSeed', async (_event, seedPhrase: string[]) => {
|
|
|
|
|
try {
|
|
|
|
|
const wallet = new neptuneNative.WalletManager()
|
|
|
|
|
return wallet.generateKeysFromSeed(seedPhrase)
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error generating keys from seed ipc:', error)
|
|
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
ipcMain.handle('wallet:buildTransactionWithPrimitiveProof', async (_event, args) => {
|
|
|
|
|
const { spendingKeyHex, inputAdditionRecords, outputAddresses, outputAmounts, fee } = args
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const builder = new neptuneNative.SimpleTransactionBuilder()
|
|
|
|
|
const result = await builder.buildTransactionWithPrimitiveProof(
|
|
|
|
|
import.meta.env.VITE_APP_API,
|
|
|
|
|
spendingKeyHex,
|
|
|
|
|
inputAdditionRecords,
|
|
|
|
|
outputAddresses,
|
|
|
|
|
outputAmounts,
|
|
|
|
|
fee
|
|
|
|
|
)
|
|
|
|
|
return JSON.parse(result)
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error building transaction with primitive proof ipc:', error)
|
|
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
})
|