Wallet.#poolSafe ??= new Pool(SafeWorker)\r
}\r
\r
- /**\r
- * Removes encrypted secrets in storage and releases variable references to\r
- * allow garbage collection.\r
- */\r
- async destroy (): Promise<void> {\r
- let i = 0\r
- for (const a in this.#accounts) {\r
- await this.#accounts[a].destroy()\r
- delete this.#accounts[a]\r
- i++\r
- }\r
- this.#m = null\r
- this.#s = null\r
- await Wallet.#poolSafe.assign({\r
- method: 'destroy',\r
- name: this.id\r
- })\r
- }\r
-\r
/**\r
* Retrieves an account from a wallet using its child key derivation function.\r
* Defaults to the first account at index 0.\r
}\r
\r
/**\r
- * Fetches the lowest-indexed unopened account from a wallet in sequential\r
- * order. An account is unopened if it has no frontier block.\r
- *\r
- * @param {Rpc|string|URL} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks\r
- * @param {number} batchSize - Number of accounts to fetch and check per RPC callout\r
- * @param {number} from - Account index from which to start the search\r
- * @returns {Promise<Account>} The lowest-indexed unopened account belonging to the wallet\r
- */\r
- async getNextNewAccount (rpc: Rpc, batchSize: number = ADDRESS_GAP, from: number = 0): Promise<Account> {\r
- if (!Number.isSafeInteger(batchSize) || batchSize < 1) {\r
- throw new RangeError(`Invalid batch size ${batchSize}`)\r
- }\r
- const accounts = await this.accounts(from, from + batchSize - 1)\r
- const addresses = []\r
- for (const a in accounts) {\r
- addresses.push(accounts[a].address)\r
- }\r
- const data = {\r
- "accounts": addresses\r
- }\r
- const { errors } = await rpc.call('accounts_frontiers', data)\r
- for (const key of Object.keys(errors ?? {})) {\r
- const value = errors[key]\r
- if (value === 'Account not found') {\r
- return Account.fromAddress(key)\r
- }\r
- }\r
- return await this.getNextNewAccount(rpc, batchSize, from + batchSize)\r
- }\r
-\r
- /**\r
- * Refreshes wallet account balances, frontiers, and representatives from the\r
- * current state on the network.\r
- *\r
- * A successful response will set these properties on each account.\r
- *\r
- * @param {Rpc|string|URL} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks\r
- * @returns {Promise<Account[]>} Accounts with updated balances, frontiers, and representatives\r
+ * Removes encrypted secrets in storage and releases variable references to\r
+ * allow garbage collection.\r
*/\r
- async refresh (rpc: Rpc | string | URL, from: number = 0, to: number = from): Promise<AccountList> {\r
- if (typeof rpc === 'string' || rpc.constructor === URL) {\r
- rpc = new Rpc(rpc)\r
- }\r
- if (rpc.constructor !== Rpc) {\r
- throw new TypeError('RPC must be a valid node')\r
- }\r
- const accounts = await this.accounts(from, to)\r
- for (const a in accounts) {\r
- try {\r
- await accounts[a].refresh(rpc)\r
- } catch (err) {\r
- delete accounts[a]\r
- }\r
+ async destroy (): Promise<void> {\r
+ let i = 0\r
+ for (const a in this.#accounts) {\r
+ await this.#accounts[a].destroy()\r
+ delete this.#accounts[a]\r
+ i++\r
}\r
- return accounts\r
+ this.#m = null\r
+ this.#s = null\r
+ await Wallet.#poolSafe.assign({\r
+ method: 'destroy',\r
+ name: this.id\r
+ })\r
}\r
\r
/**\r
return true\r
}\r
\r
+ /**\r
+ * Refreshes wallet account balances, frontiers, and representatives from the\r
+ * current state on the network.\r
+ *\r
+ * A successful response will set these properties on each account.\r
+ *\r
+ * @param {Rpc|string|URL} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks\r
+ * @returns {Promise<Account[]>} Accounts with updated balances, frontiers, and representatives\r
+ */\r
+ async refresh (rpc: Rpc | string | URL, from: number = 0, to: number = from): Promise<AccountList> {\r
+ if (typeof rpc === 'string' || rpc.constructor === URL) {\r
+ rpc = new Rpc(rpc)\r
+ }\r
+ if (rpc.constructor !== Rpc) {\r
+ throw new TypeError('RPC must be a valid node')\r
+ }\r
+ const accounts = await this.accounts(from, to)\r
+ for (const a in accounts) {\r
+ try {\r
+ await accounts[a].refresh(rpc)\r
+ } catch (err) {\r
+ delete accounts[a]\r
+ }\r
+ }\r
+ return accounts\r
+ }\r
+\r
/**\r
* Unlocks the wallet using the same password as used prior to lock it.\r
*\r
}\r
return true\r
}\r
+\r
+ /**\r
+ * Fetches the lowest-indexed unopened account from a wallet in sequential\r
+ * order. An account is unopened if it has no frontier block.\r
+ *\r
+ * @param {Rpc|string|URL} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks\r
+ * @param {number} batchSize - Number of accounts to fetch and check per RPC callout\r
+ * @param {number} from - Account index from which to start the search\r
+ * @returns {Promise<Account>} The lowest-indexed unopened account belonging to the wallet\r
+ */\r
+ async unopened (rpc: Rpc, batchSize: number = ADDRESS_GAP, from: number = 0): Promise<Account> {\r
+ if (!Number.isSafeInteger(batchSize) || batchSize < 1) {\r
+ throw new RangeError(`Invalid batch size ${batchSize}`)\r
+ }\r
+ const accounts = await this.accounts(from, from + batchSize - 1)\r
+ const addresses = []\r
+ for (const a in accounts) {\r
+ addresses.push(accounts[a].address)\r
+ }\r
+ const data = {\r
+ "accounts": addresses\r
+ }\r
+ const { errors } = await rpc.call('accounts_frontiers', data)\r
+ for (const key of Object.keys(errors ?? {})) {\r
+ const value = errors[key]\r
+ if (value === 'Account not found') {\r
+ return Account.fromAddress(key)\r
+ }\r
+ }\r
+ return await this.unopened(rpc, batchSize, from + batchSize)\r
+ }\r
}\r
await test('return correct account from test vector', async () => {
const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)
- const account = await wallet.getNextNewAccount(rpc)
+ const account = await wallet.unopened(rpc)
assert.exists(account)
assert.equals(account.address, NANO_TEST_VECTORS.ADDRESS_1)
await test('return successfully for small batch size', async () => {
const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)
- const account = await wallet.getNextNewAccount(rpc, 1)
+ const account = await wallet.unopened(rpc, 1)
assert.exists(account)
assert.equals(account.address, NANO_TEST_VECTORS.ADDRESS_1)
await test('return successfully for large batch size', async () => {
const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)
- const account = await wallet.getNextNewAccount(rpc, 100)
+ const account = await wallet.unopened(rpc, 100)
assert.exists(account)
assert.equals(account.address, NANO_TEST_VECTORS.ADDRESS_1)
const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)
- await assert.rejects(wallet.getNextNewAccount())
- await assert.rejects(wallet.getNextNewAccount(null))
- await assert.rejects(wallet.getNextNewAccount(1))
- await assert.rejects(wallet.getNextNewAccount(''))
- await assert.rejects(wallet.getNextNewAccount('foo'))
+ await assert.rejects(wallet.unopened())
+ await assert.rejects(wallet.unopened(null))
+ await assert.rejects(wallet.unopened(1))
+ await assert.rejects(wallet.unopened(''))
+ await assert.rejects(wallet.unopened('foo'))
await wallet.destroy()
})
const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)
- await assert.rejects(wallet.getNextNewAccount(rpc, null))
- await assert.rejects(wallet.getNextNewAccount(rpc, -1))
- await assert.rejects(wallet.getNextNewAccount(rpc, ''))
- await assert.rejects(wallet.getNextNewAccount(rpc, 'foo'))
- await assert.rejects(wallet.getNextNewAccount(rpc, { 'foo': 'bar' }))
+ await assert.rejects(wallet.unopened(rpc, null))
+ await assert.rejects(wallet.unopened(rpc, -1))
+ await assert.rejects(wallet.unopened(rpc, ''))
+ await assert.rejects(wallet.unopened(rpc, 'foo'))
+ await assert.rejects(wallet.unopened(rpc, { 'foo': 'bar' }))
await wallet.destroy()
})