import { default as TransportBLE } from '@ledgerhq/hw-transport-web-ble'\r
import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb'\r
import { default as TransportHID } from '@ledgerhq/hw-transport-webhid'\r
-import { Wallet } from '.'\r
+import { Wallet } from './wallets'\r
import { ChangeBlock, ReceiveBlock, SendBlock } from '#src/lib/block.js'\r
import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_ADPU_CODES, LEDGER_STATUS_CODES } from '#src/lib/constants.js'\r
import { bytes, dec, hex } from '#src/lib/convert.js'\r
'use strict'
import { parentPort } from 'node:worker_threads'
-import { Bip39Words } from '../bip39-wordlist'
+import { Bip39Words } from './bip39-wordlist'
import { Bip44Ckd } from './bip44-ckd'
import { Blake2bCkd } from './blake2b-ckd'
-import { NanoNaCl } from '../nano-nacl'
+import { NanoNaCl } from './safe/nano-nacl'
import { Bip39Mnemonic } from '#src/lib/bip39-mnemonic.js'
-import { bytes, dec, hex, utf8 } from '#src/lib/convert.js'
+import { default as Convert, bytes, hex, utf8 } from '#src/lib/convert.js'
import { NamedData } from '#src/types.js'
/**
NODE: importWorkerThreads = `import { parentPort } from 'node:worker_threads'`
export default `
${importWorkerThreads}
+ ${Convert}
+ const Bip39Words = ${Bip39Words}
const Safe = ${Safe}
`
+++ /dev/null
-//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
-//! SPDX-License-Identifier: GPL-3.0-or-later
-
-export { SafeWorker } from './worker-queue'
'use strict'\r
\r
import { Blake2b } from '#src/lib/blake2b.js'\r
-import { default as Convert, hex } from '#src/lib/convert.js'\r
+import { hex } from '#src/lib/convert.js'\r
import { Key, NamedData } from '#types'\r
\r
/**\r
+++ /dev/null
-//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
-//! SPDX-License-Identifier: GPL-3.0-or-later
-
-import { parentPort } from 'node:worker_threads'
-import { NamedData } from '#types'
-
-/**
-* Provides basic worker event messaging to extending classes.
-*
-* In order to be properly bundled in a format that can be used to create an
-* inline Web Worker, the extending classes must export WorkerInterface and
-* themselves as a string:
-*```
-* export default `
-* const WorkerInterface = ${WorkerInterface}
-* const WorkerImplementation = ${WorkerImplementation}
-* `
-* ```
-* They must also initialize the event listener by calling their inherited
-* `listen()` function. Finally, they must override the implementation of the
-* `work()` function. See the documentation of those functions for details.
-*/
-export abstract class WorkerInterface {
- static parentPort: any
- static {
- NODE: this.parentPort = parentPort
- }
- /**
- * Processes data through a worker.
- *
- * Extending classes must override this template by implementing the same
- * function signature and providing their own processing call in the try-catch
- * block.
- *
- * @param {NamedData} data - Flat object of data key-value pairs
- * @returns Promise for processed data
- */
- static work (data: NamedData): Promise<NamedData> {
- return new Promise((resolve, reject): void => {
- try {
- if (data == null) {
- throw new Error('Missing data')
- }
- const { x, y } = data
- resolve({ x, y })
- } catch (err) {
- reject(err)
- }
- })
- }
-
- /**
- * Transfers buffers of worker results back to the main thread.
- *
- * @param {NamedData} data - Key-value pairs of processed data
- */
- static report (data: NamedData): void {
- const buffers = []
- try {
- if (typeof data === 'object') {
- for (const d of Object.keys(data)) {
- if (data[d] instanceof ArrayBuffer) {
- buffers.push(data[d])
- }
- }
- }
- } catch (err) {
- console.error(err)
- throw new Error('Failed to report results', { cause: err })
- }
- //@ts-expect-error
- BROWSER: postMessage(data, buffers)
- NODE: parentPort?.postMessage(data, buffers)
- }
-
- /**
- * Listens for messages from the main thread.
- *
- * Extending classes must call this in a static initialization block:
- * ```
- * static {
- * Extension.listen()
- * }
- * ```
- */
- static listen (): void {
- const listener = async (message: MessageEvent<any>): Promise<void> => {
- // console.log(message)
- const { data } = message
- if (data.method === 'STOP') {
- this.report({})
- BROWSER: close()
- NODE: process.exit()
- } else {
- this.work(data).then(this.report).catch(this.report)
- }
- }
- BROWSER: addEventListener('message', listener)
- NODE: this.parentPort?.on('message', listener)
- }
-}
import { Database } from '#src/lib/database.js'\r
import { Entropy } from '#src/lib/entropy.js'\r
import { Rpc } from '#src/lib/rpc.js'\r
+import { default as SafeWorker } from '#src/lib/safe.js'\r
+import { WorkerQueue } from '#src/lib/worker-queue.js'\r
import { KeyPair, NamedData, WalletType } from '#types'\r
-import { SafeWorker } from '#workers'\r
\r
/**\r
* Represents a wallet containing numerous Nano accounts derived from a single\r
*/\r
export class Wallet {\r
static #DB_NAME = 'Wallet'\r
+ static #isInternal: boolean = false\r
+\r
+ /**\r
+ * Retrieves a wallet from the database.\r
+ */\r
+ static async #get (name: string) {\r
+ try {\r
+ const record = await Database.get<string>(name, this.#DB_NAME)\r
+ const decoded = JSON.parse(record[name])\r
+ const type: 'BIP-44' | 'BLAKE2b' = decoded.type\r
+ const iv: ArrayBuffer = hex.toBuffer(decoded.iv)\r
+ const salt: ArrayBuffer = hex.toBuffer(decoded.salt)\r
+ const encrypted: ArrayBuffer = hex.toBuffer(decoded.encrypted)\r
+ return { type, iv, salt, encrypted }\r
+ } catch (err) {\r
+ throw new Error('Failed to get wallet from database', { cause: err })\r
+ }\r
+ }\r
\r
/**\r
* Creates a new HD wallet by using an entropy value generated using a\r
* @returns {Bip44Wallet} A newly instantiated Wallet\r
*/\r
static async create (name: string, type: 'BIP-44' | 'BLAKE2b', password: string, mnemonicSalt?: string): Promise<Wallet> {\r
+ Wallet.#isInternal = true\r
+ const self = new this(name, type)\r
try {\r
- const { iv, salt, encrypted } = await SafeWorker.request<ArrayBuffer>({\r
+ const { iv, salt, encrypted } = await self.#safe.request<ArrayBuffer>({\r
action: 'create',\r
type,\r
password: utf8.toBuffer(password),\r
salt: bytes.toHex(new Uint8Array(salt)),\r
encrypted: bytes.toHex(new Uint8Array(encrypted))\r
})\r
- await Database.put({ [name]: encoded }, this.#DB_NAME)\r
- return new this(name, type)\r
+ await Database.put({ [name]: encoded }, Wallet.#DB_NAME)\r
+ return self\r
} catch (err) {\r
throw new Error('Error creating new Bip44Wallet', { cause: err })\r
}\r
}\r
\r
+ /**\r
+ * Retrieves an existing wallet from the database using its name.\r
+ *\r
+ * @param {string} name - Entered by user when the wallet was initially created\r
+ * @returns {Wallet} Restored locked Wallet\r
+ */\r
+ static async restore (name: string): Promise<Wallet> {\r
+ try {\r
+ if (typeof name !== 'string' || name === '') {\r
+ throw new TypeError('Wallet name is required to restore')\r
+ }\r
+ const { type } = await this.#get(name)\r
+ Wallet.#isInternal = true\r
+ return new this(name, type)\r
+ } catch (err) {\r
+ throw new Error('Failed to restore wallet', { cause: err })\r
+ }\r
+ }\r
+\r
#accounts: AccountList\r
#lockTimer?: any\r
#name: string\r
+ #safe: WorkerQueue\r
#type: WalletType\r
\r
get name () { return `${this.type}_${this.#name}` }\r
get type () { return this.#type }\r
\r
constructor (name: string, type: WalletType) {\r
- if (this.constructor === Wallet) {\r
- throw new Error('Wallet is an abstract class and cannot be instantiated directly.')\r
+ if (!Wallet.#isInternal) {\r
+ throw new Error(`Wallet cannot be instantiated directly. Use 'await Wallet.create()' instead.`)\r
}\r
+ Wallet.#isInternal = false\r
this.#accounts = new AccountList()\r
this.#name = name\r
+ this.#safe = new WorkerQueue(SafeWorker)\r
this.#type = type\r
}\r
\r
if (indexes.length > 0) {\r
const promises = []\r
for (const index of indexes) {\r
- promises.push(SafeWorker.request<ArrayBuffer>({\r
+ promises.push(this.#safe.request<ArrayBuffer>({\r
action: 'derive',\r
index\r
}))\r
}\r
- const publicKeys = await Promise.all(promises)\r
- const publicAccounts = publicKeys.length > 0\r
- ? Account.import(publicKeys)\r
- : []\r
- const accounts = [...publicAccounts]\r
- for (const a of accounts) {\r
+ const publicKeys: KeyPair[] = await Promise.all(promises)\r
+ if (publicKeys.length === 0) return []\r
+ const publicAccounts = Account.import(publicKeys)\r
+ for (const a of publicAccounts) {\r
if (a.index == null) {\r
throw new RangeError('Index missing for Account')\r
}\r
*/\r
async lock (): Promise<boolean> {\r
try {\r
- const { isLocked } = await SafeWorker.request<boolean>({\r
+ const { isLocked } = await this.#safe.request<boolean>({\r
action: 'lock'\r
})\r
if (!isLocked) {\r
*/\r
async sign (index: number, block: ChangeBlock | ReceiveBlock | SendBlock): Promise<string> {\r
try {\r
- const { signature } = await SafeWorker.request<ArrayBuffer>({\r
+ const { signature } = await this.#safe.request<ArrayBuffer>({\r
action: 'sign',\r
index,\r
data: JSON.stringify(block)\r
*/\r
async unlock (password: string): Promise<boolean> {\r
try {\r
- const record = await Database.get<string>(this.#name, Wallet.#DB_NAME)\r
- const decoded = JSON.parse(record[this.#name])\r
- const iv: ArrayBuffer = hex.toBuffer(decoded.iv)\r
- const salt: ArrayBuffer = hex.toBuffer(decoded.salt)\r
- const encrypted: ArrayBuffer = hex.toBuffer(decoded.encrypted)\r
- const { isUnlocked } = await SafeWorker.request<boolean>({\r
+ const { iv, salt, encrypted } = await Wallet.#get(this.#name)\r
+ const { isUnlocked } = await this.#safe.request<boolean>({\r
action: 'unlock',\r
password: utf8.toBuffer(password),\r
iv,\r
+++ /dev/null
-//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>\r
-//! SPDX-License-Identifier: GPL-3.0-or-later\r
-\r
-import { Wallet } from '.'\r
-import { Bip39Mnemonic } from '#src/lib/bip39-mnemonic.js'\r
-import { SEED_LENGTH_BIP44 } from '#src/lib/constants.js'\r
-import { hex } from '#src/lib/convert.js'\r
-import { Entropy } from '#src/lib/entropy.js'\r
-import { Key, KeyPair } from '#types'\r
-import { SafeWorker } from '#workers'\r
-\r
-/**\r
-* Hierarchical deterministic (HD) wallet created by using a source of entropy to\r
-* derive a mnemonic phrase. The mnemonic phrase, in combination with an optional\r
-* salt, is used to generate a seed. A value can be provided as a parameter for\r
-* entropy, mnemonic + salt, or seed; if no argument is passed, a new entropy\r
-* value will be generated using a cryptographically strong pseudorandom number\r
-* generator.\r
-*\r
-* Importantly, the salt is not stored in the instantiated Wallet object. If a\r
-* salt is used, then losing it means losing the ability to regenerate the seed\r
-* from the mnemonic.\r
-*\r
-* Accounts are derived from the seed. Private keys are derived using a BIP-44\r
-* derivation path. The public key is derived from the private key using the\r
-* Ed25519 key algorithm. Account addresses are derived as described in the nano\r
-* documentation (https://docs.nano.org)\r
-*\r
-* A password must be provided when creating or importing the wallet and is used\r
-* to lock and unlock the wallet. The wallet will be initialized as locked. When\r
-* the wallet is unlocked, a new password can be specified using the lock()\r
-* method.\r
-*/\r
-export class Bip44Wallet extends Wallet {\r
- static #isInternal: boolean = false\r
-\r
- private constructor (id: Entropy, seed?: Uint8Array<ArrayBuffer>, mnemonic?: Bip39Mnemonic) {\r
- if (!Bip44Wallet.#isInternal) {\r
- throw new Error(`Bip44Wallet cannot be instantiated directly. Use 'await Bip44Wallet.create()' instead.`)\r
- }\r
- Bip44Wallet.#isInternal = false\r
- super(id.hex, 'BIP-44')\r
- }\r
-\r
- /**\r
- * Creates a new HD wallet by using an entropy value generated using a\r
- * cryptographically strong pseudorandom number generator.\r
- *\r
- * @param {string} password - Encrypts the wallet to lock and unlock it\r
- * @param {string} [salt=''] - Used when generating the final seed\r
- * @returns {Bip44Wallet} A newly instantiated Bip44Wallet\r
- */\r
- static async create (password: string, salt?: string): Promise<Bip44Wallet>\r
- /**\r
- * Creates a new HD wallet by using an entropy value generated using a\r
- * cryptographically strong pseudorandom number generator.\r
- *\r
- * @param {Uint8Array} key - Encrypts the wallet to lock and unlock it\r
- * @param {string} [salt=''] - Used when generating the final seed\r
- * @returns {Bip44Wallet} A newly instantiated Bip44Wallet\r
- */\r
- static async create (key: Uint8Array<ArrayBuffer>, salt?: string): Promise<Bip44Wallet>\r
- static async create (passkey: Key, salt: string = ''): Promise<Bip44Wallet> {\r
- try {\r
- const e = await Entropy.create()\r
- return await Bip44Wallet.fromEntropy(passkey as string, e.hex, salt)\r
- } catch (err) {\r
- throw new Error('Error creating new Bip44Wallet', { cause: err })\r
- }\r
- }\r
-\r
- /**\r
- * Creates a new HD wallet by using a pregenerated entropy value. The user\r
- * must ensure that it is cryptographically strongly random.\r
- *\r
- * @param {string} password - Used to lock and unlock the wallet\r
- * @param {string} entropy - Used when generating the initial mnemonic phrase\r
- * @param {string} [salt=''] - Used when generating the final seed\r
- * @returns {Bip44Wallet} A newly instantiated Bip44Wallet\r
- */\r
- static async fromEntropy (password: string, entropy: string, salt: string = ''): Promise<Bip44Wallet> {\r
- let wallet: Bip44Wallet\r
- try {\r
- const id = await Entropy.create()\r
- const e = await Entropy.import(entropy)\r
- const m = await Bip39Mnemonic.fromEntropy(e.hex)\r
- const s = await m.toBip39Seed(salt)\r
- Bip44Wallet.#isInternal = true\r
- wallet = new this(id, s, m)\r
- } catch (err) {\r
- throw new Error('Error importing Bip44Wallet from entropy', { cause: err })\r
- }\r
- try {\r
- await wallet.lock()\r
- } catch (err) {\r
- await wallet.destroy()\r
- throw new Error('Error locking Bip44Wallet while importing from entropy', { cause: err })\r
- }\r
- return wallet\r
- }\r
-\r
- /**\r
- * Creates a new HD wallet by using a pregenerated mnemonic phrase.\r
- *\r
- * @param {string} password - Used to lock and unlock the wallet\r
- * @param {string} mnemonic - Used when generating the final seed\r
- * @param {string} [salt=''] - Used when generating the final seed\r
- * @returns {Bip44Wallet} A newly instantiated Bip44Wallet\r
- */\r
- static async fromMnemonic (password: string, mnemonic: string, salt: string = ''): Promise<Bip44Wallet> {\r
- let wallet: Bip44Wallet\r
- try {\r
- const id = await Entropy.create()\r
- const m = await Bip39Mnemonic.fromPhrase(mnemonic)\r
- const s = await m.toBip39Seed(salt)\r
- Bip44Wallet.#isInternal = true\r
- wallet = new this(id, s, m)\r
- } catch (err) {\r
- throw new Error('Error importing Bip44Wallet from mnemonic', { cause: err })\r
- }\r
- try {\r
- await wallet.lock()\r
- } catch (err) {\r
- await wallet.destroy()\r
- throw new Error('Error locking Bip44Wallet while importing from mnemonic', { cause: err })\r
- }\r
- return wallet\r
- }\r
-\r
- /**\r
- * Creates a new HD wallet by using a pregenerated seed value. This seed cannot\r
- * be used to regenerate any higher level randomness which includes entropy,\r
- * mnemonic phrase, and salt.\r
- *\r
- * @param {string} password - Used to lock and unlock the wallet\r
- * @param {string} seed - Hexadecimal 128-character string used to derive private-public key pairs\r
- * @returns {Bip44Wallet} A newly instantiated Bip44Wallet\r
- */\r
- static async fromSeed (password: string, seed: string): Promise<Bip44Wallet> {\r
- if (seed.length !== SEED_LENGTH_BIP44) {\r
- throw new Error(`Expected a ${SEED_LENGTH_BIP44}-character seed, but received ${seed.length}-character string.`)\r
- }\r
- if (!/^[0-9a-fA-F]+$/i.test(seed)) {\r
- throw new Error('Seed contains invalid hexadecimal characters.')\r
- }\r
- const id = await Entropy.create()\r
- Bip44Wallet.#isInternal = true\r
- const wallet = new this(id, hex.toBytes(seed))\r
- try {\r
- await wallet.lock()\r
- } catch (err) {\r
- await wallet.destroy()\r
- throw new Error('Error locking Bip44Wallet while importing from seed', { cause: err })\r
- }\r
- return wallet\r
- }\r
-\r
- /**\r
- * Retrieves an existing HD wallet from storage using its ID.\r
- *\r
- * @param {string} id - Generated when the wallet was initially created\r
- * @returns {Bip44Wallet} Restored locked Bip44Wallet\r
- */\r
- static async restore (id: string): Promise<Bip44Wallet> {\r
- if (typeof id !== 'string' || id === '') {\r
- throw new TypeError('Wallet ID is required to restore')\r
- }\r
- id = id.replace('BIP-44_', '')\r
- Bip44Wallet.#isInternal = true\r
- return new this(await Entropy.import(id))\r
- }\r
-}\r
+++ /dev/null
-//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>\r
-//! SPDX-License-Identifier: GPL-3.0-or-later\r
-\r
-import { Wallet } from '.'\r
-import { Bip39Mnemonic } from '#src/lib/bip39-mnemonic.js'\r
-import { Blake2b } from '#src/lib/blake2b.js'\r
-import { SEED_LENGTH_BLAKE2B } from '#src/lib/constants.js'\r
-import { hex, utf8 } from '#src/lib/convert.js'\r
-import { Entropy } from '#src/lib/entropy.js'\r
-import { Key, KeyPair } from '#types'\r
-\r
-/**\r
-* BLAKE2b wallet created by deriving a mnemonic phrase from a seed or vice\r
-* versa. If no value is provided for either, a new BIP-39 seed and mnemonic will\r
-* be generated using a cryptographically strong pseudorandom number generator.\r
-*\r
-* Account private keys are derived on an ad hoc basis using the Blake2b hashing\r
-* function. Account public key are derived from the private key using the\r
-* Ed25519 key algorithm. Account addresses are derived from the public key as\r
-* described in the Nano documentation.\r
-* https://docs.nano.org/integration-guides/the-basics/\r
-*\r
-* A password must be provided when creating or importing the wallet and is used\r
-* to lock and unlock the wallet. The wallet will be initialized as locked. When\r
-* the wallet is unlocked, a new password can be specified using the lock()\r
-* method.\r
-*/\r
-export class Blake2bWallet extends Wallet {\r
- static #isInternal: boolean = false\r
-\r
- private constructor (id: Entropy, seed?: Uint8Array<ArrayBuffer>, mnemonic?: Bip39Mnemonic) {\r
- if (!Blake2bWallet.#isInternal) {\r
- throw new Error(`Blake2bWallet cannot be instantiated directly. Use 'await Blake2bWallet.create()' instead.`)\r
- }\r
- Blake2bWallet.#isInternal = false\r
- super(id.hex, 'BLAKE2b')\r
- }\r
-\r
- /**\r
- * Creates a new BLAKE2b wallet by using a seed generated using a\r
- * cryptographically strong pseudorandom number generator.\r
- *\r
- * @param {string} password - Encrypts the wallet to lock and unlock it\r
- * @returns {Blake2bWallet} A newly instantiated Blake2bWallet\r
- */\r
- static async create (password: string): Promise<Blake2bWallet>\r
- /**\r
- * Creates a new BLAKE2b wallet by using a seed generated using a\r
- * cryptographically strong pseudorandom number generator.\r
- *\r
- * @param {Uint8Array} key - Encrypts the wallet to lock and unlock it\r
- * @returns {Blake2bWallet} A newly instantiated Blake2bWallet\r
- */\r
- static async create (key: Uint8Array): Promise<Blake2bWallet>\r
- static async create (passkey: string | Uint8Array): Promise<Blake2bWallet> {\r
- try {\r
- const seed = await Entropy.create()\r
- return await Blake2bWallet.fromSeed(passkey as string, seed.hex)\r
- } catch (err) {\r
- throw new Error('Error creating new Blake2bWallet', { cause: err })\r
- }\r
- }\r
-\r
- /**\r
- * Creates a new BLAKE2b wallet by using a pregenerated seed. The user must\r
- * ensure that it is cryptographically strongly random.\r
- *\r
- * @param {string} password - Used to lock and unlock the wallet\r
- * @param {string} seed - Hexadecimal 64-character string used to derive private-public key pairs\r
- * @returns {Blake2bWallet} A newly instantiated Blake2bWallet\r
- */\r
- static async fromSeed (password: string, seed: string): Promise<Blake2bWallet> {\r
- if (seed.length !== SEED_LENGTH_BLAKE2B) {\r
- throw new Error(`Expected a ${SEED_LENGTH_BLAKE2B}-character seed, but received ${seed.length}-character string.`)\r
- }\r
- if (!/^[0-9a-fA-F]+$/i.test(seed)) {\r
- throw new Error('Seed contains invalid hexadecimal characters.')\r
- }\r
-\r
- const id = await Entropy.create()\r
- const s = hex.toBytes(seed)\r
- const m = await Bip39Mnemonic.fromEntropy(seed)\r
- Blake2bWallet.#isInternal = true\r
- const wallet = new this(id, s, m)\r
- try {\r
- await wallet.lock()\r
- } catch (err) {\r
- await wallet.destroy()\r
- throw new Error('Error locking Blake2bWallet while importing from seed', { cause: err })\r
- }\r
- return wallet\r
- }\r
-\r
- /**\r
- * Creates a new BLAKE2b wallet by using a pregenerated mnemonic phrase.\r
- *\r
- * @param {string} password - Used to lock and unlock the wallet\r
- * @param {string} mnemonic - Used when generating the final seed\r
- * @returns {Blake2bWallet} A newly instantiated Blake2bWallet\r
- */\r
- static async fromMnemonic (password: string, mnemonic: string): Promise<Blake2bWallet> {\r
- let wallet: Blake2bWallet\r
- try {\r
- const id = await Entropy.create()\r
- const m = await Bip39Mnemonic.fromPhrase(mnemonic)\r
- const s = await m.toBlake2bSeed()\r
- Blake2bWallet.#isInternal = true\r
- wallet = new this(id, s, m)\r
- } catch (err) {\r
- throw new Error('Error importing Blake2bWallet from mnemonic', { cause: err })\r
- }\r
- try {\r
- await wallet.lock()\r
- } catch (err) {\r
- await wallet.destroy()\r
- throw new Error('Error locking Blake2bWallet while importing from mnemonic', { cause: err })\r
- }\r
- return wallet\r
- }\r
-\r
- /**\r
- * Retrieves an existing BLAKE2b wallet from storage using its ID.\r
- *\r
- * @param {string} id - Generated when the wallet was initially created\r
- * @returns {Blake2bWallet} Restored locked Blake2bWallet\r
- */\r
- static async restore (id: string): Promise<Blake2bWallet> {\r
- if (typeof id !== 'string' || id === '') {\r
- throw new TypeError('Wallet ID is required to restore')\r
- }\r
- id = id.replace('BLAKE2b_', '')\r
- Blake2bWallet.#isInternal = true\r
- return new this(await Entropy.import(id))\r
- }\r
-}\r
+++ /dev/null
-//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>\r
-//! SPDX-License-Identifier: GPL-3.0-or-later\r
-\r
-export { Wallet } from './wallet'\r
-export { Bip44Wallet } from './bip44-wallet'\r
-export { Blake2bWallet } from './blake2b-wallet'\r
-export { LedgerWallet } from './ledger-wallet'\r
}
}
}
-
-export const SafeWorker = new WorkerQueue(safe)