]> git.codecow.com Git - libnemo.git/commitdiff
Complete merge of wallet types.
authorChris Duncan <chris@zoso.dev>
Thu, 31 Jul 2025 21:40:37 +0000 (14:40 -0700)
committerChris Duncan <chris@zoso.dev>
Thu, 31 Jul 2025 21:40:37 +0000 (14:40 -0700)
12 files changed:
src/lib/bip44-ckd.ts [moved from src/lib/safe/bip44-ckd.ts with 100% similarity]
src/lib/blake2b-ckd.ts [moved from src/lib/safe/blake2b-ckd.ts with 100% similarity]
src/lib/ledger.ts [moved from src/lib/wallets/ledger-wallet.ts with 97% similarity]
src/lib/safe.ts [moved from src/lib/safe/safe.ts with 98% similarity]
src/lib/safe/index.ts [deleted file]
src/lib/safe/nano-nacl.ts
src/lib/safe/worker-interface.ts [deleted file]
src/lib/wallet.ts [moved from src/lib/wallets/wallet.ts with 78% similarity]
src/lib/wallets/bip44-wallet.ts [deleted file]
src/lib/wallets/blake2b-wallet.ts [deleted file]
src/lib/wallets/index.ts [deleted file]
src/lib/worker-queue.ts [moved from src/lib/safe/worker-queue.ts with 98% similarity]

similarity index 97%
rename from src/lib/wallets/ledger-wallet.ts
rename to src/lib/ledger.ts
index 46d62a9a140f7c935b2c887bf23d6b1b75416e7d..276b1fda789d1ad8b18f17be50f7d524ad435094 100644 (file)
@@ -5,7 +5,7 @@ import { ledgerUSBVendorId } from '@ledgerhq/devices'
 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
similarity index 98%
rename from src/lib/safe/safe.ts
rename to src/lib/safe.ts
index 4cb646867d2cf65405202f9601e0b09f58b1bd9f..89bb4c786ca3b71d314876a44dac958861d597d7 100644 (file)
@@ -4,12 +4,12 @@
 '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'
 
 /**
@@ -457,5 +457,7 @@ let importWorkerThreads = ''
 NODE: importWorkerThreads = `import { parentPort } from 'node:worker_threads'`
 export default `
        ${importWorkerThreads}
+       ${Convert}
+       const Bip39Words = ${Bip39Words}
        const Safe = ${Safe}
 `
diff --git a/src/lib/safe/index.ts b/src/lib/safe/index.ts
deleted file mode 100644 (file)
index e944442..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
-//! SPDX-License-Identifier: GPL-3.0-or-later
-
-export { SafeWorker } from './worker-queue'
index 0e8c8c2de65043a280b63f011b192df59f378b86..44afc7da51509455685b07f362a4e318d99400bd 100644 (file)
@@ -4,7 +4,7 @@
 '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
diff --git a/src/lib/safe/worker-interface.ts b/src/lib/safe/worker-interface.ts
deleted file mode 100644 (file)
index abd5899..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-//! 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)
-       }
-}
similarity index 78%
rename from src/lib/wallets/wallet.ts
rename to src/lib/wallet.ts
index 0156598382e67f3b9775d1f969192ad13590822b..cb907d9cb6cc215c2948b93b7734bb51de06494e 100644 (file)
@@ -9,8 +9,9 @@ import { bytes, hex, utf8 } from '#src/lib/convert.js'
 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
@@ -21,6 +22,24 @@ import { SafeWorker } from '#workers'
 */\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
@@ -31,8 +50,10 @@ export class Wallet {
        * @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
@@ -44,27 +65,49 @@ export class Wallet {
                                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
@@ -129,17 +172,15 @@ export class Wallet {
                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
@@ -170,7 +211,7 @@ export class Wallet {
        */\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
@@ -221,7 +262,7 @@ export class Wallet {
        */\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
@@ -244,12 +285,8 @@ export class Wallet {
        */\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
diff --git a/src/lib/wallets/bip44-wallet.ts b/src/lib/wallets/bip44-wallet.ts
deleted file mode 100644 (file)
index a37b608..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-//! 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
diff --git a/src/lib/wallets/blake2b-wallet.ts b/src/lib/wallets/blake2b-wallet.ts
deleted file mode 100644 (file)
index 57279c6..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-//! 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
diff --git a/src/lib/wallets/index.ts b/src/lib/wallets/index.ts
deleted file mode 100644 (file)
index 94d687e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-//! 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
similarity index 98%
rename from src/lib/safe/worker-queue.ts
rename to src/lib/worker-queue.ts
index 1143167131ff2ed72f62622a2ed59e634fe6fc73..d69e56581bf2adba9e9bf5d2674accd59ff6b9d3 100644 (file)
@@ -110,5 +110,3 @@ export class WorkerQueue {
                }
        }
 }
-
-export const SafeWorker = new WorkerQueue(safe)