]> git.codecow.com Git - libnemo.git/commitdiff
Extract wallet refresh to separate module and refactor to use batch RPC endpoints.
authorChris Duncan <chris@zoso.dev>
Tue, 19 Aug 2025 14:51:00 +0000 (07:51 -0700)
committerChris Duncan <chris@zoso.dev>
Tue, 19 Aug 2025 14:51:00 +0000 (07:51 -0700)
src/lib/wallet/index.ts
src/lib/wallet/refresh.ts [new file with mode: 0644]
test/test.refresh-accounts.mjs

index fc85a6f679e3ea08d9126df37671eb7676d1a927..6f7d2020947e1cc672ff53401f718c9f3626bd30 100644 (file)
@@ -3,6 +3,7 @@
 \r
 import { KeyPair, NamedData, WalletType } from '#types'\r
 import { Account, AccountList } from '../account'\r
+import { _accounts } from './accounts'\r
 import { _backup } from './backup'\r
 import { Block } from '../block'\r
 import { ADDRESS_GAP } from '../constants'\r
@@ -12,12 +13,12 @@ import { Database } from '../database'
 import { _get } from './get'\r
 import { _load } from './load'\r
 import { _lock } from './lock'\r
+import { _refresh } from './refresh'\r
 import { _restore } from './restore'\r
 import { Rpc } from '../rpc'\r
 import { _sign } from './sign'\r
 import { _unlock } from './unlock'\r
 import { Vault } from '../vault'\r
-import { _accounts } from './accounts'\r
 import { _verify } from './verify'\r
 import { _unopened } from './unopened'\r
 \r
@@ -261,21 +262,7 @@ export class Wallet {
        * @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 instanceof URL) {\r
-                       rpc = new Rpc(rpc)\r
-               }\r
-               if (!(rpc instanceof 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
+               return await _refresh(this, rpc, from, to)\r
        }\r
 \r
        /**\r
diff --git a/src/lib/wallet/refresh.ts b/src/lib/wallet/refresh.ts
new file mode 100644 (file)
index 0000000..40373fc
--- /dev/null
@@ -0,0 +1,43 @@
+//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
+//! SPDX-License-Identifier: GPL-3.0-or-later
+
+import { Account, AccountList } from '../account'
+import { Rpc } from '../rpc'
+import { Vault } from '../vault'
+import { Wallet } from '#wallet'
+import { KeyPair } from '#types'
+
+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> {
+       try {
+               if (typeof rpc === 'string' || rpc instanceof URL) {
+                       rpc = new Rpc(rpc)
+               }
+               if (!(rpc instanceof Rpc)) {
+                       throw new TypeError('RPC must be a valid node')
+               }
+               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 accounts = await wallet.accounts(from, to)
+               const addresses = []
+               for (const account of accounts) {
+                       addresses.push(account.address)
+               }
+               const data = {
+                       accounts: addresses
+               }
+               const { balances } = await rpc.call('accounts_balances', data) as { balances: { [address: string]: { balance: string, receivable: string } } }
+               const { frontiers } = await rpc.call('accounts_frontiers', data) as { frontiers: { [address: string]: string } }
+               for (const account of accounts) {
+                       account.balance = balances[account.address]?.balance
+                       account.receivable = balances[account.address]?.receivable
+                       account.frontier = frontiers[account.address]
+               }
+               return accounts
+       } catch (err) {
+               console.error(err)
+               throw new Error('Failed to refresh accounts', { cause: err })
+       }
+}
index 2a0f270ca92b238d35bf19a89c3ad59a6f5ad0da..6f3291c2d84e24b111b55269d1bd893bd270193f 100644 (file)
@@ -27,7 +27,7 @@ if (isNode) {
 const rpc = new Rpc(env.NODE_URL ?? '', env.API_KEY_NAME)
 
 await Promise.all([
-       suite('Refreshing account info', { skip: true }, async () => {
+       suite('Refreshing account info', { skip: false }, async () => {
 
                await test('fetch balance, frontier, and representative', async () => {
                        const wallet = await Wallet.load('BIP-44', NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)
@@ -163,9 +163,9 @@ await Promise.all([
                })
        }),
 
-       suite('Refreshing wallet accounts', { skip: true }, async () => {
+       suite('Refreshing wallet accounts', { skip: false }, async () => {
 
-               await test('should get balance, frontier, and representative for one account', async () => {
+               await test('get balance, frontier, and representative for one account', async () => {
                        const wallet = await Wallet.load('BIP-44', NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)
                        await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)
                        const accounts = await wallet.refresh(rpc)
@@ -184,8 +184,17 @@ await Promise.all([
                        await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)
                        const accounts = await wallet.refresh(rpc, 0, 2)
 
-                       assert.equal(accounts.length, 1)
-                       assert.ok(accounts[0] instanceof Account)
+                       assert.equal(accounts.length, 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)
+                       }
+                       assert.equal(accounts[0].address, 'nano_1pu7p5n3ghq1i1p4rhmek41f5add1uh34xpb94nkbxe8g4a6x1p69emk8y1d')
+                       assert.equal(accounts[1].address, 'nano_3phqgrqbso99xojkb1bijmfryo7dy1k38ep1o3k3yrhb7rqu1h1k47yu78gz')
+                       assert.equal(accounts[2].address, 'nano_3b5fnnerfrkt4me4wepqeqggwtfsxu8fai4n473iu6gxprfq4xd8pk9gh1dg')
 
                        await assert.resolves(wallet.destroy())
                })