try {
const entropy = crypto.getRandomValues(new Uint8Array(32))
const { phrase: mnemonicPhrase } = await Bip39.fromEntropy(entropy)
- const record = await this.import(type, key, keySalt, mnemonicPhrase, mnemonicSalt)
+ const record = await this.#import(type, key, keySalt, mnemonicPhrase, mnemonicSalt)
if (this.#seed == null || this.#mnemonic == null) {
throw new Error('Failed to generate seed and mnemonic')
}
return { ...record, seed: this.#seed.slice(), mnemonic: utf8.toBuffer(this.#mnemonic) }
} catch (err) {
throw new Error('Failed to create wallet', { cause: err })
+ } finally {
+ this.lock()
}
}
*/
static async import (type?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise<NamedData<ArrayBuffer>> {
try {
- if (!this.#locked) {
- throw new Error('Wallet is in use')
- }
- if (key == null || keySalt == null) {
- throw new Error('Wallet password is required')
- }
- if (type == null) {
- throw new TypeError('Wallet type is required')
- }
- if (type !== 'BIP-44' && type !== 'BLAKE2b') {
- throw new TypeError('Invalid wallet type')
- }
- if (secret == null) {
- throw new TypeError('Seed or mnemonic is required')
- }
- if (typeof secret !== 'string' && mnemonicSalt !== undefined) {
- throw new TypeError('Mnemonic must be a string')
- }
- if (type === 'BIP-44') {
- if (secret instanceof ArrayBuffer && (secret.byteLength < 16 || secret.byteLength > 64)) {
- throw new RangeError('Seed for BIP-44 wallet must be 16-64 bytes')
- }
- }
- if (type === 'BLAKE2b') {
- if (secret instanceof ArrayBuffer && secret.byteLength !== 32) {
- throw new RangeError('Seed for BLAKE2b wallet must be 32 bytes')
- }
- }
- this.#type = type
- if (secret instanceof ArrayBuffer) {
- this.#seed = secret
- if (type === 'BLAKE2b') {
- this.#mnemonic = (await Bip39.fromEntropy(new Uint8Array(secret))).phrase
- }
- } else {
- const mnemonic = await Bip39.fromPhrase(secret)
- this.#mnemonic = mnemonic.phrase
- this.#seed = type === 'BIP-44'
- ? (await mnemonic.toBip39Seed(mnemonicSalt ?? '')).buffer
- : (await mnemonic.toBlake2bSeed()).buffer
+ const record = await this.#import(type, key, keySalt, secret, mnemonicSalt)
+ if (this.#seed == null) {
+ throw new Error('Wallet seed not found')
}
- const { iv, encrypted } = await this.#encryptWallet(key)
- return { iv, salt: keySalt, encrypted }
+ return record
} catch (err) {
- this.lock()
throw new Error('Failed to import wallet', { cause: err })
+ } finally {
+ this.lock()
}
}
return { action, type, key, iv, keySalt, seed, mnemonicPhrase, mnemonicSalt, encrypted, index, data }
}
+
+ /**
+ * Encrypts an existing seed or mnemonic+salt and returns the initialization
+ * vector, salt, and encrypted data representing the wallet in a locked state.
+ */
+ static async #import (type?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise<NamedData<ArrayBuffer>> {
+ try {
+ if (!this.#locked) {
+ throw new Error('Wallet is in use')
+ }
+ if (key == null || keySalt == null) {
+ throw new Error('Wallet password is required')
+ }
+ if (type == null) {
+ throw new TypeError('Wallet type is required')
+ }
+ if (type !== 'BIP-44' && type !== 'BLAKE2b') {
+ throw new TypeError('Invalid wallet type')
+ }
+ if (secret == null) {
+ throw new TypeError('Seed or mnemonic is required')
+ }
+ if (typeof secret !== 'string' && mnemonicSalt !== undefined) {
+ throw new TypeError('Mnemonic must be a string')
+ }
+ if (type === 'BIP-44') {
+ if (secret instanceof ArrayBuffer && (secret.byteLength < 16 || secret.byteLength > 64)) {
+ throw new RangeError('Seed for BIP-44 wallet must be 16-64 bytes')
+ }
+ }
+ if (type === 'BLAKE2b') {
+ if (secret instanceof ArrayBuffer && secret.byteLength !== 32) {
+ throw new RangeError('Seed for BLAKE2b wallet must be 32 bytes')
+ }
+ }
+ this.#type = type
+ if (secret instanceof ArrayBuffer) {
+ this.#seed = secret
+ if (type === 'BLAKE2b') {
+ this.#mnemonic = (await Bip39.fromEntropy(new Uint8Array(secret))).phrase
+ }
+ } else {
+ const mnemonic = await Bip39.fromPhrase(secret)
+ this.#mnemonic = mnemonic.phrase
+ this.#seed = type === 'BIP-44'
+ ? (await mnemonic.toBip39Seed(mnemonicSalt ?? '')).buffer
+ : (await mnemonic.toBlake2bSeed()).buffer
+ }
+ const { iv, encrypted } = await this.#encryptWallet(key)
+ return { iv, salt: keySalt, encrypted }
+ } catch (err) {
+ throw new Error('Failed to import wallet', { cause: err })
+ }
+ }
}
let importWorkerThreads = ''