Documentation

Reference

View as Markdown

@paralock/lightwalletd

Reference for LightwalletdClient, a ZcashNode backed by a lightwalletd or Zaino gRPC server, so swaps don't need a full Zcash node.

@paralock/lightwalletd lets a lightwalletd-compatible gRPC server (lightwalletd or Zaino) act as the Zcash backend for Paralock swaps. You don't have to run or sync a full node.

LightwalletdClient implements ZcashNode from @paralock/zcash, so you can pass it anywhere the SDK takes a Zcash node.

Install

Shell
npm install @paralock/lightwalletd

Version 0.1.0. Node.js 20 or newer only (it uses gRPC through @grpc/grpc-js). The service definitions ship in the package's proto/ directory.

Example

TypeScript
import { LightwalletdClient } from "@paralock/lightwalletd";
import { createTaker } from "@paralock/sdk";

const zcash = new LightwalletdClient("testnet.zec.rocks:443"); // TLS on port 443

const taker = createTaker({
  zcash: { network: "testnet", node: zcash, key: process.env.ZEC_KEY! },
  evm: { tempo: moderato },
  maker: "https://maker.example",
  store: "./paralock-taker",
});

const utxos = await zcash.getAddressUtxos([taker.zcashAddress]);
console.log(`${utxos.reduce((n, u) => n + u.value, 0n)} zat confirmed`);
// …quote and swap as usual, then:
zcash.close();

Swap on public testnets walks through a full testnet swap that uses this client.

LightwalletdClient

TypeScript
class LightwalletdClient implements ZcashNode {
  constructor(url: string, options?: LightwalletdOptions);
  readonly url: string;
  readonly target: string; // host:port the channel connects to
  readonly tls: boolean;
  close(): void;
  getLightdInfo(): Promise<LightdInfo>;
}
OptionTypeDefaultMeaning
tlsbooleanby URLUse TLS. Default: true, except for http:// and grpc:// URLs and loopback hosts (localhost, 127.x.x.x, ::1), which use plaintext.
timeoutMsnumber30_000Deadline of each call, in milliseconds. A streaming call must finish within it.
retriesnumber3Extra attempts after a transport failure: gRPC UNAVAILABLE, DEADLINE_EXCEEDED or RESOURCE_EXHAUSTED (rate limited).
retryDelayMsnumber250First retry delay. Doubles each attempt, with jitter, capped at 5 s.
log(message: string) => voidconsole.warnWarnings, such as a server that can't report network upgrades.

Call close() when you are done: it closes the gRPC channel. getLightdInfo() returns the server's GetLightdInfo answer (chain name, block height, consensus branch id, next upgrade).

URL forms

URLTransportDefault port
https://host[:port], grpcs://host[:port]TLS443
http://host[:port], grpc://host[:port]plaintext9067
host[:port]TLS, or plaintext for a loopback host443 (TLS), 9067 (plaintext)

A path after the host is not allowed. The tls option overrides the scheme.

TypeScript
new LightwalletdClient("testnet.zec.rocks:443"); // TLS
new LightwalletdClient("https://zec.rocks"); // TLS, port 443
new LightwalletdClient("http://127.0.0.1:9067"); // plaintext: the local devnet's lightwalletd

Method mapping

ZcashNode methodgRPC callNotes
getBlockCountGetLatestBlock
getNextBranchIdGetLightdInfo.consensusBranchIdThrows if a network upgrade activates at the next block: retry after it is mined.
upgradeBeforeGetLightdInfo.upgradeName / upgradeHeightbranchId is always 0 (not reported). Needs a server that reports lightwalletProtocolVersion; older servers skip the check with one warning.
getAddressUtxosGetAddressUtxosConfirmed UTXOs.
getAddressTxidsGetTaddressTransactionsFalls back to GetTaddressTxids on older servers. Txids are computed locally; v6 txids come from GetBlockRange compact blocks.
findSpendGetTaddressTransactionsScans the address's mined transactions for the spend.
getRawTransactionGetTransactionconfirmations is computed from the tip; 0 while in the mempool.
sendRawTransactionSendTransactionReturns the locally computed txid. "Already known" counts as success.
getTxOutnot implemented
generatenot implemented

Differences from a full node

  • No getTxOut. The swap engines check confirmed UTXOs instead, so a spend that is still in the mempool isn't seen until it is mined.
  • Mined history only. Address queries return mined transactions.
  • Txids are computed locally. lightwalletd streams raw transactions without their ids. This package hashes v1 to v4 (double SHA-256) and v5 (ZIP 244, including the Sapling and Orchard digests; tested against the official vectors). For v6 transactions it takes the txid from the server's compact blocks.
  • v6 transactions can't be decoded. getRawTransaction rejects them. Paralock's own lock, claim and refund transactions are v5.
  • Upgrade check. It needs a server that reports lightwalletProtocolVersion. Older servers skip the check, with a warning.

Errors

TypeScript
class LightwalletdError extends Error {
  readonly method: string; // the gRPC method, e.g. "SendTransaction"
  readonly code: number; // gRPC status code, or the node's error code for SendTransaction
  get alreadyKnown(): boolean;
}

Thrown for a gRPC failure (after retries) or for a transaction the server refused (SendTransaction with a non-zero error code). alreadyKnown is true when a broadcast was refused because the node already has the transaction; sendRawTransaction treats that as success itself.

Plain Errors are thrown when the server returns a different transaction or txid than requested, reports an invalid branch id, or when an upgrade activates at the next block.

Txid utilities

ExportSignatureMeaning
txidOftxidOf(data: Uint8Array | string): stringThe txid of a raw transaction (v1 to v5), display-order hex.
decodeTxdecodeTx(data: Uint8Array | string): DecodedTx{ txid, version, inputs: RawInput[] }. Parses every version to its last byte (v1 to v4 structurally, including Sprout JoinSplits and Sapling descriptions) and throws on trailing or missing data, so a txid is only computed over one whole transaction. Throws UnsupportedVersionError for v6 and later.
RawInput{ prevTxid?: string; vout?: number; scriptSig: Uint8Array }A transparent input. Coinbase inputs have no prevTxid.
UnsupportedVersionErrorversion: numberA transaction version this module can't decode.
shieldedDigestsshieldedDigests(raw: Uint8Array): ShieldedDigestsZIP 244 Sapling and Orchard digests of a v5 transaction's shielded part.
TypeScript
import { UnsupportedVersionError, decodeTx } from "@paralock/lightwalletd";

try {
  const { txid, version, inputs } = decodeTx(rawHex);
  console.log(txid, version, inputs.length);
} catch (err) {
  if (err instanceof UnsupportedVersionError) console.log(`v${err.version}: not decodable here`);
  else throw err;
}

Servers

Public servers run by the Zcash community:

NetworkServer
Testnettestnet.zec.rocks:443
Mainnetzec.rocks:443, na.zec.rocks:443, eu.zec.rocks:443, ap.zec.rocks:443, sa.zec.rocks:443

The local devnet runs lightwalletd at http://127.0.0.1:9067 (see CLI).