All explainers

2026-05-26

What are the fees and where do they go?

Depositing into SolMask is free. The protocol charges its fee when you withdraw, in two parts — both on-chain, both enforced by the program, both admin-tunable. There are no hidden charges, no spread on the swap path, and no per-asset variation. The numbers below are enforced on-chain by the protocol.

Deposits: free

When you deposit into a SolMask pool, the full amount enters the shielded vault. Nothing is skimmed on the way in — the amount you commit to in your shielded note is exactly what you deposited. Deposit 1 SOL and your note is worth 1 SOL; deposit 1,000 USDC and your note is worth 1,000 USDC.

The withdraw percentage fee: in the withdrawn asset

When you withdraw, the protocol charges a small percentage — Config.withdraw_fee_bps, an admin-tunable rate capped at 100 basis points (1.00%). At the recommended 23 bps (0.23%) it works out to fee = withdrawn_amount * 23 / 10_000. The fee is taken in whatever asset you're withdrawing — SOL from a SOL withdraw, USDC from a USDC withdraw — and accrues to a per-pool token fee vault PDA owned by the pool.

This percentage is bound inside the withdraw zero-knowledge proof: the circuit proves that your spent notes equal the released output plus the fee plus any change, and the program independently recomputes the expected fee from the on-chain rate and rejects any mismatch. Neither you nor the relayer can understate it.

The withdraw flat fee: a flat 0.003 SOL

On top of the percentage, every withdraw pays a flat protocol fee that defaults to 0.003 SOLConfig.withdraw_fee_lamports. It is an admin-tunable on-chain value (capped at 0.1 SOL), not a hardcoded constant, and it does not scale with the withdrawn amount.

Mechanically, the relayer that submits your withdraw pays that SOL fee out of its own wallet at execution time and recoups exactly it by keeping a small tip slice — in the withdrawn asset — out of the released amount before routing the rest to your recipient. The Solana network gas is a separate cost the relayer absorbs; it is not added to your fee. This design is what lets you withdraw to a freshly created, unfunded wallet — the receiving wallet needs no SOL of its own.

A worked example, end to end

Say you deposit 1.0000 SOL into the SOL pool.

The deposit is free: the full 1.0000 SOL enters the pool vault, and your shielded note records 1.0000 SOL as the spendable amount.

You wait through your privacy delay. When you withdraw the 1 SOL (at the recommended 23 bps), the protocol takes ~0.0023 SOL as the percentage fee into the pool's token fee vault and 0.003 SOL as the flat fee to the fee collector. Your recipient lands roughly 0.9947 SOL.

Total cost on a 1 SOL round-trip: about 0.0053 SOL, or ~53 basis points — but you pay none of it until you exit. On a 100 SOL withdraw the percentage dominates and the flat fee is negligible (~23.3 bps total). On a 0.1 SOL withdraw the flat fee dominates (~3.2%). SolMask is more cost-effective for larger amounts.

Where the fees ultimately go

Both fees ultimately funnel to a single on-chain account — Config.fee_collector — configured by the SolMask admin at deployment. The flat SOL fee goes there directly, in SOL, on every withdraw. The percentage fees accumulate in per-pool fee_vault accounts in the pool's native asset, and are swept by the admin to the fee collector when a pool's vault crosses a configurable sweep_threshold. Sweeping is a manual operation, not automatic.

The fee collector destination is published in the deployed Config PDA, and both fee rates (withdraw_fee_bps and withdraw_fee_lamports) are readable there too. You can verify where the fees go and what they are without trusting our word for it.

What the fees pay for

The withdraw fees are the protocol's revenue: they pay for the infrastructure (the relayer, the indexer, the trusted-setup ceremony costs) and for ongoing development. They are not network gas fees — the actual Solana priority fees on your transactions are separate and go to validators in the normal way.

Charging on exit rather than entry means deposits cost nothing, and you only pay when value actually leaves the pool. Because the flat portion is fixed, it makes very small withdraws economically unattractive but doesn't penalise large ones — which keeps the anonymity set populated with meaningful amounts rather than dust.

There are no other fees. No subscription, no deposit fee, no withholding on the swap side beyond what Jupiter itself charges for cross-asset routing. What you see in the UI is what you pay.

What are the fees and where do they go? · SolMask