Wallet Setup

Create, configure, and sync 1Sat wallets for Node.js, browser, or remote environments.

Packages

Package Environment Storage
@1sat/wallet-node Node.js / Bun SQLite (Knex) or MySQL
@1sat/wallet-browser Browser IndexedDB
@1sat/wallet-remote Any (thin client) Remote server only
@1sat/wallet Core library Indexers, backup, address sync

Node.js Wallet

import { createNodeWallet } from '@1sat/wallet-node'

const { wallet, services, monitor, destroy, fullSync } = await createNodeWallet({
  privateKey: 'L1...', // PrivateKey instance, WIF string, or hex string
  chain: 'main',       // 'main' | 'test'
  storageIdentityKey: 'my-cli-agent', // unique per device, persist across sessions
  // Optional:
  storage: {           // Knex.Config — default: SQLite at ./wallet.db
    client: 'mysql2',
    connection: { host: '127.0.0.1', user: 'root', password: '...', database: 'wallet' },
    useNullAsDefault: true,
  },
  remoteStorageUrl: 'https://storage.example.com', // enables cloud backup
  feeModel: { model: 'sat/kb', value: 100 },       // default shown
  onTransactionBroadcasted: (txid) => console.log('Broadcast:', txid),
  onTransactionProven: (txid, blockHeight) => console.log('Proven:', txid, blockHeight),
})

// Monitor handles tx lifecycle (broadcasting, proof checking)
// It is created but NOT started — call startTasks() when ready
monitor.startTasks()

// When done: stops monitor, destroys wallet, closes database
await destroy()

NodeWalletResult

Property Type Description
wallet Wallet BRC-100 wallet instance
services OneSatServices 1Sat API access
monitor Monitor Transaction lifecycle monitor (call startTasks())
destroy () => Promise<void> Cleanup: stops monitor, destroys wallet, closes DB
fullSync ((onProgress?) => Promise<FullSyncResult>) | undefined Only available if remoteStorageUrl was provided and connected
storage WalletStorageManager For diagnostics
remoteStorage StorageClient | undefined For diagnostics

Browser Wallet

import { createWebWallet } from '@1sat/wallet-browser'

const { wallet, services, monitor, destroy, fullSync } = await createWebWallet({
  privateKey: identityWif,        // PrivateKey | WIF string | hex string
  chain: 'main',
  storageIdentityKey: 'device-unique-id', // different per device
  // Optional:
  remoteStorageUrl: 'https://storage.example.com',
  onMonitorEvent: (event) => console.log(event.type, event),
})

monitor.startTasks()

WebWalletConfig is identical to NodeWalletConfig except it uses IndexedDB (no storage Knex option) and adds an onMonitorEvent callback for structured lifecycle events.

Remote Wallet

No local storage. The server handles transaction lifecycle.

import { createRemoteWallet } from '@1sat/wallet-remote'

const { wallet, services, destroy, feeModel } = await createRemoteWallet({
  privateKey: 'L1...',
  chain: 'main',
  remoteStorageUrl: 'https://my-wallet-server.example.com',
  // Optional:
  feeModel: { model: 'sat/kb', value: 100 },
  connectionTimeout: 5000, // default: 5000ms
})

RemoteWalletResult has no monitor or fullSync — the server manages those. It includes feeModel indicating the effective fee model used.

Full Sync (Multi-Device Handoff)

fullSync reconciles local and remote storage. It pushes local changes, resets sync state, then pulls everything from the server. This runs automatically during wallet creation when another device is active, or can be called manually via the fullSync property on the wallet result.

// Only available if remoteStorageUrl was provided and connected
if (fullSync) {
  const result = await fullSync((stage, message) => {
    console.log(`${stage}: ${message}`)
  })
  console.log('Pushed:', result.pushed) // { inserts, updates }
  console.log('Pulled:', result.pulled) // { inserts, updates }
}

FullSyncOptions (internal)

The standalone fullSync() function takes { storage, remoteStorage, identityKey, onProgress?, maxRoughSize?, maxItems? }. The factory functions wrap this for you.

FullSync Stages

Stage Description
pushing Pushing local data to remote server
resetting Resetting sync state for clean pull
pulling Pulling all data from remote
complete Sync finished

Derivation Paths

import {
  YOURS_WALLET_PATH, YOURS_ORD_PATH, YOURS_ID_PATH,
  getKeysFromMnemonicAndPaths, deriveIdentityKey,
} from '@1sat/utils'
Constant Path Purpose
YOURS_WALLET_PATH m/44'/236'/0'/1/0 Yours Wallet payment
YOURS_ORD_PATH m/44'/236'/1'/0/0 Yours Wallet ordinals
YOURS_ID_PATH m/0'/236'/0'/0/0 Yours Wallet identity
RELAYX_ORD_PATH m/44'/236'/0'/2/0 RelayX ordinals
RELAYX_SWEEP_PATH m/44'/236'/0'/0/0 RelayX sweep
TWETCH_WALLET_PATH m/0/0 Twetch payment
AYM_WALLET_PATH m/0/0 AYM payment
AYM_ORD_PATH m AYM ordinals (master key)
// Derive keys from mnemonic
const keys = getKeysFromMnemonicAndPaths(mnemonic, {
  changeAddressPath: YOURS_WALLET_PATH,
  ordAddressPath: YOURS_ORD_PATH,
  identityAddressPath: YOURS_ID_PATH,
})
// keys.payPk (WIF), keys.ordPk (WIF), keys.identityPk (WIF)

// Derive identity key from pay + ord WIFs
const identityKey = deriveIdentityKey(keys.payPk, keys.ordPk)

Address Sync

Address sync uses a fetcher/processor split for Chrome extension compatibility (SSE does not work in service workers). Use AddressSyncManager in unified environments.

import { AddressSyncManager, AddressSyncQueueIdb } from '@1sat/wallet'

const syncManager = new AddressSyncManager({
  wallet,
  services,
  syncQueue: new AddressSyncQueueIdb(), // or AddressSyncQueueSqlite
  addressManager,                        // AddressManager instance
  network: 'mainnet',                    // 'mainnet' | 'testnet'
  batchSize: 20,                         // optional, default 20
})

syncManager.on('sync:progress', ({ pending, done, failed }) => {
  console.log(`Pending: ${pending}, Done: ${done}, Failed: ${failed}`)
})

await syncManager.sync() // opens SSE stream + processes queue
syncManager.stop()

For Chrome extensions, use AddressSyncFetcher (popup context) and AddressSyncProcessor (service worker) separately.

Backup & Restore

Backup uses a streaming Zip-based API via fflate. FileBackupProvider implements WalletStorageProvider to receive sync chunks during export.

import { FileBackupProvider, FileRestoreReader, Zip, ZipDeflate, unzip } from '@1sat/wallet'

// === BACKUP ===
const chunks: Uint8Array[] = []
const zip = new Zip((err, data, final) => {
  if (err) throw err
  chunks.push(data)
  if (final) {
    const blob = new Blob(chunks, { type: 'application/zip' })
    // save or download blob
  }
})

const provider = new FileBackupProvider(zip, storage.getSettings(), identityKey)
await storage.syncToWriter(auth, provider)
// Write manifest.json to zip, then zip.end()

// === RESTORE ===
const zipData = new Uint8Array(await file.arrayBuffer())
const unzipped = await new Promise<Unzipped>((resolve, reject) => {
  unzip(zipData, (err, data) => (err ? reject(err) : resolve(data)))
})
const manifest = JSON.parse(new TextDecoder().decode(unzipped['manifest.json']))
const reader = new FileRestoreReader(unzipped, manifest)
await storage.syncFromReader(manifest.identityKey, reader)

Wallet Indexers

These run automatically during address sync. No configuration needed.

Indexer What it tracks
InscriptionIndexer Ordinal inscriptions
Bsv21Indexer BSV-21 fungible tokens
OrdLockIndexer Marketplace listings
LockIndexer Time-locked BSV
MapIndexer MAP protocol metadata
SigmaIndexer Sigma protocol signatures
OriginIndexer Ordinal origin tracking
OpNSIndexer OpNS name bindings
CosignIndexer Cosigner data
FundIndexer Funding outputs (P2PKH)

Installation

bun add @1sat/wallet-node    # Node.js / Bun
bun add @1sat/wallet-browser # Browser
bun add @1sat/wallet-remote  # Remote (thin client)

All environment packages depend on @1sat/wallet (core) which provides indexers, backup, and address sync.