Files
paperclip-wallet/renderer/paperclip-wallets.js
matt 1ceb56c7b8 Update wallet UI to use PaperclipChain
- 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
2025-06-15 18:39:48 -07:00

271 lines
6.8 KiB
JavaScript

const {ipcRenderer} = require("electron");
class PaperclipWallets {
constructor() {
this.addressList = [];
this.price = 0;
}
_getPrice() {
return this.price;
}
_setPrice(price) {
this.price = price;
}
getAddressList() {
return this.addressList;
}
clearAddressList() {
this.addressList = [];
}
getAddressExists(address) {
if (address) {
return this.addressList.indexOf(address) > -1;
}
return false;
}
addAddressToList(address) {
if (address) {
this.addressList.push(address);
}
}
async createNewWallet(password) {
try {
const ClipsCrypto = require('../modules/clips-crypto.js');
const keyPair = ClipsCrypto.generateKeyPair();
// Store wallet in database
const wallet = {
address: keyPair.address,
publicKey: keyPair.publicKey,
privateKey: keyPair.privateKey, // In production, encrypt this with password
name: `Account ${this.addressList.length + 1}`,
created: Date.now()
};
PaperclipDatabase.saveWallet(wallet);
this.addAddressToList(keyPair.address);
return wallet;
} catch (error) {
throw new Error(`Failed to create wallet: ${error.message}`);
}
}
async importFromPrivateKey(privateKeyHex, password) {
try {
const ClipsCrypto = require('../modules/clips-crypto.js');
const keyPair = ClipsCrypto.importPrivateKey(privateKeyHex);
const wallet = {
address: keyPair.address,
publicKey: keyPair.publicKey,
privateKey: keyPair.privateKey,
name: `Imported Account`,
created: Date.now()
};
PaperclipDatabase.saveWallet(wallet);
this.addAddressToList(keyPair.address);
return wallet;
} catch (error) {
throw new Error(`Failed to import wallet: ${error.message}`);
}
}
async sendTransaction(fromAddress, toAddress, amount, password) {
try {
// Get wallet data
const wallet = PaperclipDatabase.getWallet(fromAddress);
if (!wallet) {
throw new Error("Wallet not found");
}
// Validate address format
const ClipsCrypto = require('../modules/clips-crypto.js');
if (!ClipsCrypto.isValidAddress(toAddress)) {
throw new Error("Invalid recipient address");
}
// Get current nonce
const nonce = await ipcRenderer.invoke("paperclip-get-nonce", fromAddress);
// Create and sign transaction
const transaction = ClipsCrypto.createTransaction({
sender: fromAddress,
receiver: toAddress,
amount: parseInt(amount),
nonce: nonce,
type: 'transfer',
data: '',
privateKey: wallet.privateKey
});
// Broadcast transaction
const result = await ipcRenderer.invoke("paperclip-broadcast-tx",
ClipsCrypto.transactionToHex(transaction));
if (result.success) {
return {
hash: result.hash,
height: result.height
};
} else {
throw new Error(result.error || "Transaction failed");
}
} catch (error) {
throw new Error(`Transaction failed: ${error.message}`);
}
}
async getWalletBalance(address) {
try {
const balance = await ipcRenderer.invoke("paperclip-get-balance", address);
return balance;
} catch (error) {
console.error(`Failed to get balance for ${address}:`, error);
return 0;
}
}
async refreshWalletData() {
try {
this.clearAddressList();
const wallets = PaperclipDatabase.getWallets();
if (!wallets || !wallets.addresses) {
return {
sumBalance: 0,
addressData: [],
sumBalanceFormatted: "0 CLIPS"
};
}
const data = {
sumBalance: 0,
addressData: []
};
// Get balance for each wallet
for (const address of wallets.addresses) {
const wallet = PaperclipDatabase.getWallet(address);
const balance = await this.getWalletBalance(address);
data.addressData.push({
address: address,
name: wallet ? wallet.name : `Account`,
balance: balance,
balanceFormatted: this.formatBalance(balance)
});
data.sumBalance += balance;
this.addAddressToList(address);
}
data.sumBalanceFormatted = this.formatBalance(data.sumBalance);
return data;
} catch (error) {
throw new Error(`Failed to refresh wallet data: ${error.message}`);
}
}
formatBalance(balance) {
if (balance === 0) {
return "0 CLIPS";
}
if (balance >= 1000000) {
return (balance / 1000000).toFixed(2) + "M CLIPS";
} else if (balance >= 1000) {
return (balance / 1000).toFixed(2) + "K CLIPS";
} else {
return balance.toLocaleString() + " CLIPS";
}
}
validateAddress(address) {
const ClipsCrypto = require('../modules/clips-crypto.js');
return ClipsCrypto.isValidAddress(address);
}
validateAmount(amount) {
const num = parseFloat(amount);
return !isNaN(num) && num > 0;
}
// UI Event Handlers
async handleCreateNewWallet() {
const password = $("#walletPasswordFirst").val();
if (!password) {
throw new Error("Password cannot be empty");
}
if (password !== $("#walletPasswordSecond").val()) {
throw new Error("Passwords do not match");
}
return await this.createNewWallet(password);
}
async handleImportPrivateKey() {
const privateKey = $("#inputPrivateKey").val();
const password = $("#keyPasswordFirst").val();
if (!privateKey) {
throw new Error("Private key cannot be empty");
}
if (!password) {
throw new Error("Password cannot be empty");
}
if (password !== $("#keyPasswordSecond").val()) {
throw new Error("Passwords do not match");
}
return await this.importFromPrivateKey(privateKey, password);
}
async handleSendTransaction() {
const fromAddress = $("#sendFromAddress").val();
const toAddress = $("#sendToAddress").val();
const amount = $("#sendAmount").val();
const password = $("#sendPassword").val();
if (!fromAddress) {
throw new Error("From address is required");
}
if (!toAddress) {
throw new Error("To address is required");
}
if (!this.validateAddress(toAddress)) {
throw new Error("Invalid recipient address format");
}
if (!this.validateAmount(amount)) {
throw new Error("Invalid amount");
}
if (!password) {
throw new Error("Password is required");
}
return await this.sendTransaction(fromAddress, toAddress, amount, password);
}
}
// Create global instance
const ClipsWallet = new PaperclipWallets();
// Make it available globally
window.ClipsWallet = ClipsWallet;