- Remove Ethereum/Web3 references from HTML - Create PaperclipWallets class with Ed25519 key support - Add PaperclipDatabase for wallet storage - Update module loading order in index.html - Convert button classes from btn-etho to btn-clips
296 lines
7.2 KiB
JavaScript
296 lines
7.2 KiB
JavaScript
const storage = require('electron-storage');
|
|
const path = require('path');
|
|
|
|
class PaperclipDatabase {
|
|
constructor() {
|
|
this.walletFile = 'paperclip-wallets.json';
|
|
this.settingsFile = 'paperclip-settings.json';
|
|
}
|
|
|
|
// Wallet operations
|
|
getWallets() {
|
|
try {
|
|
const data = storage.getSync(this.walletFile);
|
|
return data || { addresses: [], names: {}, keys: {} };
|
|
} catch (error) {
|
|
return { addresses: [], names: {}, keys: {} };
|
|
}
|
|
}
|
|
|
|
saveWallet(wallet) {
|
|
try {
|
|
const wallets = this.getWallets();
|
|
|
|
// Add address if not exists
|
|
if (!wallets.addresses.includes(wallet.address)) {
|
|
wallets.addresses.push(wallet.address);
|
|
}
|
|
|
|
// Save wallet data
|
|
wallets.names[wallet.address] = wallet.name;
|
|
wallets.keys[wallet.address] = {
|
|
publicKey: wallet.publicKey,
|
|
privateKey: wallet.privateKey, // TODO: Encrypt with password
|
|
created: wallet.created
|
|
};
|
|
|
|
storage.setSync(this.walletFile, wallets);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to save wallet:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
getWallet(address) {
|
|
try {
|
|
const wallets = this.getWallets();
|
|
|
|
if (!wallets.addresses.includes(address)) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
address: address,
|
|
name: wallets.names[address] || 'Account',
|
|
publicKey: wallets.keys[address]?.publicKey,
|
|
privateKey: wallets.keys[address]?.privateKey,
|
|
created: wallets.keys[address]?.created
|
|
};
|
|
} catch (error) {
|
|
console.error('Failed to get wallet:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
removeWallet(address) {
|
|
try {
|
|
const wallets = this.getWallets();
|
|
|
|
// Remove from addresses array
|
|
const index = wallets.addresses.indexOf(address);
|
|
if (index > -1) {
|
|
wallets.addresses.splice(index, 1);
|
|
}
|
|
|
|
// Remove wallet data
|
|
delete wallets.names[address];
|
|
delete wallets.keys[address];
|
|
|
|
storage.setSync(this.walletFile, wallets);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to remove wallet:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
updateWalletName(address, newName) {
|
|
try {
|
|
const wallets = this.getWallets();
|
|
|
|
if (wallets.addresses.includes(address)) {
|
|
wallets.names[address] = newName;
|
|
storage.setSync(this.walletFile, wallets);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
} catch (error) {
|
|
console.error('Failed to update wallet name:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Address book operations
|
|
getAddressBook() {
|
|
try {
|
|
const data = storage.getSync('address-book.json');
|
|
return data || [];
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
saveAddressBookEntry(entry) {
|
|
try {
|
|
const addressBook = this.getAddressBook();
|
|
|
|
// Check if address already exists
|
|
const existingIndex = addressBook.findIndex(item => item.address === entry.address);
|
|
|
|
if (existingIndex > -1) {
|
|
// Update existing entry
|
|
addressBook[existingIndex] = entry;
|
|
} else {
|
|
// Add new entry
|
|
addressBook.push(entry);
|
|
}
|
|
|
|
storage.setSync('address-book.json', addressBook);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to save address book entry:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
removeAddressBookEntry(address) {
|
|
try {
|
|
const addressBook = this.getAddressBook();
|
|
const filtered = addressBook.filter(item => item.address !== address);
|
|
|
|
storage.setSync('address-book.json', filtered);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to remove address book entry:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Settings operations
|
|
getSettings() {
|
|
try {
|
|
const data = storage.getSync(this.settingsFile);
|
|
return data || {
|
|
rpcUrl: 'http://localhost:26657',
|
|
autoConnect: true,
|
|
notifications: true
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
rpcUrl: 'http://localhost:26657',
|
|
autoConnect: true,
|
|
notifications: true
|
|
};
|
|
}
|
|
}
|
|
|
|
saveSetting(key, value) {
|
|
try {
|
|
const settings = this.getSettings();
|
|
settings[key] = value;
|
|
storage.setSync(this.settingsFile, settings);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to save setting:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
saveSettings(settingsObj) {
|
|
try {
|
|
storage.setSync(this.settingsFile, settingsObj);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to save settings:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Transaction history (local cache)
|
|
getTransactionHistory(address) {
|
|
try {
|
|
const data = storage.getSync(`tx-history-${address}.json`);
|
|
return data || [];
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
saveTransaction(address, transaction) {
|
|
try {
|
|
const history = this.getTransactionHistory(address);
|
|
|
|
// Check if transaction already exists
|
|
const exists = history.some(tx => tx.hash === transaction.hash);
|
|
|
|
if (!exists) {
|
|
history.unshift(transaction); // Add to beginning
|
|
|
|
// Keep only last 100 transactions
|
|
if (history.length > 100) {
|
|
history.splice(100);
|
|
}
|
|
|
|
storage.setSync(`tx-history-${address}.json`, history);
|
|
}
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to save transaction:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Utility methods
|
|
clearAllData() {
|
|
try {
|
|
storage.removeSync(this.walletFile);
|
|
storage.removeSync(this.settingsFile);
|
|
storage.removeSync('address-book.json');
|
|
|
|
// Clear transaction histories
|
|
const wallets = this.getWallets();
|
|
wallets.addresses.forEach(address => {
|
|
try {
|
|
storage.removeSync(`tx-history-${address}.json`);
|
|
} catch (e) {
|
|
// Ignore errors for non-existent files
|
|
}
|
|
});
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to clear data:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
exportWallets() {
|
|
try {
|
|
const wallets = this.getWallets();
|
|
const settings = this.getSettings();
|
|
const addressBook = this.getAddressBook();
|
|
|
|
return {
|
|
wallets: wallets,
|
|
settings: settings,
|
|
addressBook: addressBook,
|
|
exportDate: new Date().toISOString()
|
|
};
|
|
} catch (error) {
|
|
console.error('Failed to export data:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
importWallets(data) {
|
|
try {
|
|
if (data.wallets) {
|
|
storage.setSync(this.walletFile, data.wallets);
|
|
}
|
|
|
|
if (data.settings) {
|
|
storage.setSync(this.settingsFile, data.settings);
|
|
}
|
|
|
|
if (data.addressBook) {
|
|
storage.setSync('address-book.json', data.addressBook);
|
|
}
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to import data:', error);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create global instance
|
|
const PaperclipDatabase = new PaperclipDatabase();
|
|
|
|
// Make it available globally
|
|
window.PaperclipDatabase = PaperclipDatabase;
|
|
|
|
module.exports = PaperclipDatabase; |