Reference
The Setrya signer
The light-client wallet that builds, inspects, signs and broadcasts payments, and the rules it enforces.
On this page
The Setrya signer, setrya-signer, is the wallet that pays your partners. It is a light-client Zcash wallet built on librustzcash, the Zcash project's Rust libraries, and it runs on your settlement host next to the API. It holds one account, builds every payment as a PCZT (a partially created Zcash transaction), checks it against Setrya's privacy rule, proves it, signs it and broadcasts it. Setrya's API talks to it over a private network and never sees its keys.
Why it exists
Setrya was designed around Zallet, the Zcash full-node wallet, running next to a Zebra node. As of October 2026 that pairing cannot follow the testnet:
- Testnet activated NU7 at height 4,465,026. Zebra 7.0.0 follows it and moved its state database to format v29.
- Zallet's latest release, v0.1.0-beta.3, reads only the v28 format (zcash/zallet#887). Its chain backend also runs only on Linux.
The signer needs no full node, which also saves the tens of gigabytes a Zebra state takes. It answers the same RPC methods Setrya's adapter calls on Zallet and Zebra, so switching back later means changing two URLs. Architecture covers both backends.
What a lightwalletd server learns
The signer reads the chain from a public lightwalletd server, testnet.zec.rocks:443 on testnet and zec.rocks:443 on mainnet by default.
| The server sees | The server cannot see |
|---|---|
| Your server's IP address and when it connects | Amounts |
| The wallet's birthday height, needed to start the note tree | Recipients |
| The raw bytes of every transaction you broadcast | Memos |
| Which transaction IDs you look up | Which notes belong to you, since decryption happens on your server |
A dishonest server could also withhold or misreport chain data, which a full node you run yourself would rule out. To hide your IP address, route the signer through Tor by setting a SOCKS5 proxy, for example 127.0.0.1:9050, with --socks5 at init or socks5 in config.toml.
Rules it enforces
The signer refuses anything outside Setrya's FullPrivacy rule, so a bug or a compromised caller further up cannot weaken it.
pczt_createaccepts only theFullPrivacypolicy with fund sourceorchard. Anything else is refused with error-8.- It spends only Ironwood notes. It never spends legacy Orchard notes, because moving them reveals the amount (ZIP 318), and never Sapling or transparent funds.
- Change goes back to Ironwood.
- Every recipient must be a unified address on the configured network with an Orchard receiver. Since NU6.3, an Orchard receiver is paid inside Ironwood.
- After building, the signer reads the PCZT back and refuses it if any transparent, Sapling or Orchard output slipped in.
- Amounts are decimal ZEC with at most 8 decimal places, greater than zero and within the 21 million ZEC supply. Exponent notation is refused.
pczt_inspectreportsprivacy_policy: "FullPrivacy"only for PCZTs this process built. Setrya's own review treats anything else as a failure.pczt_signandpczt_extractrefuse PCZTs this process did not build.pczt_extractstores the transaction in the wallet and returns its hex and txid. It never broadcasts. Broadcasting is a separatesendrawtransactioncall, so Setrya can store the signed bytes first.
Commands
| Command | What it does |
|---|---|
setrya-signer init --network test --data-dir DIR |
Creates the wallet with one account named payer. Prints a 24-word recovery phrase once, the account UUID and an Orchard-only receiving address |
setrya-signer serve --data-dir DIR --listen 127.0.0.1:28232 |
Syncs every 20 seconds and serves RPC |
setrya-signer address --data-dir DIR |
Prints a receiving address. Orchard-only by default |
setrya-signer balance --data-dir DIR |
Prints spendable balances by pool, in zatoshis |
init options
| Option | Meaning |
|---|---|
--network test or --network main |
The network the wallet uses. It cannot change later |
--birthday H |
The first block height to scan. The default is the chain tip minus 100 |
--lightwalletd host:port |
A different lightwalletd server |
--socks5 host:port |
Route every connection through this SOCKS5 proxy |
To restore a wallet, pipe its recovery phrase to init on standard input and pass the original --birthday, so the scan starts early enough to find your funds.
serve options
| Option | Meaning |
|---|---|
--listen ADDR |
Where RPC listens. The default is 127.0.0.1:28232 |
--allow-private-bind |
Allow a private network address, such as a container network |
--cookie-file PATH |
Where to write the RPC cookie. The default is DATA_DIR/.cookie |
--cookie-group-readable |
Write the cookie as mode 0640, so a client in the signer's group can read it |
The signer refuses to listen on a public address or on every interface (0.0.0.0). A private address needs --allow-private-bind.
address options
| Option | Meaning |
|---|---|
--receiver orchard |
The default. Funds land in Ironwood and can pay right away |
--receiver sapling |
A Sapling address, for a funder that cannot create Orchard or Ironwood outputs |
--receiver transparent |
A transparent address, for a funder that can only pay transparent addresses. Everything about a transparent payment is public |
Sapling and transparent funds cannot pay under FullPrivacy. They have to be moved into Ironwood first, which reveals the amount.
Data directory
| File | Contents |
|---|---|
config.toml |
Network, lightwalletd server, optional SOCKS5 proxy, birthday |
identity.txt |
The age identity that decrypts the seed, mode 0600 |
seed.age |
The recovery phrase, age-encrypted |
wallet.sqlite |
The wallet database |
.cookie |
The RPC credential, rewritten at every start, unless --cookie-file moves it |
Write the recovery phrase down and keep it offline. identity.txt and seed.age together are as sensitive as the phrase itself, so keep the directory on a volume only the service user can read. Backups and recovery covers what to back up.
RPC methods
Every request is JSON-RPC 2.0 over HTTP POST, with HTTP Basic auth __cookie__:<secret> from the cookie file, the scheme Zallet and Zebra use. A missing or wrong credential gets HTTP 401.
| Group | Methods | Notes |
|---|---|---|
| Wallet | rpc.discover, getwalletstatus, getwalletinfo, z_listaccounts, z_getaddressforaccount, z_getbalanceforaccount |
getwalletstatus reports locked: true until the wallet has scanned to the tip |
| PCZT flow | pczt_create, pczt_inspect, pczt_prove, pczt_sign, pczt_extract |
Parameter order and result fields follow Zallet |
| History | z_viewtransaction, z_listtransactions |
Transactions that involve this wallet |
| Chain | getinfo, getblockchaininfo |
Answered from lightwalletd, shaped like Zebra's |
| Chain | sendrawtransaction, getrawtransaction, getrawmempool |
getrawtransaction leaves out height and confirmations while the transaction is in the mempool, and returns -5 when it is unknown |
Error codes
| Code | Meaning |
|---|---|
-32601 |
Unknown method |
-32602 |
Invalid parameters, such as an unreadable PCZT |
-8 |
Policy refusal: wrong privacy policy or fund source, a rejected recipient, a bad amount |
-6 |
Insufficient funds, with the amount needed including the fee |
-5 |
No such transaction in the mempool or the chain |
Known limits
- This librustzcash revision sets no NU7 height for mainnet. The pinned revision has to be upgraded before mainnet reaches its NU7 height.
- One account per data directory.
- Proving keys are built on the first proof after a start, which takes tens of seconds. Setrya's adapter retries once after a timeout.
z_viewtransactionreports status and confirmations only, without detail for each output.- Received funds become spendable after the wallet's default confirmation policy: 3 confirmations for the wallet's own change and 10 for funds received from others.