Skip to content

fwd/nano-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

476 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

line

Enterprise Nano Wallet

Zero dependency Nano currency wallet for Browser, Node.js & CLI

Tests npm version npm downloads Zero Dependencies License Node.js Universal

line

Install

NPM:

npm install @nano/wallet

Browser (CDN):

<script src="https://unpkg.com/@nano/wallet"></script>

CLI (global):

npm install -g @nano/wallet

Import

// CommonJS (require)
const nano = require('@nano/wallet')

// ESM (import)
import nano from '@nano/wallet'

// ESM named imports
import { generate, convert, send, receive, change_rep } from '@nano/wallet'

// Browser (global)
// <script src="https://unpkg.com/@nano/wallet"></script>
// Available as window.nano

line

Quick Start

const nano = require('@nano/wallet')

nano.app({
    node: 'https://rpc.nano.to',
    rpc_key: 'YOUR_API_KEY', // free key @ rpc.nano.to
    database: 'encrypted_wallet.txt',
    secret: 'SUPER_SECRET_PASSWORD'
})

;(async () => {

    // Create checkout
    var payment = await nano.checkout({ amount: '0.00133' })

    console.log(payment.browser)

    // Wait for payment
    var success = await nano.waitFor(payment)

    // Receive pending
    var receive = await nano.receive()

    // Send payment
    var send = await nano.send({
        to: 'YOUR_FRIENDS_ADDRESS',
        amount: '0.00133'
    })

    console.log(send)

})()

line

RPC (rpc.nano.to)

This wallet works seamlessly with rpc.nano.to, a free and paid RPC-as-a-Service for the Nano network.

// Free RPC
nano.app({ node: 'https://rpc.nano.to' })

// With API key (higher limits)
nano.app({
    node: 'https://rpc.nano.to',
    rpc_key: 'YOUR_API_KEY'
})

// Raw RPC calls
await nano.rpc({ action: "block_count" })
// { "count": "215474654", "unchecked": "4", "cemented": "215474654" }

await nano.rpc({ action: "account_info", account: "nano_1abc..." })

await nano.rpc({ action: "process", json_block: "true", subtype: "send", block: signedBlock })

line

CLI

npm install -g @nano/wallet

Quick Start — 5 commands to send your first Nano:

# 1. Create a wallet (encrypted locally)
nano-wallet generate --secret mypassword
# Wallet saved to ./nano-wallet.dat
# Address: nano_3abc...
# Mnemonic: word1 word2 word3 ...

# 2. Print your address (easy copy/paste + browser receive link)
nano-wallet address --secret mypassword
# Address: nano_3abc...
# Receive: https://nano.to/nano_3abc...

# 3. Claim free Nano from the built-in faucet
nano-wallet faucet --secret mypassword
# Faucet claimed! 0.001 NANO is on the way.
#   hash: ABC123...
#   to:   nano_3abc...

# 4. Receive the pending Nano
nano-wallet receive --secret mypassword
# Received 1 block(s):
#   0.001 NANO — hash: ABC123...

# 5. Check your balance
nano-wallet balance --secret mypassword

# 6. Change representative (auto-picks a good one)
nano-wallet change_rep --secret mypassword
# or specify one:
# nano-wallet change_rep nano_1anr... --secret mypassword

# 7. Send Nano to anyone
nano-wallet send nano_1to... 0.00005 --secret mypassword
# Sent 0.00005 NANO
#   to:   nano_1to...
#   hash: DEF456...
#   view: https://nanobrowse.com/block/DEF456...

With environment variables (even cleaner):

export NANO_SECRET=mypassword

nano-wallet generate
nano-wallet receive
nano-wallet send nano_1to... 0.001
nano-wallet balance

Utility commands (no wallet needed):

# Convert units
nano-wallet convert 1.5 NANO RAW
nano-wallet convert 1000000000000000000000000000000 RAW NANO

# Raw RPC calls
nano-wallet rpc block_count
nano-wallet rpc account_info account=nano_1abc...

# Check any address (no wallet required)
nano-wallet balance nano_1abc...
nano-wallet account_info nano_1abc...

# Print your address and nano.to receive link
nano-wallet address --secret mypassword

# Claim free test Nano (requires NANO_RPC_KEY)
nano-wallet faucet --secret mypassword
nano-wallet faucet nano_3abc... --secret mypassword   # or pass address directly

# Encrypt / decrypt files
nano-wallet encrypt myfile.json mypassword
nano-wallet decrypt encrypted.txt mypassword

# Sign a block manually
nano-wallet sign '{"walletBalanceRaw":"1000...","toAddress":"nano_1..."}' PRIVATE_KEY

All options:

Options:
  --secret <password>     Wallet password (encrypts/decrypts wallet file)
  --wallet <file>         Wallet file path (default: ./nano-wallet.dat)
  --node <url>            RPC endpoint (default: https://rpc.nano.to)
  --key <api_key>         RPC API key for rpc.nano.to
  --json                  Output raw JSON

Environment Variables:
  NANO_SECRET             Wallet password
  NANO_WALLET             Wallet file path
  NANO_RPC                RPC endpoint
  NANO_RPC_KEY            API key for rpc.nano.to

line

Offline API

nano.generate()
nano.import( nano.generate() )
nano.accounts()
nano.add_account()
nano.sign(block)
nano.convert('421.70', 'NANO', 'RAW') // 421700000000000000000000000000000
nano.encrypt('any_string', process.env.PASSWORD) // AES-256
nano.decrypt('any_string', process.env.PASSWORD) // UTF-8
nano.export()

Wallet Management

Build non-custodial Nano applications with AES-256 encrypted wallet persistence.

nano.app({ 
    node: 'https://rpc.nano.to',
    rpc_key: 'RPC_API_KEY', // get free key @ rpc.nano.to
    database: 'aes_string.txt', 
    secret: 'SUPER_SECRET_PASSWORD'
})

console.log( nano.accounts() )

await nano.receive()

await nano.send({ to: '@faucet', amount: 0.001 })

Multi-Account (Metadata)

nano.app({ 
    node: 'https://rpc.nano.to',
    rpc_key: 'RPC_API_KEY',
    database: 'aes_string.txt', 
    secret: 'SUPER_SECRET_PASSWORD'
})

const user = { userId: 'JoeDoe' }

console.log( nano.add_account(user) )

await nano.receive(user)

var balance = await nano.balance(user)

console.log( balance )

await nano.send({ 
    to: user, 
    from: 0,
    amount: '0.0000133'
})

Balances

// get all balances
await nano.balances()

// get balance of specific address
await nano.balance({ userId: 'johnDoe' })
// {
//     "balance": "325586539664609129644855132177",
//     "pending": "2309372510769300000000000000000000",
//     "receivable": "2309372510769300000000000000000000",
//     "balance_nano": "0.32558653966460912964",
//     "pending_nano": "2309.3725107693",
//     "receivable_nano": "2309.3725107693"
// }

Send

// send to globally known accounts
await nano.send({ to: '@fosse', amount: 0.1 })

// send to multiple accounts
await nano.send({ to: [ '@fosse', '@bank' ], amount: 0.1 })

// send all funds on address
await nano.send({ to: '@fosse', amount: 'all' })

// transfer between your own accounts
await nano.send({ to: 1, from: 0, amount: 0.1 })

// transfer between your own users
await nano.send({ to: { userId: 'johnDoe' }, from: { userId: 'janeDoe' }, amount: 0.1 })

Receive

// receive all
await nano.receive()

// receive all for specific address
await nano.receive({ userId: 'johnDoe' })

Change Representative

// auto-pick a good rep from rpc.nano.to
await nano.change_rep()

// specify a rep address
await nano.change_rep('nano_1anrzcuwe64rwxzcco8dkhpyxpi8kd7zsjc1oeimpc3ppca4mrjtwnqposrs')

// with config object
await nano.change_rep({ rep: 'nano_1anrzcuwe64rwxzcco8dkhpyxpi8kd7zsjc1oeimpc3ppca4mrjtwnqposrs' })
// {
//     "hash": "BLOCK_HASH",
//     "representative": "nano_1anr...",
//     "account": "nano_3abc...",
//     "browser": "https://nanobrowse.com/block/BLOCK_HASH"
// }

When no representative address is provided, the wallet fetches a list of available representatives from rpc.nano.to (via the reps RPC action) and automatically picks one at random.

Checkout

var checkout = await nano.checkout({ address: 0, amount: '0.133' })
console.log( checkout )
// {
//     "id": "CHECKOUT_ID",
//     "browser": "https://nano.to/id_CHECKOUT_ID",
//     "json": "https://api.nano.to/checkout/CHECKOUT_ID",
//     "check": "https://api.nano.to/check/CHECKOUT_ID",
//     "address": "YOUR_ADDRESS",
//     "qrcode": "data:image/png;base64"
// }

var payment = await nano.waitFor(checkout)
console.log( payment )
// {
//     id: 'b06a8127',
//     success: true,
//     block: '3C0D9A50649C6BE...',
//     amount: '0.133',
//     amount_raw: '1330000000000000000000000'
// }

Manual Signing

SEND

var send = nano.sign({
    walletBalanceRaw: '18618869000000000000000000000000',
    toAddress: 'nano_3kyb49tqpt39ekc49kbej51ecsjqnimnzw1swxz4boix4ctm93w517umuiw8',
    representativeAddress: 'nano_1stofnrxuz3cai7ze75o174bpm7scwj9jn3nxsn8ntzg784jf1gzn1jjdkou',
    frontier: '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D',
    transactionHash: 'CBC911F57B6827649423C92C88C0C56637A4274FF019E77E24D61D12B5338783',
    amountRaw: '7000000000000000000000000000000',
}, process.env.PRIVATE_KEY) 

RECEIVE

var receive = nano.sign({
    walletBalanceRaw: '18618869000000000000000000000000',
    toAddress: 'nano_3kyb49tqpt39ekc49kbej51ecsjqnimnzw1swxz4boix4ctm93w517umuiw8',
    representativeAddress: 'nano_1stofnrxuz3cai7ze75o174bpm7scwj9jn3nxsn8ntzg784jf1gzn1jjdkou',
    frontier: '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D',
    transactionHash: 'CBC911F57B6827649423C92C88C0C56637A4274FF019E77E24D61D12B5338783',
    amountRaw: '7000000000000000000000000000000',
    work: 'c5cf86de24b24419',
}, process.env.PRIVATE_KEY) 

var hash = await nano.process( receive )

CHANGE_REP

var change_rep = nano.sign({
    walletBalanceRaw: '3000000000000000000000000000000',
    address: 'nano_3igf8hd4sjshoibbbkeitmgkp1o6ug4xads43j6e4gqkj5xk5o83j8ja9php',
    representativeAddress: 'nano_1anrzcuwe64rwxzcco8dkhpyxpi8kd7zsjc1oeimpc3ppca4mrjtwnqposrs',
    frontier: '128106287002E595F479ACD615C818117FCB3860EC112670557A2467386249D4',
    work: '0000000000000000',
}, process.env.PRIVATE_KEY) 

var hash = await nano.process( change_rep )

Export Wallet

JSON object, stringified and encrypted with AES-256

nano.offline({ 
    filename: 'aes_string.txt', 
    password: process.env.PASSWORD
})

console.log( nano.export() )

line

Zero Dependencies

This package has zero external npm dependencies. All cryptographic libraries are vendored and sandboxed directly in the source:

  • nanocurrency-web-js — Wallet generation, block signing, Ed25519, Blake2b
  • crypto-js — AES-256 encryption (unified across Browser & Node.js)

This eliminates supply chain attack vectors while keeping the package fully self-contained.

line

Upgrading from v1.x

v3 replaced the aes256 npm dependency with the vendored CryptoJS library for encryption. Existing v1.x wallets are automatically migrated when loaded — no action is required in most cases.

Automatic Migration

When nano.offline() or nano.import() detects a legacy wallet, it:

  1. Decrypts with the old format (AES-256-CTR)
  2. Re-encrypts with the new format (AES-256-CBC)
  3. Saves the updated file
// Just load your wallet as usual — migration happens automatically
nano.offline({ database: 'my_old_wallet.txt', secret: 'my_password' })
// Console: @nano/wallet: Migrated wallet from legacy format to AES-256-CBC.

Manual Migration

// Migrate a wallet file without loading it
nano.migrate({ database: 'my_old_wallet.txt', secret: 'my_password' })
// { migrated: true, accounts: 1, file: 'my_old_wallet.txt' }

CLI Migration

# Decrypt legacy wallet and inspect
nano-wallet decrypt my_old_wallet.txt my_password

# Re-encrypt in new format
nano-wallet encrypt decrypted_output.json my_password > my_new_wallet.txt

Note: Browser wallets are unaffected — they always used CryptoJS.

line

Faucet

Claim 0.001 free test NANO in one step. Requires an RPC key from rpc.nano.to.

nano.app({
    node: 'https://rpc.nano.to',
    rpc_key: 'YOUR_RPC_KEY',
    database: 'nano-wallet.dat',
    secret: 'mypassword'
})

// Auto-detect address from loaded wallet
var result = await nano.faucet()

// Or pass an address explicitly
var result = await nano.faucet('nano_3abc...')

console.log(result)
// {
//   success: true,
//   message: '0.001 NANO sent to nano_3abc...',
//   claim: {
//     id: 42,
//     nano_address: 'nano_3abc...',
//     amount: '0.001',
//     status: 'sent',
//     tx_hash: 'ABC123...',
//     created_at: '2026-02-18T12:00:00.000Z'
//   }
// }

GET FREE NANO

License

MIT

line

Sponsor (DigitalOcean)

line

Stargazers

Stargazers over time

About

JavaScript Nano Wallet

Topics

Resources

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •