]> zoso.dev Git - libnemo.git/commitdiff
Using 'Node" as class name interferes with browser Node class, so revert it to 'Rpc'.
authorChris Duncan <chris@zoso.dev>
Sat, 2 Nov 2024 05:59:29 +0000 (22:59 -0700)
committerChris Duncan <chris@zoso.dev>
Sat, 2 Nov 2024 05:59:29 +0000 (22:59 -0700)
README.md
src/lib/account.ts
src/lib/block.ts
src/lib/ledger.ts
src/lib/rpc.ts [moved from src/lib/node.ts with 93% similarity]
src/lib/tools.ts
src/lib/wallet.ts
src/main.ts
test/refresh-accounts.test.mjs
test/tools.test.mjs

index 887278b06c21bbb828a8c8efd97ad33d113ce260..8a10272c58ab92cdd7c7318ac311e5f5f0001474 100644 (file)
--- a/README.md
+++ b/README.md
@@ -174,7 +174,7 @@ try {
 
 #### Caculating proof-of-work from an online service
 ```javascript
-const node = new Node('https://nano-node.example.com/')
+const node = new Rpc('https://nano-node.example.com/')
 try {
        await block.pow('https://nano-node.example.com/')
 } catch (err) {
@@ -184,7 +184,7 @@ try {
 
 #### Processing a block on the network
 ```javascript
-const node = new Node('https://nano-node.example.com', 'nodes-api-key')
+const node = new Rpc('https://nano-node.example.com', 'nodes-api-key')
 try {
        const hash = await block.process('https://nano-node.example.com/')
 } catch (err) {
index 356d1abc73dd7185b024b0bc527284f359f3caa8..7a111d3df7f0f5ae7c7bc4bd86ec8daea50626dc 100644 (file)
@@ -5,7 +5,7 @@ import { blake2b } from 'blakejs'
 import { ACCOUNT_KEY_LENGTH, ALPHABET, PREFIX, PREFIX_LEGACY } from './constants.js'\r
 import { base32, bytes, hex } from './convert.js'\r
 import Ed25519 from './ed25519.js'\r
-import { Node } from './node.js'\r
+import { Rpc } from './rpc.js'\r
 import { Safe } from './safe.js'\r
 \r
 /**\r
@@ -157,13 +157,13 @@ export class Account {
        * A successful response sets the balance, frontier, and representative\r
        * properties.\r
        *\r
-       * @param {Node|string|URL} node - Node information required to call `account_info`\r
+       * @param {Rpc|string|URL} rpc - RPC node information required to call `account_info`\r
        */\r
-       async refresh (node: Node | string | URL): Promise<void> {\r
-               if (typeof node === 'string' || node.constructor === URL) {\r
-                       node = new Node(node)\r
+       async refresh (rpc: Rpc | string | URL): Promise<void> {\r
+               if (typeof rpc === 'string' || rpc.constructor === URL) {\r
+                       rpc = new Rpc(rpc)\r
                }\r
-               if (node.constructor !== Node) {\r
+               if (rpc.constructor !== Rpc) {\r
                        throw new TypeError('RPC must be a valid node')\r
                }\r
                const data = {\r
@@ -172,7 +172,7 @@ export class Account {
                        "representative": "true",\r
                        "weight": "true"\r
                }\r
-               const { balance, frontier, receivable, representative, weight } = await node.call('account_info', data)\r
+               const { balance, frontier, receivable, representative, weight } = await rpc.call('account_info', data)\r
                if (frontier == null) {\r
                        throw new Error('Account not found')\r
                }\r
index f94cb16d0f405a137d97ea4768f3cc76cc138995..4e23a7d02d6bee427f629b35687ec6c84f5a994b 100644 (file)
@@ -5,7 +5,7 @@ import { BURN_ADDRESS, PREAMBLE } from './constants.js'
 import { Account } from './account.js'
 import { bytes, dec, hex } from './convert.js'
 import Ed25519 from './ed25519.js'
-import { Node } from './node.js'
+import { Rpc } from './rpc.js'
 import Tools from './tools.js'
 
 /**
@@ -77,19 +77,19 @@ abstract class Block {
        *
        * A successful response sets the `work` property.
        *
-       * @param {Node|string|URL} node - Node information required to call `work_generate`
+       * @param {Rpc|string|URL} rpc - RPC node information required to call `work_generate`
        */
-       async pow (node: Node | string | URL): Promise<void> {
-               if (typeof node === 'string' || node.constructor === URL) {
-                       node = new Node(node)
+       async pow (rpc: Rpc | string | URL): Promise<void> {
+               if (typeof rpc === 'string' || rpc.constructor === URL) {
+                       rpc = new Rpc(rpc)
                }
-               if (node.constructor !== Node) {
+               if (rpc.constructor !== Rpc) {
                        throw new TypeError('RPC must be a valid node')
                }
                const data = {
                        "hash": this.previous
                }
-               const { work } = await node.call('work_generate', data)
+               const { work } = await rpc.call('work_generate', data)
                this.work = work
        }
 
@@ -152,10 +152,10 @@ abstract class Block {
        * The block must already be signed (see `sign()` for more information).
        * The block must also have a `work` value.
        *
-       * @param {Node|string|URL} node - Node information required to call `process`
+       * @param {Rpc|string|URL} rpc - RPC node information required to call `process`
        * @returns {Promise<string>} Hash of the processed block
        */
-       async process (node: Node): Promise<string> {
+       async process (rpc: Rpc): Promise<string> {
                if (!this.signature) {
                        throw new Error('Block is missing signature. Use sign() and try again.')
                }
@@ -167,7 +167,7 @@ abstract class Block {
                        "json_block": "true",
                        "block": this.json()
                }
-               const res = await node.call('process', data)
+               const res = await rpc.call('process', data)
                if (res.hash == null) {
                        throw new Error('Block could not be processed', res)
                }
index 5cf5bf90dc35cf7c6d2929dfd2a8e2d09fd03725..43fadd18d4838aa32864776f71bd642a8740d6f0 100644 (file)
@@ -11,7 +11,7 @@ import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb'
 import { default as TransportHID } from '@ledgerhq/hw-transport-webhid'
 import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_STATUS_CODES } from './constants.js'
 import { bytes, dec, hex, utf8 } from './convert.js'
-import { Node } from './node.js'
+import { Rpc } from './rpc.js'
 import { ChangeBlock, ReceiveBlock, SendBlock } from './block.js'
 
 export class Ledger {
@@ -339,11 +339,11 @@ export class Ledger {
        *
        * @param {number} index - Account number
        * @param {string} hash - Hexadecimal block hash
-       * @param {Node} node - Node class object with a node URL
+       * @param {Rpc} rpc - Rpc class object with a node URL
        */
-       async updateCache (index: number, hash: string, node: Node): Promise<{ status: string }>
-       async updateCache (index: number, input: any, node?: Node): Promise<{ status: string }> {
-               if (typeof input === 'string' && node?.constructor === Node) {
+       async updateCache (index: number, hash: string, rpc: Rpc): Promise<{ status: string }>
+       async updateCache (index: number, input: any, node?: Rpc): Promise<{ status: string }> {
+               if (typeof input === 'string' && node?.constructor === Rpc) {
                        const data = {
                                'json_block': 'true',
                                'hash': input
similarity index 93%
rename from src/lib/node.ts
rename to src/lib/rpc.ts
index 8bae1b7d743c932e6cef3c45ee63a41aa9747112..752ce1c16a5c4c348f19007623b68fc6f9119d42 100644 (file)
@@ -1,16 +1,14 @@
 // SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>
 // SPDX-License-Identifier: GPL-3.0-or-later
 
-import { Safe } from './safe.js'
-
 /**
 * Represents a Nano network node. It primarily consists of a URL which will
 * accept RPC calls, and an optional API key header construction can be passed if
-* required by the node. Once instantiated, the Node object can be used to call
+* required by the node. Once instantiated, the Rpc object can be used to call
 * any action supported by the Nano protocol. The URL protocol must be HTTPS; any
 * other value will be changed automatically.
 */
-export class Node {
+export class Rpc {
   #u: URL
   #n?: string
 
index 22b01762bb71b872099d4efabe222c8fc7f09144..aa53be5c706b95becde2518f39542da6888efe18 100644 (file)
@@ -7,7 +7,7 @@ import { Account } from './account.js'
 import { UNITS } from './constants.js'
 import { bytes, hex } from './convert.js'
 import Ed25519 from './ed25519.js'
-import { Node } from './node.js'
+import { Rpc } from './rpc.js'
 import { Bip44Wallet, Blake2bWallet, LedgerWallet } from './wallet.js'
 import { SendBlock } from './block.js'
 
@@ -108,28 +108,28 @@ export async function sign (key: string, ...input: string[]): Promise<string> {
 * Collects the funds from a specified range of accounts in a wallet and sends
 * them all to a single recipient address.
 *
-* @param {Node|string|URL} node - Node information required to refresh accounts, calculate PoW, and process blocks
+* @param {Rpc|string|URL} rpc - RPC node information required to refresh accounts, calculate PoW, and process blocks
 * @param {Blake2bWallet|Bip44Wallet|LedgerWallet} wallet - Wallet from which to sweep funds
 * @param {string} recipient - Destination address for all swept funds
 * @param {number} from - Starting account index to sweep
 * @param {number} to - Ending account index to sweep
 * @returns An array of results including both successes and failures
  */
-export async function sweep (node: Node | string | URL, wallet: Blake2bWallet | Bip44Wallet | LedgerWallet, recipient: string, from: number = 0, to: number = from) {
-       if (node == null || wallet == null || recipient == null) {
+export async function sweep (rpc: Rpc | string | URL, wallet: Blake2bWallet | Bip44Wallet | LedgerWallet, recipient: string, from: number = 0, to: number = from) {
+       if (rpc == null || wallet == null || recipient == null) {
                throw new ReferenceError('Missing required sweep arguments')
        }
-       if (typeof node === 'string' || node.constructor === URL) {
-               node = new Node(node)
+       if (typeof rpc === 'string' || rpc.constructor === URL) {
+               rpc = new Rpc(rpc)
        }
-       if (node.constructor !== Node) {
+       if (rpc.constructor !== Rpc) {
                throw new TypeError('RPC must be a valid node')
        }
        const blockQueue = []
        const results: { status: 'success' | 'error', address: string, message: string }[] = []
 
        const recipientAccount = new Account(recipient)
-       const accounts = await wallet.refresh(node, from, to)
+       const accounts = await wallet.refresh(rpc, from, to)
        for (const account of accounts) {
                if (account.representative?.address && account.frontier) {
                        const block = new SendBlock(
@@ -142,9 +142,9 @@ export async function sweep (node: Node | string | URL, wallet: Blake2bWallet |
                        )
                        blockQueue.push(new Promise(async resolve => {
                                try {
-                                       await block.pow(node)
+                                       await block.pow(rpc)
                                        await block.sign(account.index)
-                                       const hash = await block.process(node)
+                                       const hash = await block.process(rpc)
                                        results.push({ status: 'success', address: block.account.address, message: hash })
                                } catch (err: any) {
                                        results.push({ status: 'error', address: block.account.address, message: err.message })
index 4b0c0bd4dff3a73f45567c04a08068ca6a8c2a14..bfa6df2ca594d384a4dc91078ff933b66ed04697 100644 (file)
@@ -7,7 +7,7 @@ import { nanoCKD } from './bip32-key-derivation.js'
 import { ADDRESS_GAP, SEED_LENGTH_BIP44, SEED_LENGTH_BLAKE2B } from './constants.js'\r
 import { bytes, dec } from './convert.js'\r
 import { Entropy } from './entropy.js'\r
-import { Node } from './node.js'\r
+import { Rpc } from './rpc.js'\r
 import { Safe } from './safe.js'\r
 import Tools from './tools.js'\r
 import type { Ledger } from './ledger.js'\r
@@ -88,13 +88,13 @@ abstract class Wallet {
        * 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 {Node|string|URL} node - Node information required to refresh accounts, calculate PoW, and process blocks\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
 \r
-       async getNextNewAccount (node: Node, batchSize: number = ADDRESS_GAP, from: number = 0): Promise<Account> {\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
@@ -103,14 +103,14 @@ abstract class Wallet {
                const data = {\r
                        "accounts": addresses\r
                }\r
-               const { errors } = await node.call('accounts_frontiers', data)\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 new Account(key)\r
                        }\r
                }\r
-               return await this.getNextNewAccount(node, batchSize, from + batchSize)\r
+               return await this.getNextNewAccount(rpc, batchSize, from + batchSize)\r
        }\r
 \r
        /**\r
@@ -118,20 +118,20 @@ abstract class Wallet {
        *\r
        * A successful response will set these properties on each account.\r
        *\r
-       * @param {Node|string|URL} node - Node information required to refresh accounts, calculate PoW, and process blocks\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 (node: Node | string | URL, from: number = 0, to: number = from): Promise<Account[]> {\r
-               if (typeof node === 'string' || node.constructor === URL) {\r
-                       node = new Node(node)\r
+       async refresh (rpc: Rpc | string | URL, from: number = 0, to: number = from): Promise<Account[]> {\r
+               if (typeof rpc === 'string' || rpc.constructor === URL) {\r
+                       rpc = new Rpc(rpc)\r
                }\r
-               if (node.constructor !== Node) {\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 (let i = 0; i < accounts.length; i++) {\r
                        try {\r
-                               await accounts[i].refresh(node)\r
+                               await accounts[i].refresh(rpc)\r
                        } catch (err) {\r
                                accounts.splice(i--, 1)\r
                        }\r
index c4d2553c1818aedf6900f2d38274f108b655fef2..d836cecf7a7d714c978193b3284a482c49ac24c1 100644 (file)
@@ -3,10 +3,10 @@
 
 import { Account } from './lib/account.js'
 import { SendBlock, ReceiveBlock, ChangeBlock } from './lib/block.js'
-import { Node } from './lib/node.js'
+import { Rpc } from './lib/rpc.js'
 import { Rolodex } from './lib/rolodex.js'
 import { Safe } from './lib/safe.js'
 import Tools from './lib/tools.js'
 import { Bip44Wallet, Blake2bWallet, LedgerWallet } from './lib/wallet.js'
 
-export { Account, SendBlock, ReceiveBlock, ChangeBlock, Node, Rolodex, Safe, Tools, Bip44Wallet, Blake2bWallet, LedgerWallet }
+export { Account, SendBlock, ReceiveBlock, ChangeBlock, Rpc, Rolodex, Safe, Tools, Bip44Wallet, Blake2bWallet, LedgerWallet }
index d0ae268588bcd74c54af2a01c3aadfbbfa193858..3983e67516ad14d9a6c239239a26131d9de01b49 100644 (file)
@@ -6,14 +6,14 @@
 import { describe, it } from 'node:test'
 import { strict as assert } from 'assert'
 import { NANO_TEST_VECTORS, STORAGE } from './TEST_VECTORS.js'
-import { Account, Bip44Wallet, Node } from '../dist/main.js'
+import { Account, Bip44Wallet, Rpc } from '../dist/main.js'
 
 // WARNING: Do not send any funds to the test vectors below
 // Test vectors from https://docs.nano.org/integration-guides/key-management/ and elsewhere
 
 const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)
 await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)
-const node = new Node(process.env.NODE_URL, process.env.API_KEY_NAME, process.env.API_KEY_VALUE)
+const node = new Rpc(process.env.NODE_URL, process.env.API_KEY_NAME, process.env.API_KEY_VALUE)
 
 const skip = true
 
@@ -57,7 +57,7 @@ describe('refreshing account info', { skip }, async () => {
        })
 
        it('should throw with invalid node', async () => {
-               const invalidNode = new Node('http://invalid.com')
+               const invalidNode = new Rpc('http://invalid.com')
                const accounts = await wallet.accounts()
                const account = accounts[0]
                await assert.rejects(account.refresh(invalidNode),
index ac9c252c06385c1a233b4e25e1d7be27fe498f33..9e7db5106728976037f2a5c1284a9b3477b6cf0a 100644 (file)
@@ -6,11 +6,11 @@
 import { describe, it } from 'node:test'\r
 import { strict as assert } from 'assert'\r
 import { RAW_MAX, NANO_TEST_VECTORS, STORAGE } from './TEST_VECTORS.js'\r
-import { Bip44Wallet, Account, SendBlock, Node, Tools } from '../dist/main.js'\r
+import { Bip44Wallet, Account, SendBlock, Rpc, Tools } from '../dist/main.js'\r
 \r
 const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)\r
 await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)\r
-const rpc = new Node(process.env.NODE_URL, process.env.API_KEY_NAME, process.env.API_KEY_VALUE)\r
+const rpc = new Rpc(process.env.NODE_URL, process.env.API_KEY_NAME, process.env.API_KEY_VALUE)\r
 \r
 describe('unit conversion tests', async () => {\r
        it('should convert nano to raw', async () => {\r