Solada: a swap corridor is one order book

Native SOL for native ADA, across two chains that share nothing, through one pair market. How the corridor works, why it is an order book and not a bridge, and how the payout rule is enforced by the chain instead of by us.

Solada is the reference tenant. It is built the way a customer builds on Clobber: as a client of the public API, with an account, a market, credits, orders and balances, and no access to anything a customer does not have. It runs continuously on test networks, Solana devnet on one side and Cardano preprod on the other, and you can swap on it at solada.clobberhq.com. The coins there have no monetary value, which is what lets the corridor be public.

This page is the engineering behind it, written for the reader who would otherwise build a bridge.


#Two chains, no shared asset

Solana and Cardano have no asset in common and no execution environment in common. A transfer between them cannot be a transfer; something has to be exchanged. The usual answer is a bridge: lock SOL on one side, mint a wrapped SOL on the other, and let people trade the wrapper. That moves the trust into the bridge's validator set and gives the user a token that is only as good as the bridge.

The honest product is a cross, not a wrap. Someone who holds ADA and wants SOL is on one side of a trade, someone who holds SOL and is willing to sell it for ADA is on the other, and the thing that matches them, discovers the price and settles the difference is an order book. Solada is that order book, with the two chains at its edges.

Concretely, the corridor is one market on one Clobber environment:

Market SOL-ADA, kind pair: base SOL, settlement ADA
Currencies SOL at scale 3, ADA at scale 6 (lovelace exactly)
Grid tick 0.01 ADA, lot 0.001 SOL, so one tick of one lot is exactly 10 minor units of ADA
Fees taker 20 bps, maker rebate 5 bps, charged in ADA in both directions
Price a live book, quoted by a market maker around the spot SOL/ADA cross and moved by whoever trades it

Selling the base is SOL to ADA; buying it is ADA to SOL. The market does not know it is a corridor. Pair markets in Clobber are plain spot with the rule that you must hold what you sell, and that rule is the entire settlement model: an order can only move value that is already in the ledger.

The scale of SOL is the one number here that came from the engine rather than from the chain. The grid rules require a pair's lot size to carry exactly the base currency's decimals and a tick times a lot to land on the settlement currency's grid, and with SOL at its native nine decimals no sane tick exists. At scale 3 the arithmetic is exact, and lamports below a thousandth of a SOL stay in the vault, on the safe side of the solvency check below.

#One swap, end to end

A swap is a small state machine that a daemon next to the engine drives, with the chains on one side and the Clobber API on the other. Every transition is written to the daemon's own log before the action it triggers, so a daemon that dies mid-swap resumes by replaying its log, the same discipline the engine uses one level down.

1 quoted: a fresh deposit address for this swap one address per swap, no memos, no shared address; good for about thirty minutes 2 confirming: the deposit chain is watched Solana: finalized commitment. Cardano: fifteen blocks of depth. the policy is the solvency dial: nothing is credited that a reorg could take back 3 credited: one API call, idempotent on txid the same credits endpoint every tenant uses; a watcher that reports twice cannot credit twice 4 filled: an immediate-or-cancel order crosses the book sized against the swap account's balance, against the market maker's resting quote the acknowledgement carries the fills: the rate is known before anything leaves 5 paid: the proceeds leave on the other chain one withdrawal id end to end; sign once, rebroadcast the same bytes; never paid twice inside the engine the credit, the order and the fills are commands in the cell's journal, in order, acknowledged after they are durable. The ledger holds what every swap account and the market maker own, exact. on the chains a watcher per chain tails finalized deposits into the swap addresses; an executor per chain pays out. Both are adapters behind one interface, which is what a new chain implements.
The life of one swap. The two amber steps are ordinary API calls, the same credit and order any tenant sends, and they are what makes the corridor a market rather than a bridge: the price is discovered by a fill, not set by a contract. Everything on the chains is an adapter; everything in the engine is journaled and replayable.

Three properties of this pipeline carry the weight.

Attribution without memos. Every swap gets its own deposit address, minted by the daemon from the chain's address source. A deposit is attributed by where it landed, never by what it said, which is the difference between a system that can lose a payment and one that cannot. Deposits that arrive after the window are still deposits into an address the corridor owns.

The order is immediate-or-cancel, so the worst rate is bounded. The swap is sized against the balance the credit produced and sent as a limit order that fills what it can at the quoted price or better and cancels the rest. The acknowledgement carries the fills, because the engine ran before the response, so the daemon knows the exact proceeds before it signs a payout. Slippage is a number the user saw, not a surprise.

A payout is paid once, however many times the daemon asks. The withdrawal id is the identity end to end. On Solana the transaction is signed once and the same bytes are rebroadcast, so a retry cannot be a second payment. On Cardano the withdrawal id is stamped in the transaction's metadata, so a daemon that restarts can find its own payout on chain before deciding whether to make one. The same idempotency discipline the API asks of its callers, applied by the corridor to the chains.

#Solvency you can check

A corridor that holds coins owes coins, and the honest question is whether it holds at least what it owes, per currency, at every moment. The corridor answers it as an inequality:

vault on chain ≥ what the ledger owes

The right side is the market maker's inventory plus every swap account's balance in that currency, and it is exact, because the ledger is inside the engine: double entry, integers only, conserved at write time. There is no reconciliation job between the corridor's books and the engine's, because the corridor's books are the engine's. The left side is the sum over the vault and every deposit address, read from the chain.

The inequality has a useful shape. A deposit raises both sides by the same amount, so it can never break it. A fill moves value between two accounts inside the ledger and touches neither side. The only operation that can lower the left side is a payout, and a payout that fails on chain re-credits the ledger and leaves the swap visible as failed with its balance intact. A negative margin on any currency is therefore a single unambiguous signal, and it stops the corridor.

Everything the corridor did is also in the journal. Each credit, order and fill is a command in the environment's log, and the corridor page shows that log as it happened, which is the same replayable record the engine stands on for failover and audit.

#Where custody is, today

The payout no longer runs through a vault key. On both chains a contract releases it against the cell's attestation, the mechanism the next section describes, so the corridor cannot direct a payout the book did not produce. What the corridor still holds is the deposit: the swap address a user sends to is one the corridor generated, and the sweep moves those coins into a vault the corridor controls, which is why the proof of reserves above exists at all. On test networks that is the appropriate design: the coins have no monetary value, the trust is in the code, and every payout can be watched on a public explorer.

Solvent and non-custodial are different properties, and the inequality above proves the first one. It says the corridor holds at least what it owes, per currency, at every moment, checked against the chains rather than asserted. It does not say the corridor could not decide to pay somewhere else. That second question is the one the contract answers, and it is answered at the corridor's edge, not in the engine. The market does not care who holds the collateral: what the engine requires is that an order only moves value the ledger already has, and what a user should require is a credible answer to "what backs this balance, and who is able to move it". A vault an operator controls is one answer. A contract that releases only against a statement the engine signed is a better one.

#The chain enforces the payout rule

The non-custodial corridor keeps the book, the market maker, the fees and the swap state machine exactly as they are. What changed is the vault. It is no longer an address that a key can empty: it is a program on Solana and a validator on Cardano that holds the funds and releases them only when handed a statement, signed by the cell that ran the match, naming the swap, the recipient and the amount, with a refund path on the same terms for a swap that never fills. A payout is no longer "the corridor decided to send this much to that address"; it is "the contract checked that the engine attested this fill, and released exactly what the fill says". On test networks that path runs today in both directions: a swap crosses the book, the cell signs the fill, and the program on Solana or the validator on Cardano releases the coins to the address the signature names, refusing any other address, any other amount, and the same swap twice.

That statement is not new machinery invented for the occasion, which is the reason this rung was reachable at all. The cell already produces the material: every credit, order and fill is a command in an ordered, hash verified log that replays to the same state byte for byte, so a signed claim about a fill is checkable against a record that cannot be quietly rewritten, by anyone holding the log. An off chain matcher whose every payout is provable against a replayable log is a different object from an off chain matcher you are asked to trust.

where it began a better lock non-custodial, running on test networks the vault is keys the corridor holds you trust the operator to pay you, and not to be compromised while it holds provably solvent, not yet trustless the vault is a quorum, not one key removes: one machine, one key, gone the signers together still hold it custody with a better lock the vault is a contract that checks the engine's signature removes: paying any address or amount the fill did not name left to trust: the attestation, and replay is how anyone checks it
Each rung keeps what is under it and removes one thing the user has to take on faith. The step that earns the word non-custodial is the last one, because it is the first one where the corridor cannot direct a payout the book did not produce. What survives it is a single claim, that the engine's attestation is honest, and that claim is checkable against the log rather than promised.

Both chains enforce the same rule underneath, and they enforce it in the idiom native to each: Solana checks a signature inside one transaction, Cardano threads a single stateful UTxO through every payout. Account by account, and UTxO by UTxO, this is what that looks like.

one transaction, two instructions 1 Ed25519SigVerify, the native program checks a signature, by a key, over a message, all three supplied by whoever built the transaction generic: this program does not know Solada exists 2 payout, solada_escrow rebuilds the same message from the payout args, then reads instruction 1 back through the sysvar and requires: same key, same message, same signature a match binds the native program's check to this exact escrow and this exact payout EscrowState PDA seeds: escrow, authority cell_pubkey, chain_tag = 1 read only inside payout Vault PDA seeds: vault, escrow holds the lamports signs the transfer with its own seeds: no private key exists to leak Redeemed PDA seeds: redeemed, escrow, hash(swap_id) created by init, inside payout a repeat swap_id fails to create it: replay refused before any transfer runs amount_minor lamports, CPI signed by the vault's own seeds recipient its key is folded into the signed message, so the signature authorizes paying exactly that address
Every payout is one transaction carrying two instructions. The native program's verify is generic, it checks a signature and nothing about Solada; the program's own instruction is what ties that check to this escrow, by reading the sibling instruction back and demanding it covers exactly the cell's key, the exact message and the exact signature. Three program derived addresses do the rest: one holds the cell's key, one holds the coins and can only move them by a signed transfer under its own seeds, and one exists solely so a second attempt at the same swap id has nothing left to create.
one transaction spends the UTxO and recreates it the one escrow UTxO 1 thread token, minted exactly once lovelace: the vault balance datum: cell_vk, redeemed = [...] token quantity = 1 is what proves this is THE UTxO spent with Payout { attestation, signature } swap_id, recipient, amount_minor, chain, expiry spent as must satisfy the validator checks, all of them signature verifies under datum.cell_vk version = 1, chain = cardano swap_id is not already in redeemed continuing datum: same key, + [swap_id] escrow keeps in minus amount_minor, or more recipient paid amount_minor, at that address tx validity upper bound is at or before expiry (no wall clock on chain; the bound stands in for now) escrow UTxO, continuing same thread token, forwarded redeemed now includes this swap_id value reduced by amount_minor payment output at least amount_minor lovelace to the address the attestation names reconstructed from the recipient's key hash
There is exactly one escrow UTxO, ever, because the thread token that makes it unique can only be minted once. A payout spends it and recreates it in the same transaction: same token, same key, one more swap id in the redeemed set, a little less lovelace. The validator does not trust any of that on its own, it checks all seven conditions against the transaction itself, which is also why the redeemed set is authoritative rather than advisory: nothing about this UTxO can be true unless the transaction proves it.

What changes in the corridor, and what does not:

#The ceiling, and where the corridor stops below it

There is one rung above the escrow, and it is worth naming because it is the answer most engineers reach for first. In an atomic swap the two legs bind: the user locks the coins they are paying with under a hash, the maker locks the other side under the same hash once the first lock is final, and each claim reveals what the other side needs to claim in turn. Either both sides are paid or neither is, and nobody, the corridor included, is trusted with anything at any point. Both chains support it natively: Cardano's extended UTXO model was designed for exactly this kind of validator, a script that releases an output to one key on presentation of a preimage or to another key after a slot, and Solana runs the same logic as a small program holding lamports in escrow.

user Solana Cardano market maker 0 the fill in the book fixes the amounts; the user picks a secret s and publishes H = hash(s) 1 lock SOL under H, refund to user after T1 the maker waits for the lock to be final under the chain's policy, then and only then: 2 lock ADA under the same H, refund to maker after T2, with T2 < T1 3 claim the ADA by revealing s: the preimage is now public on Cardano 4 claim the SOL with the s the user revealed if either side walks away, each timeout refunds its own locker: no state in which one party has paid and the other has not
The trustless ceiling, with the user going first because the user holds the secret, and the maker locking second and shorter so it can never be left holding a lock the user could still claim after the maker's refund. The cost of it is on the diagram: two locks, two claims, two wallets and two timeouts on every swap, including the swaps where nothing goes wrong.

The price of that shape is not the contracts, it is the swap. Two signatures on two wallets, and a floor of minutes that no amount of engineering removes, because the floor is two finality policies and a timeout, not the software. Worse for the book, the user holds a free option between the maker's lock and their own claim: they can watch the price move and simply not reveal. The option is bounded by the maker's timeout and it is real, so a maker prices it into the spread, and everyone who was not going to exercise it pays for the people who would. So the corridor climbs to the escrow, where the chain enforces the payout rule and the user still signs once, and stops there. The atomic shape stays specified and stays available for a counterparty whose requirement is that nobody is trusted at all, which is a different product than a swap people use on a Tuesday.

The shape generalises beyond this pair, and it is the shape Clobber is built to sit inside: matching off the chain, where an order book belongs, and settlement on the chain, where the coins belong. The engine keeps a complete, replayable, hash-verified record of every fill; the chain keeps the coins and enforces the exchange. Neither one has to trust the other with the part it is bad at.


Solada runs on test networks only. Never send mainnet funds to an address on the corridor page.