25.00 USDC
received on Base, exactly as requested
- You paid
- 0.019714 ZECfrom your shielded balance
- Held by
- Two on-chain locks. No custodian.
- If it stalls
- Both sides refund
- Base claim
0x91ac…03fe
Example values
Pay anyone an exact dollar amount straight from shielded ZEC. A lock on Zcash and a lock on the dollar chain open with the same key, so either both sides settle or both get their money back. No bridge, no custodian, no wrapped token.
Open source (MIT). Escrows live on six public testnets. Experimental and not audited.
7c1e…a90b0x4b2f…e1d70x91ac…03fed03a…5c7eA shop shares a link with an address and a price. You pay from your shielded balance, and they receive exactly what they asked for, on the chain they chose. The ZEC rounds up, never the dollars.
paralock.xyz/app?pay=0x5aE1…c9F2&usd=25&chain=base&label=Acme%20Coffee
private settles with adaptor signatures, so no hash links the two chains.25.00 USDC
received on Base, exactly as requested
0x91ac…03feExample values
Each chain holds one side of the trade, and taking your side hands the other party the key to theirs. The other party is a maker: it quotes a price, locks the stablecoins and earns the spread. Anyone can run one.
It stays on your device until you claim your dollars.
Only the secret lets the maker take it. If the maker never does, it's yours again at block N.
Once your ZEC is confirmed, the maker locks stablecoins under the same secret. The maker can refund them only after time T, long before N.
Claiming reveals the secret. In a payment, the dollars go straight to the person you're paying.
It uses the secret your claim revealed. Both sides are paid, and nobody held anyone else's money.
Standard mode shown. Private mode replaces the shared hash with adaptor signatures; the guarantees are the same.
Every outcome is enforced by the Zcash script and the EVM contract, not by a person. The ZEC refund window always outlasts the dollar lock by at least 2×, so whoever learns the secret has time to use it, and each side verifies the other's lock on-chain before committing anything more.
| If | Then |
|---|---|
| The maker never locks | You refund your ZEC after block N. |
| You never claim | The secret stays hidden, so the maker can't touch the ZEC. The maker refunds after T, and you refund after N. |
| You claim | That reveals the secret, and the maker has until block N, long after T, to use it. |
| Someone copies the secret from the mempool | There is nothing to steal. The dollar lock only pays the recipient set when it was created, and the ZEC lock also needs the maker's signature. |
Removing the middleman is step one. The rest is about what the two chains can reveal about you, and each level reveals less.
| Level | What it does | On Zcash, observers see | Value linking the chains |
|---|---|---|---|
| 1HygieneShipped | Shield before and after, a fresh recipient, a relayed claim, standard amounts and timing jitter. | A transparent HTLC | The same sha256 hash on both chains |
| 2Adaptor signaturesShipped, experimental | No hash anywhere. The ZEC sits in a 2-of-2 multisig, and the dollar escrow releases on a one-time key's signature. | An ordinary 2-of-2 multisig spend | None |
| 3Fully shielded legIn research | FROST 2-of-2 shielded notes with Schnorr adaptor signatures, so the ZEC never leaves the shielded pool. | A normal shielded transaction | None |
At every level your wallet history stays out of the swap. Amounts and timing can still be correlated; standard amounts and jitter make that harder. Read the privacy design
Give your users dollar payments from shielded ZEC in a few lines of TypeScript. The SDK runs both chains, the timeouts and the recovery, and your app never touches their funds. It's MIT-licensed: embed the taker, or run a maker and earn the spread.
npm install @paralock/sdk@paralock/sdkcreateTaker and createMaker: both modes, exact-amount payments, privacy options, crash-safe recovery.
@paralock/zcashHTLC and 2-of-2 locks, v5 transactions and ZIP 244 signing, in TypeScript. Runs in browsers.
@paralock/adaptorECDSA adaptor signatures on secp256k1 with DLEQ proofs. Runs in browsers.
@paralock/evmviem clients for the hashlock and signature escrows on any EVM chain.
@paralock/lightwalletdUse a public lightwalletd server as the Zcash backend. No full node to run.
pnpm paralock is the CLI inside the repo, so there's nothing to install globally. You need Node 20+, pnpm, Docker or OrbStack, Foundry 1.8+ and ths (a one-command Zcash regtest).
Get the code.
git clone https://github.com/bitfalt/ParalockInstall dependencies, then build the packages and the CLI.
cd Paralock && pnpm install && pnpm buildCheck every prerequisite. Anything missing comes with its install command.
pnpm paralock doctorStart a Zcash regtest, all six EVM chains, the contracts, a maker and this app at localhost:3000.
pnpm paralock dev --web --evm allimport { SwapFailedError, createTaker } from "@paralock/sdk";
import { LightwalletdClient } from "@paralock/lightwalletd";
const taker = createTaker({
zcash: { network, key, node: new LightwalletdClient("zec.rocks:443") },
evm: { base: { rpcUrl, chainId, htlc, adaptorEscrow, account } },
maker: "https://maker.example",
store: "./swaps", // secrets are saved before anything is broadcast
});
// Pay Acme Coffee exactly 25 USDC on Base, in private mode.
const quote = await taker.quoteExactOut(25_000_000n, "base", "adaptor");
try {
await taker.swap(quote, { recipient: "0x5aE1…c9F2", label: "Acme Coffee" });
} catch (err) {
// The maker stalled: take the ZEC back after the refund height.
if (err instanceof SwapFailedError) await taker.refund(err.swap.id);
}createTaker, quoteExactOut, swap. The recipient gets exactly the amount you quoted, on the chain they chose.
Your app never holds user funds. They sit in two on-chain locks and move only when the protocol says so.
Secrets and refund data are saved before anything is broadcast. resume() and refund() work from a fresh process.
pnpm paralock dev starts a Zcash regtest, six EVM chains, the contracts and a maker on your laptop.
@paralock/lightwalletd talks to public lightwalletd servers, and the escrows are live on six public testnets.
llms.txt, every docs page as Markdown, a read-only MCP server and an installable skill for coding agents.
300 tests across the contracts, the SDK and live regtest runs. Experimental and not audited.
Anywhere shielded ZEC needs to become exact dollars, without handing it to someone in the middle.
Keep the treasury in shielded ZEC and pay each contributor an exact amount on the chain they choose. One devnet run paid $4,665.75 to four people on four chains.
See the exampleMake the secret a decryption key. The seller is paid only by revealing it on-chain, and the buyer reads it from the claim. No escrow agent.
See the exampleA Zcash wallet or an AI agent embeds the SDK and pays anywhere stablecoins work: exact amounts, no exchange account.
Settle large ZEC trades through two on-chain locks instead of trusting the other desk. The price is fixed before anything locks.
The same two escrow contracts on every chain: Tempo settles in OUSD, the rest in USDC. Both are deployed on all six public testnets, and the whole set runs locally with one command.
Nobody but you and the maker ever holds the funds, and neither of you can take the other side without paying. The Zcash script and the EVM contract enforce it: either both sides settle or both refund.
What you still rely on: the code, which is experimental and not audited, and the maker's price, which you accept before anything locks. You also need to claim before T; the SDK watches both chains and does it for you.
No. Anyone who copies the secret from the mempool can submit the claim, but the dollar lock only pays the recipient fixed when it was created, and the ZEC lock also requires the maker's signature. In private mode no secret is published at all: the claim publishes a signature that only the maker can turn into the key.
Zodl's CrossPay spends shielded ZEC through NEAR Intents market makers, and deposits move through NEAR's PoA bridge, which holds them in a treasury. THORChain's ZEC pool keeps funds in validator-held vaults. Both are good products, but an intermediary holds your money while the swap is in flight.
With Paralock, only the two parties ever hold funds, the SDK is self-hostable, and it settles natively on Tempo, which isn't a NEAR Intents destination.
Partly, depending on the mode. Your shielded balance never touches the swap: only the swap amount is unshielded, and change and refunds are shielded again.
In standard mode the Zcash lock is a transparent HTLC carrying the same hash as the dollar lock, so the two legs can be paired. Private mode removes that hash, and Zcash sees an ordinary 2-of-2 multisig. A fully shielded Zcash leg through FROST is still in research.
Not yet. The escrows are deployed on six public testnets, and the Zcash side runs on testnet through public lightwalletd servers, with no node to run. The hosted app uses a simulated maker. The code is experimental and has not been audited, so mainnet isn't supported.
The hosted app runs against a simulated maker, so nothing real moves. Try all three endings (settled, the maker vanishes, you never claim) and watch both locks.
Launch app