import * as Bip39 from '@voltaire/crypto/Bip39';
import * as HDWallet from '@voltaire/crypto/HDWallet';
import * as Secp256k1 from '@voltaire/crypto/Secp256k1';
import { Address } from '@voltaire/primitives/Address';
class Wallet {
private root: ReturnType<typeof HDWallet.fromSeed>;
private constructor(root: ReturnType<typeof HDWallet.fromSeed>) {
this.root = root;
}
static async create(): Promise<Wallet> {
const mnemonic = Bip39.generateMnemonic(256);
const seed = await Bip39.mnemonicToSeed(mnemonic);
console.log('BACKUP YOUR MNEMONIC:', mnemonic);
return new Wallet(HDWallet.fromSeed(seed));
}
static async fromMnemonic(mnemonic: string, passphrase = ''): Promise<Wallet> {
if (!Bip39.validateMnemonic(mnemonic)) {
throw new Error('Invalid mnemonic');
}
const seed = await Bip39.mnemonicToSeed(mnemonic, passphrase);
return new Wallet(HDWallet.fromSeed(seed));
}
static fromExtendedKey(xprv: string): Wallet {
return new Wallet(HDWallet.fromExtendedKey(xprv));
}
getAccount(accountIndex: number, addressIndex: number = 0) {
const key = HDWallet.deriveEthereum(this.root, accountIndex, addressIndex);
const privateKey = HDWallet.getPrivateKey(key)!;
const publicKey = Secp256k1.derivePublicKey(privateKey);
const address = Address.fromPublicKey(publicKey);
return {
path: `m/44'/60'/${accountIndex}'/0/${addressIndex}`,
privateKey,
publicKey,
address: address.toHex()
};
}
getAccounts(count: number, accountIndex: number = 0) {
return Array.from({ length: count }, (_, i) =>
this.getAccount(accountIndex, i)
);
}
exportExtendedPrivateKey(): string {
return HDWallet.toExtendedPrivateKey(this.root);
}
exportExtendedPublicKey(): string {
return HDWallet.toExtendedPublicKey(this.root);
}
}
// Usage
const wallet = await Wallet.create();
const account = wallet.getAccount(0, 0);
console.log('Address:', account.address);
// Restore from mnemonic
const restored = await Wallet.fromMnemonic(
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
);
console.log('Restored:', restored.getAccount(0, 0).address);