private-transfer is the easy path when you want to pay someone exact Y from private balance without manually building --tail-calls.
For a public recipient, it unshields through a fresh public account in your wallet and forwards exact Y to --to. Anything leftover (Tornado note remainder, unused-gas refund) stays on that fresh account — not on the recipient.
Works on Tornado, Privacy Pools, and Railgun (same EIP-7702 / paymaster model as unshield). You can also use transfer --from tornado, --from privacy-pools, or --from railgun.
# Pay someone in ETH
Dry-run first (no --broadcast):
kohaku private-transfer --to 0xFriend --amount-formatted 0.1
Then broadcast:
kohaku private-transfer --to 0xFriend --amount-formatted 0.1 --broadcast
--to can also be a stealth selector (s0) or a .eth / .gwei / .wei name.
# Tokens
kohaku private-transfer --to 0xFriend --token DAI --amount-formatted 50 --broadcast
# Protocol notes
- Tornado — the paymaster fee comes from the unshielded notes, so the CLI selects notes that cover the transfer plus that fee. A
0.1 ETHpayment may need more than0.1 ETHin notes; the tail pays exactly0.1and the remainder stays on the fresh account. - Tornado pool choice — extended ETH denominations are enabled by default, but their anonymity sets may be much smaller. Add
--exclude-new-poolsto spend only classic pools. This does not change sync or balances. - Tornado fees — the preview and leftover calculation use the fee committed in the prepared proof. If that fee leaves too little for the exact transfer, the CLI stops before broadcasting.
- Privacy Pools — unshields the exact transfer amount; the paymaster fee is taken from private balance on top. The fresh account is the EIP-7702 delegate and refund recipient, so unused-gas change does not go to
--to. - Railgun — same “exact transfer” idea; treasury fee is added on top, and bundler gas is paid from shielded WETH.
- Railgun to
0zk…— stays private inside Railgun, without an unshield or public receiving account.ethselects private WETH. The ERC-4337 paymaster still charges private WETH for gas.
Use --amount-max (or enter max interactively) to send the largest recipient amount after estimated protocol and gas fees:
kohaku private-transfer --protocol railgun --to 0xFriend --amount-max
Legacy and signature-derived notes remain separate when calculating the maximum. Railgun also reserves private WETH for gas, including transfers to a Railgun 0zk… address. Use unshield with --tail-calls when you need custom calldata (swaps, routers, multi-call); private-transfer has no --next or --tail-calls.
# Related
- Unshield Tail Calls — custom post-payout calldata
- Transfer Funds — send from a public account after it is already funded
- Using Dapps — where this sits in the preference order