return true\r
}\r
}\r
-\r
-export class AccountList extends Object {\r
- [index: number]: Account\r
-\r
- get length (): number {\r
- return Object.keys(this).length\r
- }\r
-\r
- *[Symbol.iterator] (): Iterator<Account> {\r
- const indexes = Object.keys(this)\r
- .map(key => parseInt(key))\r
- .filter(index => Number.isFinite(index))\r
- .sort((a, b) => a - b)\r
- for (const i of indexes) {\r
- yield this[i]\r
- }\r
- }\r
-\r
- static {\r
- Object.defineProperty(this, 'length', { enumerable: false })\r
- }\r
-}\r
const recipientAccount = Account.load(recipient)
const accounts = await wallet.refresh(rpc, from, to)
- for (const account of accounts) {
+ for (const [index, account] of accounts) {
const blockRequest: Promise<void> = new Promise(async (resolve) => {
let block
try {
- if (account.index == null) {
+ if (index == null && account.index == null) {
throw new TypeError('Account index is required', { cause: account })
}
block = await new Block(account)
.send(recipientAccount, account.balance ?? 0n)
- .sign(wallet, account.index)
+ .sign(wallet, account.index ?? index)
await block.pow()
const hash = await block.process(rpc)
results.push({ status: 'success', address: block.account.address, message: hash })
//! SPDX-License-Identifier: GPL-3.0-or-later
import { KeyPair, WalletType } from '#types'
-import { Account, AccountList } from '../account'
+import { Account } from '../account'
import { Vault } from '../vault'
-export async function _accounts (type: WalletType, accounts: AccountList, vault: Vault, from: number, to: number): Promise<AccountList>
-export async function _accounts (type: WalletType, accounts: AccountList, vault: Vault, from: unknown, to: unknown): Promise<AccountList> {
+export async function _accounts (type: WalletType, accounts: Map<number, Account>, vault: Vault, index: number): Promise<Account>
+export async function _accounts (type: WalletType, accounts: Map<number, Account>, vault: Vault, from: number, to: number): Promise<Map<number, Account>>
+export async function _accounts (type: WalletType, accounts: Map<number, Account>, vault: Vault, from: unknown, to: unknown = from): Promise<Account | Map<number, Account>> {
if (typeof from !== 'number' || typeof to !== 'number') {
throw new TypeError('Invalid account range', { cause: `${from}-${to}` })
}
if (from > to) [from as number, to as number] = [to, from]
- const output = new AccountList()
+ const output = new Map<number, Account>()
const indexes: number[] = []
for (let i = from; i <= to; i++) {
- if (accounts[i] == null) {
+ const account = accounts.get(i)
+ if (account == null) {
indexes.push(i)
} else {
- output[i] = accounts[i]
+ output.set(i, account)
}
}
if (indexes.length > 0) {
if (a.index == null) {
throw new RangeError('Index missing for Account')
}
- output[a.index] = accounts[a.index] = a
+ output.set(a.index, a)
+ accounts.set(a.index, a)
}
}
+ if (from === to) {
+ const account = output.get(from)
+ if (account === undefined) {
+ throw new Error(`Failed to get account at index ${from}`)
+ }
+ return account
+ }
return output
}
//! SPDX-License-Identifier: GPL-3.0-or-later\r
\r
import { NamedData, WalletType } from '#types'\r
-import { Account, AccountList } from '../account'\r
+import { Account } from '../account'\r
import { Block } from '../block'\r
import { ADDRESS_GAP } from '../constants'\r
import { bytes } from '../convert'\r
throw new TypeError('Invalid wallet type', { cause: type })\r
}\r
Wallet.#isInternal = false\r
- this.#accounts = new AccountList()\r
+ this.#accounts = new Map<number, Account>()\r
this.#id = id ?? crypto.randomUUID()\r
this.#type = type\r
this.#vault = new Vault()\r
* @returns Promise for the Account at the specified index\r
*/\r
async account (index: number = 0): Promise<Account> {\r
- return (await this.accounts(index))[index]\r
+ return await _accounts(this.type, this.#accounts, this.#vault, index)\r
}\r
\r
/**\r
* If `from` is greater than `to`, their values will be swapped.\r
* @param {number} [from=0] - Start index of accounts. Default: 0\r
* @param {number} [to=from] - End index of accounts. Default: `from`\r
- * @returns {Promise<AccountList>} Promise for a list of Accounts at the specified indexes\r
+ * @returns {Promise<Map<number, Account>>} Promise for a list of Accounts at the specified indexes\r
*/\r
- async accounts (from: number = 0, to: number = from): Promise<AccountList> {\r
+ async accounts (from: number = 0, to: number = from): Promise<Map<number, Account>> {\r
return await _accounts(this.type, this.#accounts, this.#vault, from, to)\r
}\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<AccountList>} Promise for accounts with updated balances, frontiers, and representatives\r
+ * @returns {Promise<Map<number, Account>>} Promise for accounts with updated balances, frontiers, and representatives\r
*/\r
- async refresh (rpc: Rpc | string | URL, from: number = 0, to: number = from): Promise<AccountList> {\r
+ async refresh (rpc: Rpc | string | URL, from: number = 0, to: number = from): Promise<Map<number, Account>> {\r
return await _refresh(this, rpc, from, to)\r
}\r
\r
}\r
\r
static #isInternal: boolean = false\r
- #accounts: AccountList\r
+ #accounts: Map<number, Account>\r
#id: string\r
#mnemonic?: ArrayBuffer\r
#seed?: ArrayBuffer\r
//! SPDX-License-Identifier: GPL-3.0-or-later
import { BlockInfo } from '#types'
-import { AccountList } from '../account'
+import { Account } from '../account'
import { Block } from '../block'
import { Rpc } from '../rpc'
import { Wallet } from '../wallet'
-export async function _refresh (wallet: Wallet, rpc: Rpc | string | URL, from: number, to: number): Promise<AccountList>
-export async function _refresh (wallet: Wallet, rpc: unknown, from: unknown, to: unknown): Promise<AccountList> {
+export async function _refresh (wallet: Wallet, rpc: Rpc | string | URL, from: number, to: number): Promise<Map<number, Account>>
+export async function _refresh (wallet: Wallet, rpc: unknown, from: unknown, to: unknown): Promise<Map<number, Account>> {
try {
if (typeof rpc === 'string' || rpc instanceof URL) {
rpc = new Rpc(rpc)
if (from > to) [from as number, to as number] = [to, from]
const accounts = await wallet.accounts(from, to)
const addresses = []
- for (const account of accounts) {
+ for (const [index, account] of accounts) {
addresses.push(account.address)
}
const data = {
const { frontiers } = await rpc.call('accounts_frontiers', data) as { frontiers: { [address: string]: string } }
const { representatives } = await rpc.call('accounts_representatives', data) as { representatives: { [address: string]: string } }
const { blocks } = await rpc.call('blocks_info', { json_block: true, hashes: Object.values(frontiers) }) as BlockInfo
- for (const account of accounts) {
+ for (const [index, account] of accounts) {
account.balance = balances[account.address]?.balance
account.receivable = balances[account.address]?.receivable
account.representative = representatives?.[account.address]
const to = from + batchSize
const accounts = await wallet.accounts(from, to - 1)
const addresses = []
- for (const account of accounts) {
+ for (const [index, account] of accounts) {
addresses.push(account.address)
}
const data = {
}
const { errors } = await rpc.call('accounts_frontiers', data)
if (errors != null) {
- for (let i = from; i < to; i++) {
- const account = accounts[i]
- const value = errors[account.address]
+ for (const a of addresses) {
+ const value = errors[a]
if (value === 'Account not found') {
- return account
+ const account = accounts.values().find(({ address }) => a === address)
+ if (account !== undefined) {
+ return account
+ }
}
}
}
*/
static validate (address: string): asserts address is string
}
-export declare class AccountList extends Object {
- [index: number]: Account
- get length (): number
- [Symbol.iterator] (): Iterator<Account>
-}
/**
* Represents a mnemonic phrase that identifies a wallet as defined by BIP-39.
declare function hash (data: string | string[], encoding?: 'hex'): Uint8Array<ArrayBuffer>
/**
* Signs arbitrary strings with a private key using the Ed25519 signature scheme.
+* The strings are first hashed to a 32-byte value using BLAKE2b.
*
* @param {string | Uint8Array<ArrayBuffer>} key - Hexadecimal-formatted private key to use for signing
* @param {...string} input - Data to be signed
* @param {number} [to=from] - End index of accounts. Default: `from`
* @returns {Promise<AccountList>} Promise for a list of Accounts at the specified indexes
*/
- accounts (from?: number, to?: number): Promise<AccountList>
+ accounts (from?: number, to?: number): Promise<Map<number, Account>>
/**
* Removes encrypted secrets in storage, releases variable references to
* allow garbage collection, and terminates vault worker.
* @param {(Rpc|string|URL)} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks
* @returns {Promise<AccountList>} Promise for accounts with updated balances, frontiers, and representatives
*/
- refresh (rpc: Rpc | string | URL, from?: number, to?: number): Promise<AccountList>
+ refresh (rpc: Rpc | string | URL, from?: number, to?: number): Promise<Map<number, Account>>
/**
* Signs arbitrary strings using the private key of the account at the wallet
* index specified and returns a detached signature as a hexadecimal string.
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)\r
const accounts = await wallet.accounts(1, 2)\r
\r
- assert.equal(accounts.length, 2)\r
+ assert.equal(accounts.size, 2)\r
assert.equal(accounts[1].publicKey, NANO_TEST_VECTORS.PUBLIC_1)\r
assert.equal(accounts[1].address, NANO_TEST_VECTORS.ADDRESS_1)\r
assert.equal(accounts[1].index, 1)\r
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)\r
const accounts = await wallet.accounts(0x70000000, 0x7000000f)\r
\r
- assert.equal(accounts.length, 0x10)\r
+ assert.equal(accounts.size, 0x10)\r
for (let i = 0x70000000; i < 0x7000000f; i++) {\r
const a = accounts[i]\r
assert.exists(a)\r
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)\r
const accounts = await wallet.accounts(2, 3)\r
\r
- assert.equal(accounts.length, 2)\r
+ assert.equal(accounts.size, 2)\r
assert.exists(accounts[2].publicKey)\r
assert.exists(accounts[2].address)\r
assert.equal(accounts[2].index, 2)\r
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)\r
const accounts = await wallet.accounts(0x70000000, 0x7000000f)\r
\r
- assert.equal(accounts.length, 0x10)\r
+ assert.equal(accounts.size, 0x10)\r
for (let i = 0x70000000; i < 0x7000000f; i++) {\r
const a = accounts[i]\r
assert.exists(a)\r
assert.ok('seed' in wallet)\r
assert.ok(await wallet.verify(TREZOR_TEST_VECTORS.MNEMONIC_0))\r
assert.ok(await wallet.verify(TREZOR_TEST_VECTORS.SEED_0))\r
- assert.equal(accounts.length, 4)\r
+ assert.equal(accounts.size, 4)\r
\r
- for (let i = 0; i < accounts.length; i++) {\r
+ for (let i = 0; i < accounts.size; i++) {\r
assert.exists(accounts[i])\r
assert.exists(accounts[i].address)\r
assert.exists(accounts[i].publicKey)\r
assert.ok(wallet.seed === undefined)\r
assert.ok(await wallet.verify(TREZOR_TEST_VECTORS.MNEMONIC_0))\r
assert.ok(await wallet.verify(TREZOR_TEST_VECTORS.ENTROPY_0))\r
- assert.equal(accounts.length, 4)\r
+ assert.equal(accounts.size, 4)\r
\r
- for (let i = 0; i < accounts.length; i++) {\r
+ for (let i = 0; i < accounts.size; i++) {\r
assert.exists(accounts[i])\r
assert.exists(accounts[i].address)\r
assert.exists(accounts[i].publicKey)\r
assert.exists(account.balance)
assert.notEqual(account.balance, '')
assert.equal(typeof account.balance, 'bigint')
- //@ts-expect-error
assert.ok(account.balance >= 0n)
assert.exists(account.frontier)
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)
const accounts = await wallet.refresh(rpc, 0, 2)
- assert.equal(accounts.length, 3)
+ assert.equal(accounts.size, 3)
for (let i = 0; i < 2; i++) {
- assert.exists(accounts[i])
- assert.ok(accounts[i] instanceof Account)
- assert.equal(accounts[i].index, i)
- assert.equal(accounts[i].balance, 0n)
- assert.equal(accounts[i].receivable, 0n)
+ const account = accounts.get(i)
+ assert.exists(account)
+ assert.ok(account instanceof Account)
+ assert.equal(account.index, i)
+ assert.equal(account.balance, 0n)
+ assert.equal(account.receivable, 0n)
}
assert.equal(accounts[0].address, 'nano_1pu7p5n3ghq1i1p4rhmek41f5add1uh34xpb94nkbxe8g4a6x1p69emk8y1d')
assert.equal(accounts[1].address, 'nano_3phqgrqbso99xojkb1bijmfryo7dy1k38ep1o3k3yrhb7rqu1h1k47yu78gz')