]> git.codecow.com Git - libnemo.git/commitdiff
Process derived public keys from wallet in single call.
authorChris Duncan <chris@zoso.dev>
Fri, 18 Jul 2025 13:07:40 +0000 (06:07 -0700)
committerChris Duncan <chris@zoso.dev>
Fri, 18 Jul 2025 13:07:40 +0000 (06:07 -0700)
src/lib/account.ts
src/lib/wallets/wallet.ts

index 8ca64d6aa54076d51270638cb616524775f236bf..08ac88462c9a38e7e7b2853eeb1408d50699088d 100644 (file)
@@ -86,48 +86,48 @@ export class Account {
        * Instantiates an Account object from its Nano address.\r
        *\r
        * @param {string} addresses - Address of the account\r
-       * @returns {Account} The instantiated Account object\r
+       * @returns {Account} A new Account object\r
        */\r
        static import (address: string): Account\r
        /**\r
        * Instantiates Account objects from their Nano addresses.\r
        *\r
        * @param {string[]} addresses - Addresses of the accounts\r
-       * @returns {Account[]} The instantiated Account objects\r
+       * @returns {Account[]} Array of new Account objects\r
        */\r
        static import (addresses: string[]): Account[]\r
        /**\r
        * Instantiates an Account object from its public key. It is unable to sign\r
        * blocks or messages since it has no private key.\r
        *\r
-       * @param {string} publicKey - Public key of the account\r
-       * @returns {Account} The instantiated Account object\r
+       * @param {Key} publicKey - Public key of the account\r
+       * @returns {Account} A new Account object\r
        */\r
-       static import (publicKey: string): Account\r
+       static import (publicKey: Key): Account\r
        /**\r
-       * Instantiates an Account object from its public key. It is unable to sign\r
-       * blocks or messages since it has no private key.\r
+       * Instantiates Account objects from their public keys. They are unable to sign\r
+       * blocks or messages since they have no private key.\r
        *\r
-       * @param {Uint8Array} publicKey - Public key of the account\r
-       * @returns {Account} The instantiated Account object\r
+       * @param {Key[]} publicKeys - Public keys of the accounts\r
+       * @returns {Account[]} Array of new Account objects\r
        */\r
-       static import (publicKey: Uint8Array<ArrayBuffer>): Account\r
+       static import (publicKeys: Key[]): Account[]\r
        /**\r
-       * Instantiates Account objects from their public keys. They are unable to sign\r
-       * blocks or messages since they have no private key.\r
+       * Instantiates an Account object from its public key. It is unable to sign\r
+       * blocks or messages since it has no private key.\r
        *\r
-       * @param {string[]} publicKeys - Public keys of the accounts\r
-       * @returns {Account[]} The instantiated Account objects\r
+       * @param {KeyPair} keypair - Index and keys of the account\r
+       * @returns {Account} A new Account object\r
        */\r
-       static import (publicKeys: string[]): Account[]\r
+       static import (keypair: KeyPair): Account\r
        /**\r
        * Instantiates Account objects from their public keys. They are unable to sign\r
        * blocks or messages since they have no private key.\r
        *\r
-       * @param {Uint8Array[]} publicKeys - Public keys of the accounts\r
-       * @returns {Account[]} The instantiated Account objects\r
+       * @param {KeyPair[]} keypairs - Indexes and keys of the accounts\r
+       * @returns {Account[]} Array of new Account objects\r
        */\r
-       static import (publicKeys: Uint8Array<ArrayBuffer>[]): Account[]\r
+       static import (keypairs: KeyPair[]): Account[]\r
        /**\r
        * Instantiates an Account object from its private key which is then encrypted\r
        * and stored in IndexedDB. The corresponding public key will automatically be\r
@@ -135,7 +135,7 @@ export class Account {
        *\r
        * @param {KeyPair} keypair - Index and keys of the account\r
        * @param {Key} password - Used to encrypt the private key\r
-       * @returns {Account} A new Account object\r
+       * @returns {Promise<Account>} Promise for a new Account object\r
        */\r
        static async import (keypair: KeyPair, password: Key): Promise<Account>\r
        /**\r
@@ -145,7 +145,7 @@ export class Account {
        *\r
        * @param {KeyPair[]} keypairs - Indexes and keys of the accounts\r
        * @param {Key} password - Used to encrypt the private keys\r
-       * @returns {Account[]} The instantiated Account objects\r
+       * @returns {Promise<Account[]>} Promise for array of new Account objects\r
        */\r
        static async import (keypairs: KeyPair[], password: Key): Promise<Account[]>\r
        static import (input: Key | Key[] | KeyPair | KeyPair[], password?: Key): Account | Account[] | Promise<Account | Account[]> {\r
@@ -383,16 +383,17 @@ export class Account {
        * Instantiates Account objects from public data, each specifying either its\r
        * public key or its Nano address.\r
        *\r
-       * @param {(string[]|Uint8Array[])} input - Public keys or addresses of the accounts\r
+       * @param {Key[]} input - Public keys or addresses of the accounts\r
        * @returns {Account[]} The instantiated Account objects\r
        */\r
-       static #fromPublic (input: KeyPair[] | unknown): Account[] {\r
-               if (!this.#isKeys(input)) {\r
+       static #fromPublic (input: Key[] | KeyPair[] | unknown): Account[] {\r
+               if (!this.#isKeys(input) && !this.#isKeyPairs(input)) {\r
                        throw new TypeError('Invalid public input for Account')\r
                }\r
                const accounts: Account[] = []\r
                let address: string\r
                let publicKey: Uint8Array<ArrayBuffer>\r
+               let index\r
                for (let i of input) {\r
                        let keyError, addressError\r
                        try {\r
@@ -412,16 +413,23 @@ export class Account {
                                        throw new TypeError('Failed to import Account from public data', { cause: { keyError, addressError } })\r
                                }\r
                        }\r
+                       if (this.#isKeyPair(i)) {\r
+                               index = i.index ?? undefined\r
+                       }\r
                        this.#isInternal = true\r
-                       accounts.push(new this(address, publicKey))\r
+                       accounts.push(new this(address, publicKey, index))\r
                }\r
                return accounts\r
        }\r
 \r
+       static #isKey (input: unknown): input is Key {\r
+               return typeof input === 'string' || (input instanceof Uint8Array && 'buffer' in input)\r
+       }\r
+\r
        static #isKeys (input: unknown): input is Key[] {\r
                if (Array.isArray(input)) {\r
                        for (const i of input) {\r
-                               if (typeof i !== 'string' && !(i instanceof Uint8Array && 'buffer' in i)) {\r
+                               if (!this.#isKey(i)) {\r
                                        return false\r
                                }\r
                        }\r
@@ -429,19 +437,31 @@ export class Account {
                return true\r
        }\r
 \r
+       static #isKeyPair (input: unknown): input is KeyPair {\r
+               if (typeof input === 'object') {\r
+                       const obj = input as { [key: string]: unknown }\r
+                       if ('index' in obj && typeof obj.index === 'number') {\r
+                               return true\r
+                       }\r
+                       if ('privateKey' in obj && this.#isKey(obj.privateKey)) {\r
+                               return true\r
+                       }\r
+                       if ('publicKey' in obj && this.#isKey(obj.privateKey)) {\r
+                               return true\r
+                       }\r
+               }\r
+               return false\r
+       }\r
+\r
        static #isKeyPairs (input: unknown): input is KeyPair[] {\r
                if (Array.isArray(input)) {\r
                        for (const i of input) {\r
-                               if (typeof i !== 'object') {\r
+                               if (!this.#isKeyPair(i)) {\r
                                        return false\r
                                }\r
-                               const obj = i as { [key: string]: unknown }\r
-                               if ('index' in obj || 'privateKey' in obj || 'publicKey' in obj) {\r
-                                       return true\r
-                               }\r
                        }\r
                }\r
-               return false\r
+               return true\r
        }\r
 \r
        /**\r
index fa46e43fbf9ff021bdc3166e6f5628393452ae91..28c28239ab40f33f6a24f342a2f62fcbb7907f89 100644 (file)
@@ -102,7 +102,8 @@ export abstract class Wallet {
                }\r
                if (indexes.length > 0) {\r
                        const keypairs = await this.ckd(indexes)\r
-                       const privateKeys = []\r
+                       const privateKeys: KeyPair[] = []\r
+                       const publicKeys: KeyPair[] = []\r
                        for (const keypair of keypairs) {\r
                                const { index, privateKey, publicKey } = keypair\r
                                if (index == null) {\r
@@ -110,15 +111,14 @@ export abstract class Wallet {
                                }\r
                                if (privateKey != null) {\r
                                        privateKeys.push(keypair)\r
-                               } else if (typeof publicKey === 'string') {\r
-                                       output[index] = Account.import(publicKey)\r
-                               } else if (publicKey instanceof Uint8Array) {\r
-                                       output[index] = Account.import(publicKey)\r
+                               } else if (publicKey != null) {\r
+                                       publicKeys.push(keypair)\r
                                }\r
-                               this.#accounts[index] = output[index]\r
                        }\r
                        const privateAccounts = await Account.import(privateKeys, this.seed)\r
-                       for (const a of privateAccounts) {\r
+                       const publicAccounts = Account.import(publicKeys)\r
+                       const accounts = [...privateAccounts, ...publicAccounts]\r
+                       for (const a of accounts) {\r
                                if (a.index == null) {\r
                                        throw new RangeError('Index missing for Account')\r
                                }\r