Skip to content

How it fits together ​

The SDK communicates with contracts on an EVM chain and three backend services that index and relay transactions. None of them holds keys or can move funds.

This page shows which component talks to which, what each request contains, and which requests the SDK never makes.

The whole system ​

Your application@lelantos-org/sdkNoteSourceFmdClientSubmitterRelayerClientQuoterquoteSwapChainAdapter+ Prover (local)Backend servicesfmd-webserverread-only indexrelayerthe only service that writesmetaquoterswap routesflushBatch · transfer · withdrawdepositcancelreadsEVM chainMASPthe poolNativeAdapterETH wrap / unwrapSwapWrapperatomic swap legsPermit2canonical, external
  • Proving is local. The prover runs inside the SDK. Secrets — nsk, note values, the notes being spent — never leave the process.
  • Two parties write to the chain. Your signer broadcasts deposits and cancellations. The relayer broadcasts all other transactions.
  • Reads and writes use different services. fmd-webserver is read-only and never receives transactions. The relayer does not serve note data.

Who the SDK talks to ​

PartySDK entry pointRequests
fmd-webserverFmdClient, NoteSourceencrypted notes, commitment chunks, nullifier chunks, sync positions
relayerRelayerClient, Submitter, DepositStreamchain registry, fee estimates, swap wrapper address, spend, swap and generic-execution submission, deposit flush events
metaquoterquoteSwap, fetchSwapQuoteswap route and minOut
EVM chainChainAdapterasset registry, fee rates, deposit broadcast, escrow state, handle records

The deployment also runs an explorer indexer, a risk-screening API, and a price feed. The SDK does not contact them.

Requests the SDK never makes ​

These requests would identify the wallet's notes to the server, so the SDK performs the work locally:

Request not madeReasonLocal alternative
"Is nullifier N spent?"a nullifier identifies a note the wallet ownsdownload the full spent set and check locally
"Merkle path for leaf i"the leaf index identifies the note being spentrebuild the tree from the append-only chunk feed
"Which notes are mine?"reveals the wallet's notesdownload all encrypted notes and trial-decrypt locally

The third can be delegated: the matches sync strategy sends a detection key to the server to reduce bandwidth. The delegation is opt-in and cannot be revoked.

Deposit flow ​

A deposit is broadcast by your signer. After it is mined, the funds are in escrow until the relayer adds the note to the tree.

Wallet (SDK)MASPrelayerfmd-webserversign permit1 — EIP-2612 / Permit2 witness, bound to this deposit2 deposit() — funds escrowedDepositEscrowed(id) — mined, not yet spendable3 flushBatch()4 SSE: flushed — the note is now in the treelogs indexed5 sync() — encrypted notes + commitment chunks

A new note is spendable only after steps 4 and 5. awaitDeposit waits for both; DepositStream observes step 4 directly.

The relayer's fee for step 4 is part of the deposit. Every deposit creates two leaves, both bound by the signature in step 1:

  • the depositor's note;
  • a fee note addressed to the relayer.

The fee note can use a different registered asset (feeAsset). The request records it as feeAssetId, and the pool transfers both tokens from the payer in the same transaction. The protocol fee is always in the deposited asset. If the relayer charges nothing, the fee leaf is a zero-value note sealed to an address drawn for it, which no one holds, and feeAssetId is 0.

Spend flow ​

Transfers, withdrawals, and swaps are broadcast by the relayer, never by your signer. The spend proof binds the relayer's address, so the pool rejects the transaction from any other sender.

Wallet (SDK)MASPrelayerfmd-webserver1 sync() — notes, commitment chunks, nullifier chunks2 quoteFee() — what relaying costsselect notesGroth16 prove3 — entirely local; no secret leaves the process4 submit() — proof + public inputs + shielded fee note5 transfer() / withdraw()+ tree-update SNARKnullifiers + commitments indexed

The relayer receives the proof, its public inputs, and its fee note. The spent notes, payee, and amount are private circuit inputs and are not revealed. The relayer does see the submitter's IP address and the submission time.

The relayer and the FMD server are defaults, not requirements. Submitter and NoteSource are interfaces: you can use several relayers, run your own, submit directly from your own account, or use a different indexer. See Pluggable interfaces.

Visibility by party ​

PartyCan seeCannot see
fmd-webserverthat a client fetched a page of the public feedwhich notes belong to the wallet (with the default full strategy)
relayerIP address, submission time, its feespent notes, payee, amount
metaquoterthe token pair and size of a requested routethe requester's identity, and whether the swap is executed
the chaindeposit payer and amount; withdrawal recipient and amount; a handle and the address published under itthe contents of shielded transfers, other than that they occurred; who registered a handle
your RPC providerwhich handle a client looks up, and whenwhich payment, if any, follows a lookup, unless it also serves the relayer

Deposits, withdrawals and handle registrations are publicly visible. Shielded transfers are not.

What each service can and cannot do ​

No service holds a key, so none can spend. What each can still do, and what the SDK offers against it:

ServiceCannotCanCheck
relayerchange the recipient, the amount or any output, or the label, address or controller of a handle registration: the proof binds themquote any fee; refuse to relay; see a registration's label before it landsmaxFee on a spend, acceptRelayerFee on the wallet — Fees
fmd-webservermake a spend land: a proof against a tree the pool does not hold is rejected on chainwithhold a note; serve a well-formed note the pool never insertedconfirmCommitment before crediting a payment — Watch-only wallets
artifact host—serve another proving key, whose proofs can leak the witnessdigest pinning — Browser usage

A wallet that only displays a balance needs none of these. One that pays unattended, or releases goods on a payment, should use the first two.

Next ​