Skip to content

How it fits together

The SDK sits between your application and three independent parties: a set of contracts on an EVM chain, and three backend services that index and relay on the chain's behalf. None of them holds your keys, and none of them can move your funds.

This page maps who talks to whom, and — just as importantly — what the SDK deliberately never asks.

The whole system

Your application@lelantos-org/sdkNoteSourceFmdClientSubmitterRelayerClientQuoterfetchSwapQuoteChainAdapter+ Prover (local)Backend servicesfmd-webserverread-only indexrelayerthe only service that writesmetaquoterswap routesflushBatch · transfer · withdrawdepositcancelreadsEVM chainMASPthe poolNativeAdapterETH wrap / unwrapSwapWrapperatomic swap legsPermit2canonical, external

Three things are worth reading off that picture.

Proving happens on your machine. The prover is inside the SDK box, not out at a service. No secret — note values, nsk, the notes being spent — ever leaves the process.

Only two parties write to the chain. Your own signer broadcasts deposits and cancellations. The relayer broadcasts everything else. There is no third writer.

The read path and the write path are different services. fmd-webserver is read-only and never sees a transaction; the relayer never serves note data.

Who the SDK talks to

PartySDK entry pointWhat it is asked for
fmd-webserverFmdClient, NoteSourceencrypted notes, commitment chunks, nullifier chunks, sync watermarks
relayerRelayerClient, Submitter, DepositStreamchain registry, fee estimates, spend submission, deposit-flush events
metaquoterfetchSwapQuotebest swap route and minOut
EVM chainChainAdapterasset registry, fee rate, deposit broadcast, escrow reads

The deployment also runs an explorer indexer, a risk-screening API, and a price feed. The SDK contacts none of them — they are not on any wallet path.

What the SDK never asks

Several requests are absent by design, because making them would identify you to whoever answered.

Never askedWhyWhat happens instead
"Is nullifier N spent?"naming a nullifier names a note you ownthe whole spent set is mirrored and filtered locally
"Give me the Merkle path for leaf i"the leaf index identifies the note you are spendingthe tree is rebuilt locally from an append-only chunk feed
"Which notes are mine?"that is the entire privacy propertyevery encrypted note is downloaded and trial-decrypted locally

The third is negotiable and the other two are not. FMD lets you delegate detection to the server in exchange for far less bandwidth — a deliberate, permanent, and non-default trade.

Shielding: the path you broadcast

A deposit is the one operation your own signer sends. It is also the one with a settlement step after mining: escrowed funds are not in the tree until the relayer folds them in.

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

Steps 4 and 5 are why a freshly deposited note is not immediately spendable, and why DepositStream exists.

Spending: the path the relayer broadcasts

A transfer, withdraw, or swap is never sent by your signer. The spend proof binds the relayer's address, so the pool rejects a transaction that any other account submits.

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 sees a valid proof, its public inputs, and the fee note addressed to it. It does not learn which notes were spent, who the payee is, or the amount — those are the circuit's private inputs. What it does learn is your IP address and the timing of your submission.

The relayer is a pluggable, not a dependency

Submitter is an interface. Race several relayers, route through your own, or broadcast directly from an account you control — see Pluggable interfaces. The same is true of NoteSource: the FMD server is the default index, not the only possible one.

What each party can and cannot see

PartyLearnsCannot learn
fmd-webserverthat some client fetched a page of the public feedwhich notes are yours — under the default full strategy
relayeryour IP, submission timing, the fee it is paidspent notes, payee, amount
metaquoterthat someone wants a route for a token pair and sizewho is asking, or whether the swap happens
the chaina deposit's payer and amount; a withdraw's recipient and amountanything about a shielded transfer beyond its existence

Shielding and unshielding are the visible edges. What happens between them is not.

Next