@btc-vision/transaction
Version:
OPNet transaction library allows you to create and sign transactions for the OPNet network.
168 lines • 7.41 kB
JavaScript
import * as bip39 from 'bip39';
import { BIP32Factory, MLDSASecurityLevel, QuantumBIP32Factory, } from '@btc-vision/bip32';
import { networks, toHex } from '@btc-vision/bitcoin';
import { backend } from '../ecc/backend.js';
import { Wallet } from '../keypair/Wallet.js';
import { MnemonicStrength } from './MnemonicStrength.js';
import { BIPStandard, buildBIPPath } from './BIPStandard.js';
import { AddressTypes } from '../keypair/AddressVerificator.js';
const bip32 = BIP32Factory(backend);
export { BIPStandard, getBIPDescription } from './BIPStandard.js';
/**
* Mnemonic class for managing BIP39 mnemonic phrases with BIP360 quantum support
*/
export class Mnemonic {
_phrase;
_passphrase;
_network;
_securityLevel;
_seed;
_classicalRoot;
_quantumRoot;
constructor(phrase, passphrase = '', network = networks.bitcoin, securityLevel = MLDSASecurityLevel.LEVEL2) {
if (!bip39.validateMnemonic(phrase)) {
throw new Error('Invalid mnemonic phrase');
}
this._phrase = phrase;
this._passphrase = passphrase;
this._network = network;
this._securityLevel = securityLevel;
// Derive the seed from the mnemonic
this._seed = bip39.mnemonicToSeedSync(this._phrase, this._passphrase);
// Create the classical BIP32 root
this._classicalRoot = bip32.fromSeed(this._seed, this._network);
// Create the quantum BIP32 root with network parameter
this._quantumRoot = QuantumBIP32Factory.fromSeed(this._seed, this._network, this._securityLevel);
}
get phrase() {
return this._phrase;
}
get network() {
return this._network;
}
get securityLevel() {
return this._securityLevel;
}
get seed() {
return new Uint8Array(this._seed);
}
static generatePhrase(strength = MnemonicStrength.MAXIMUM) {
return bip39.generateMnemonic(strength);
}
static generate(strength = MnemonicStrength.MAXIMUM, passphrase = '', network = networks.bitcoin, securityLevel = MLDSASecurityLevel.LEVEL2) {
const phrase = bip39.generateMnemonic(strength);
return new Mnemonic(phrase, passphrase, network, securityLevel);
}
static validate(phrase) {
return bip39.validateMnemonic(phrase);
}
/**
* Best-effort zeroing of secret material held by this mnemonic.
*
* Zeros the seed buffer and root private keys in-place.
* The mnemonic phrase and passphrase are JS strings and cannot be zeroed.
*/
zeroize() {
this._seed.fill(0);
this._classicalRoot.privateKey?.fill(0);
this._quantumRoot.privateKey?.fill(0);
}
[Symbol.dispose]() {
this.zeroize();
}
derive(index = 0, account = 0, isChange = false, bipStandard = BIPStandard.BIP84) {
const classicalPath = this.buildClassicalPath(account, index, isChange, bipStandard);
const classicalChild = this._classicalRoot.derivePath(classicalPath);
if (!classicalChild.privateKey) {
throw new Error(`Failed to derive classical private key at index ${index}`);
}
const quantumPath = this.buildQuantumPath(account, index, isChange);
const quantumChild = this._quantumRoot.derivePath(quantumPath);
if (!quantumChild.privateKey) {
throw new Error(`Failed to derive quantum private key at index ${index}`);
}
return new Wallet(toHex(new Uint8Array(classicalChild.privateKey)), toHex(new Uint8Array(quantumChild.privateKey)), this._network, this._securityLevel, new Uint8Array(this._quantumRoot.chainCode));
}
deriveOPWallet(addressType = AddressTypes.P2TR, index = 0, account = 0, isChange = false) {
let purpose;
switch (addressType) {
case AddressTypes.P2PKH:
purpose = 44;
break;
case AddressTypes.P2SH_OR_P2SH_P2WPKH:
purpose = 49;
break;
case AddressTypes.P2WPKH:
purpose = 84;
break;
case AddressTypes.P2TR:
purpose = 86;
break;
default:
throw new Error(`Unsupported address type: ${addressType}`);
}
const coinType = this.getCoinType();
const change = isChange ? 1 : 0;
const classicalPath = `m/${purpose}'/0'/${account}'/${change}/${index}`;
const classicalChild = this._classicalRoot.derivePath(classicalPath);
if (!classicalChild.privateKey) {
throw new Error(`Failed to derive classical private key at path ${classicalPath}`);
}
const quantumPath = `m/360'/${coinType}'/${account}'/${change}/${index}`;
const quantumChild = this._quantumRoot.derivePath(quantumPath);
if (!quantumChild.privateKey) {
throw new Error(`Failed to derive quantum private key at path ${quantumPath}`);
}
return new Wallet(toHex(new Uint8Array(classicalChild.privateKey)), toHex(new Uint8Array(quantumChild.privateKey)), this._network, this._securityLevel, new Uint8Array(this._quantumRoot.chainCode));
}
deriveMultipleOPWallet(addressType = AddressTypes.P2TR, count = 5, startIndex = 0, account = 0, isChange = false) {
const wallets = [];
for (let i = 0; i < count; i++) {
wallets.push(this.deriveOPWallet(addressType, startIndex + i, account, isChange));
}
return wallets;
}
deriveMultiple(count, startIndex = 0, account = 0, isChange = false, bipStandard = BIPStandard.BIP84) {
const wallets = [];
for (let i = 0; i < count; i++) {
wallets.push(this.derive(startIndex + i, account, isChange, bipStandard));
}
return wallets;
}
deriveCustomPath(classicalPath, quantumPath) {
const classicalChild = this._classicalRoot.derivePath(classicalPath);
const quantumChild = this._quantumRoot.derivePath(quantumPath);
if (!classicalChild.privateKey) {
throw new Error(`Failed to derive classical private key at path ${classicalPath}`);
}
if (!quantumChild.privateKey) {
throw new Error(`Failed to derive quantum private key at path ${quantumPath}`);
}
return new Wallet(toHex(new Uint8Array(classicalChild.privateKey)), toHex(new Uint8Array(quantumChild.privateKey)), this._network, this._securityLevel, new Uint8Array(this._quantumRoot.chainCode));
}
getClassicalRoot() {
return this._classicalRoot;
}
getQuantumRoot() {
return this._quantumRoot;
}
buildClassicalPath(account, index, isChange, bipStandard = BIPStandard.BIP84) {
const coinType = this.getCoinType();
const change = isChange ? 1 : 0;
return buildBIPPath(bipStandard, coinType, account, change, index);
}
buildQuantumPath(account, index, isChange) {
const coinType = this.getCoinType();
const change = isChange ? 1 : 0;
return `m/360'/${coinType}'/${account}'/${change}/${index}`;
}
getCoinType() {
if (this._network.bech32 === networks.testnet.bech32 ||
this._network.bech32 === networks.opnetTestnet.bech32 ||
this._network.bech32 === networks.regtest.bech32) {
return 1;
}
return 0;
}
}
//# sourceMappingURL=Mnemonic.js.map