# OTC privacy on Solana: Rings, Helius, and Nullbook

Research checked **15 November 2026**. This reference covers the Rings OTC manual and disclosures, all 19 pages of the Helius Privacy section, and the seven methods in its linked indexer reference. The last section distinguishes the mainnet behavior implemented in Nullbook from the release checks that remain.

| Name | What it does |
| --- | --- |
| [Rings OTC](https://otc.rings.run/how-it-works) | An independent trading application. It handles block discovery, negotiation, deal funding, settlement coordination and recovery. |
| [Helius Solana Privacy Rings](https://www.helius.dev/docs/privacy) | A protocol and SDK for private balances and programmable settlement on Solana. It does not run the Rings OTC marketplace. |
| [Nullbook](../README.md) | This app uses encrypted bilateral deal rooms and separate mainnet wallets. Its legacy address-restricted public offers are a different design. [Current flow](private-deals.md) |

**Reading order:** [Rings OTC trade lifecycle](#rings-otc-trade-lifecycle) · [Helius settlement](#how-helius-settlement-works) · [Wallet integration and user flows](#wallet-integration-and-user-flows) · [Developer reference and release status](#developer-reference-and-release-status) · [Implications for Nullbook](#implications-for-nullbook).

## Rings OTC trade lifecycle

1. **List.** The seller chooses the block, pricing and expiry. They can offer the whole block or set a minimum partial fill. An open listing reveals the token and discount, even though the exact size is sealed.
2. **Negotiate.** Buyers send encrypted bids. The seller can accept, counter or decline; partial sales settle independently. In an auction, the public sees a bid count. Bidders rely on the desk to withhold bids until the deadline.
3. **Fund.** Each party funds a one-use deal key it controls. An ordinary deposit exposes the asset and amount. Funding from an existing private balance has different visibility.
4. **Settle or unwind.** Both deal keys sign one atomic transaction. Its outputs deliver tokens to the buyer, net proceeds and any seller-side remainder to the seller, and the fee to the treasury. Before settlement, each side can recover its own contribution if the other leaves. [Rings trade and deal-key manual](https://otc.rings.run/how-it-works) · [Rings disclosures](https://otc.rings.run/disclosures)

**Fees and price.** Rings charges the seller 0.5% on settlement. It separately charges public usage fees: 0.02–3 SOL for an open listing, 0.2 SOL for an invite-only listing, and 0.005 SOL for a buyer’s first offer on a block. The listing fee is waived if the wallet’s $RINGS holding is worth at least 80% of that fee in USD. Network and token-interface costs are separate. Jupiter supplies the reference price: after 30 seconds it is marked stale; after two minutes percentage-based offers cannot be sent or accepted. Below 5 SOL of liquidity, only fixed prices are offered. These are Rings product rules. [Fee and market-price rules](https://otc.rings.run/how-it-works)

**Who learns what.** Rings says it stores ciphertext for proposals but still sees bidder-to-block relationships and timing. Ordinary listings reveal more bidding activity than sealed auctions. A public observer can identify deal signers, time and a treasury output, and may infer terms from a matching deposit or withdrawal. The counterparty knows the terms. The prover handles amounts inside its enclave. Rings says it screens wallets and does not hold users’ keys. Its disclosures describe an upgradeable protocol and a 2-of-5 pause authority; a pause can delay both settlement and withdrawal. [Disclosures: visibility, trust and risk](https://otc.rings.run/disclosures)

**Example for the UI:** At an agreed price of 8 SOL, a 0.5% seller fee is 0.04 SOL; the seller receives 7.96 SOL before any separate costs. If the seller withdraws exactly 7.96 SOL immediately, someone who knows the fee can reconstruct the likely price. A trade receipt should distinguish an **encrypted settlement amount** from an **amount an observer could infer**.

## How Helius settlement works

### What an explorer can see

The default Ring is permissionless and supports SOL, SPL tokens and Token-2022 tokens. A wallet can spend its private funds by signing a Solana transaction; the transaction and its timing still appear on the ledger. Visibility depends on where the funds start and end. The following table describes the **default Ring**. [Transaction flows](https://www.helius.dev/docs/privacy/concepts/overview) · [Privacy guarantees](https://www.helius.dev/docs/privacy/concepts/encryption)

| Operation | Public on Solana | Encrypted |
| --- | --- | --- |
| Deposit from a public wallet | Source, destination, token, quantity, and any deposit memo | Resulting private balance |
| Transfer between two private balances | Sender, recipient, and transaction signature | Token, quantity, memo, and balances |
| Withdraw to a public wallet | Sender, destination, token, quantity, and resulting public balance | Remaining private balance; a memo attached to an encrypted output |

A **Custom Ring** can enforce additional rules, such as requiring another signature or granting an auditor access to activity inside that Ring. A confidential Custom Ring still shows counterparties. In an anonymous Custom Ring, a relayer appears onchain instead of the two parties; the auditor may still see what the policy allows. For Nullbook, an invite-only listing makes no such promise about its eventual settlement. [Ring policies and decryption](https://www.helius.dev/docs/privacy/concepts/encryption)

### Who can read or authorize a payment

The wallet uses separate keys to sign, read encrypted data, and mark outputs spent. With local decryption, the wallet reads its own history. Giving a provider the viewing key allows it to read balances and history without authorizing payments. To show a single transaction to someone else, the sender can share a transaction-specific viewing key. Generating a proof is separate: Helius's wallet guide says the default remote prover processes the transaction's plaintext inputs and nullifier keys inside an attested AWS Nitro enclave. The integration guide describes local proving as forthcoming. Keeping the viewing key on the device does not make proving local. [Key roles](https://www.helius.dev/docs/privacy/concepts/encryption) · [Proof generation](https://www.helius.dev/docs/privacy/integration/wallet#on-proof-generation)

### How a balance changes

A UTXO (unspent transaction output) holds one amount of one asset. The protocol records a commitment to each private output in a shared Merkle tree. A wallet asks the indexer for encrypted outputs, identifies which remain unspent, and adds them up by asset. Spending consumes entire outputs: sending 7 units from an output worth 10 creates 7 for the recipient and 3 in change. A unique marker called a *nullifier* prevents the original 10 from being spent again. Two fills can spend concurrently only if they use different outputs as inputs. The documented SDK selects at most 40 inputs for a transfer; fragmented holdings can first be merged without changing their owner or value. [Private state and UTXOs](https://www.helius.dev/docs/privacy/concepts/utxo)

Solana checks transaction signatures; the Solana Privacy Program verifies proofs and updates the tree. A public deposit escrows tokens through a mint-specific interface; withdrawal releases tokens on the public side. An application program can verify an additional condition, such as a swap's agreed quantities, then invoke the privacy program in the same transaction. [Program architecture](https://www.helius.dev/docs/privacy/concepts/architecture)

### What the example swap demonstrates

In Helius's example the maker locks an order, the taker can fill it before expiry, and the maker can reclaim it afterward. Quantities and price stay hidden, but the maker and source asset are visible when the order is created; both asset identifiers are visible when it resolves. The protocol also supports a transaction with two inputs and four outputs, the shape of Rings OTC’s seal. That shape alone does not implement Rings OTC’s two separately funded deal keys or its signing and unwind rules. Helius says the escrow and swap examples use public test material that lets anyone forge their proofs. They explain a design; they cannot secure real deposits. [Swap design](https://github.com/helius-labs/privacy-ring-examples/blob/main/swap/swap_program.md) · [Example repository](https://github.com/helius-labs/privacy-ring-examples)

## Wallet integration and user flows

### Four integration paths

**An existing wallet.** Registration lets someone use an ordinary Solana address to receive shielded funds. The wallet derives separate viewing and nullifier keys, registers the public components, and keeps the original Solana key for transaction signatures. Registration alone moves no funds. One derivation method uses a deterministic signature as secret key material. Helius instructs wallets to reject third-party requests for that signature. For Nullbook, the question for Privy and each supported external wallet is whether it can perform these operations *inside the wallet* and recover the same keys on restore. A successful login or ordinary transaction signature does not answer that question. [Private wallet integration](https://www.helius.dev/docs/privacy/integration/wallet)

**A new embedded wallet.** Helius describes provisioning a noncustodial wallet when a user signs up, with public and private balances in one application. Its embedded *privacy* wallet is listed as forthcoming. Nullbook should not present that service as a feature of its existing Privy connection. [Embedded private wallet](https://www.helius.dev/docs/privacy/integration/embedded-wallet)

**A fiat ramp.** An operator keeps private inventory for each asset it supports. After receiving fiat offchain, it transfers from that inventory to the customer's private wallet; for cash-out it receives a private transfer and arranges the fiat payout. This changes what a public observer learns, not what the operator knows about its customer. Funding the operator's inventory from a public crypto account still discloses that top-up. [Confidential fiat on- and off-ramp](https://www.helius.dev/docs/privacy/integration/on-off-ramp)

**An enterprise Ring.** A business can choose whether counterparties are visible and specify who may audit, co-sign, freeze, pause, or move funds. In particular, an auditor can read records; a permanent delegate can spend. These powers depend on the selected policy and should be disclosed separately. Helius's enterprise guide describes a release target, not a live guarantee for these controls. [Custom Rings for enterprises](https://www.helius.dev/docs/privacy/integration/enterprise)

### What each wallet operation does

| Operation | What happens and what the user needs to know |
| --- | --- |
| [Deposit](https://www.helius.dev/docs/privacy/guides/deposit) | The owner signs a public transfer into a private balance. The asset, amount, addresses, and any deposit memo are visible. No ZK proof is required. A mint's first deposit can include setup of its token interface, which adds a rent cost for the payer. |
| [Transfer](https://www.helius.dev/docs/privacy/guides/transfer) | The wallet resolves the recipient, selects spendable funds, obtains a proof and submits the signed transaction. In the default Ring, the public sees the two wallets, but not the asset, amount, or encrypted memo. If the recipient is unregistered, label the alternative **Withdraw to public wallet** and request separate authorization. |
| [Withdraw](https://www.helius.dev/docs/privacy/guides/withdraw) | The wallet proves a private spend and directs the released asset to a public address. Show the address, token and amount before signing: those become public, while any change left in the private wallet stays encrypted. |
| [Read balance](https://www.helius.dev/docs/privacy/guides/read-balance) | Fetch matching encrypted outputs and decrypt them in the wallet. Sum the unspent amounts for each asset. Refresh before constructing a spend and after confirmation; a stale balance can include money already spent. |
| [Read history](https://www.helius.dev/docs/privacy/guides/read-history) | Fetch and decrypt the wallet's matching transaction records. Backfill missed activity on unlock, restore or reconnect. A public address search alone does not reveal the decrypted trade history. |

## Developer reference and release status

**Network availability.** Helius launched the permissionless Default Ring on mainnet on November 10, 2026. The [launch announcement](https://www.helius.dev/blog/solana-privacy-rings), [RPC endpoints](https://www.helius.dev/docs/privacy/endpoints), and [address directory](https://www.helius.dev/docs/privacy/addresses) identify the service, program, registry, state tree and native SOL interface. Other token interfaces are mint-specific. An identical program address on another network is not evidence that the wallet has mainnet funds.

**Audit scope.** The [security page](https://www.helius.dev/docs/privacy/security) publishes Certora and zkSecurity reports for the core program and circuits; it lists OtterSec’s report as pending publication. The November 2 trusted setup recorded 15 accepted contributions per circuit. Custom Rings were still undergoing separate audits, with December 2026 the expected completion date. A protocol audit does not cover an OTC application’s custom circuits, wallet integration, or recovery logic.

**Developer tools.** The [SDK page](https://www.helius.dev/docs/privacy/sdk) lists `@heliuslabs/spr` with `@solana/kit` for TypeScript, `spr-client` for Rust clients, and `spr-program` for programs. Pin versions compatible with the deployed program: the [official examples](https://github.com/helius-labs/privacy-ring-examples) identify differences between the published client packages and the deployed program. For source lookup, the [AI tools page](https://www.helius.dev/docs/privacy/ai-tools) describes Markdown exports, Helius documentation search, and a separate DeepWiki connection for the protocol repository.

### Privacy indexer methods

The [Privacy API](https://www.helius.dev/docs/api-reference/privacy) accepts one JSON-RPC request at `/v1/spr/{method}`; the method in the request body must match the path. The same network-specific Helius RPC URL gives SDK clients access to the Solana RPC, indexer and prover. For an isolated local run, the endpoint guide lists RPC on port 8899, indexer on 8784 and prover on 3001. The API key identifies the project. It does not decrypt trade data or authorize spending.

| Method | When to use it |
| --- | --- |
| [getEncryptedUtxosByTags](https://www.helius.dev/docs/api-reference/privacy/getencryptedutxosbytags) | Discover encrypted outputs by tag or ring. Results include historical outputs; a wallet must determine which remain unspent. |
| [getShieldedTransactionsByTags](https://www.helius.dev/docs/api-reference/privacy/getshieldedtransactionsbytags) | Retrieve events grouped by matching transaction for wallet history or a specific ring. |
| [getShieldedTransactionsBySignature](https://www.helius.dev/docs/api-reference/privacy/getshieldedtransactionsbysignature) | Inspect one Solana transaction. An empty result immediately after submission can mean the indexer has not reached its slot. |
| [getShieldedTransactionsByNullifiers](https://www.helius.dev/docs/api-reference/privacy/getshieldedtransactionsbynullifiers) | Locate transactions that spent particular outputs using the nullifiers that mark them spent. |
| [getMerkleProofs](https://www.helius.dev/docs/api-reference/privacy/getmerkleproofs) | Obtain inclusion paths for output commitments in one state tree. Refresh expired roots before building a transaction. |
| [getNonInclusionProofs](https://www.helius.dev/docs/api-reference/privacy/getnoninclusionproofs) | Check absence from a nullifier tree. A spent or queued nullifier cannot be used as if it were new. |
| [getUserRecords](https://www.helius.dev/docs/api-reference/privacy/getuserrecords) | Look up public registrations by wallet owner. A missing record is distinct from a registered wallet with zero balance. |

**Synchronization and cost.** On paginated methods, a page counts transactions (1–1,000), not individual outputs. Reuse the cursor with the same filters. After an unbounded scan ends, save `context.slot` and resume strictly after it; a scan with an upper slot limit covers only that limit. If the indexer returns `-32016`, retry after it catches up instead of recording a missing payment. Helius lists reads at **10 credits per request** and proof generation at **1,000 credits per proof**. These are service charges, separate from Solana fees and any fee Nullbook sets. [Pagination and pricing](https://www.helius.dev/docs/api-reference/privacy#pagination)

## Implications for Nullbook

### Settlement decision: no custom program deployment

Nullbook does not deploy its own program. The [mainnet implementation](private-deals.md) coordinates a seller and buyer offchain, and asks both wallets to approve one transaction against the [existing Helius program](https://www.helius.dev/docs/privacy/addresses). A standing offer that a taker can fill while the maker is offline is outside this design.

### What the app does today

| Area | Implemented behavior | Visibility or limitation |
| --- | --- | --- |
| Discovery | Birdeye supplies token prices. Nullbook Marketplace supports public token listings, multiple encrypted bids, and timed sealed auctions. A seller can select one bid to open a private room. | Seller, mint, deadlines, format and bid count are public. Sealed reveal timing is enforced by the service. There is no automatic matching, multi-buyer partial fill or per-trade wallet generation. A trade requires a supported mint. |
| Wallet | Privy proves account ownership; a separate encrypted backup restores the mainnet spending and inbox keys. | Registration links the connected account to the public mainnet owner in the authenticated directory. Losing the backup or passphrase can mean losing access. |
| Negotiation | Only the two named accounts may read a room. Offers, revisions, proof packets and transaction signatures are authenticated and encrypted between the traders. | The service sees the two accounts, their directory entries, revision, status, timing, ciphertext sizes and eventual transaction signature. Neither negotiation nor marking a side ready locks funds. |
| Settlement | The seller builds the token leg, the buyer builds the SOL leg. Each wallet checks its receivable output and any fee, simulates the combined transaction and signs the same bytes. Only a matching finalized mainnet receipt closes the deal as settled. | Network fees are public. The two signing wallets remain visible. Deposits and withdrawals reveal assets, amounts and addresses. A nonzero desk fee adds transaction-specific viewing disclosure to the counterparty. |
| Recovery | Either trader can restore their backup, sync and withdraw unspent notes without the counterparty. A separate CLI can use the owner’s own Helius project. | Keys are per wallet, not unique per deal. Helius/Solana availability, public SOL for fees and the protocol’s spending rules still apply. |

### Release checks

The [mainnet operations guide](mainnet-operations.md) covers network checks and independent recovery. The active product requires a verified mainnet genesis, mainnet wallet registration and a finalized mainnet receipt to settle a deal. A funded mainnet exchange, recovery and independent security review remain separate release checks; do not interpret the local browser or simulation tests as evidence of them.

1. **Verify wallet support and recovery.** Test backup restoration and spend authorization with each supported signer. A funded exercise on mainnet requires a deliberate choice of asset, quantity and fee budget. An ordinary connection test cannot establish recovery. [Wallet integration requirements](https://www.helius.dev/docs/privacy/integration/wallet)
2. **Verify the co-signed trade.** Use the existing programs for a two-wallet exchange and exercise recovery with each party offline in turn. Two independently submitted transfers are not an atomic swap: a test must show that one leg cannot settle alone. [Rings OTC manual](https://otc.rings.run/how-it-works)
3. **Specify what both sides agree to.** Bind the chain and program, asset identifiers, amounts in base units, fee payer and recipient, expiry, destination wallets and a unique deal identifier to the accepted terms. An edited price or payout address should invalidate earlier approval. Define what the server must store, what stays encrypted for the counterparties, and what the public offer feed may show.
4. **Test the privacy promise with a public observer.** Run a deposit, private transfer, withdrawal and expired deal using isolated fixtures or deliberately budgeted amounts. Compare the explorer, API, application logs, market history and both wallets. Confirm private history stays out of public endpoints and verify what happens if the destination is not registered. Warn before a public withdrawal, not after submission.
5. **Verify money movement independently of the UI.** Exercise partial funding, duplicate submissions, conflicting spends, stale indexer data, unavailable proving, expiry, and interrupted settlement. Confirmation and wallet synchronization can finish at different times. Verify balances after recovery; only show a deal as settled when there is chain evidence. Do not put real funds into the example escrow or swap programs. [Official examples and their security limitations](https://github.com/helius-labs/privacy-ring-examples)
