# Silver Portal and Bitcoin Mirror One of my goals this year was to understand blockchains in depth. In this guest post, I'll take you with me on part of that journey. We'll explore two related prototypes for interoperability between Bitcoin and Ethereum. The first is a cross-chain light client, while the second is a cross-chain decentralized exchange. ## Bitcoin Mirror **[Bitcoin Mirror](https://bitcoinmirror.org) is a bitcoin light client that runs on the EVM.** Here's the [testnet BtcMirror contract](https://ropsten.etherscan.io/address/0xffce2bfe3933c8ed1807c6c44241a4b3e90ca229#events). The mechanism is straightforward: anyone can submit a list of Bitcoin block headers. The contract checks header validity, keeping only the heaviest chain it has seen. (In other words, each time you submit, you can either extend the current chain or reorg--but either way, you must set a new high score for the chain with the most work, replacing what was there before.) As long as one honest actor is running a submitter script, and as long as the majority of bitcoin hashpower remains honest, the contract tracks the canonical chain. This lets users prove Bitcoin payments on Ethereum, opening some interesting possibilities. For example, 1. **Cross-chain sales.** You can deploy an ERC721 contract that mints an NFT to anyone who can prove they've paid in bitcoin. 2. **Proof of burn.** You burn 1 BTC. You post proof to a contract, which lets you mint 1 BBTC (burnt Bitcoin) on Ethereum. 3. **Proof of reserves.** Currently, contracts like WBTC use oracles to prove their Bitcoin reserves. You can replace trusted oracles using BtcMirror and a balance-tracking contract. 4. **Decentralized BTC/ETH exchange.** For example, to buy BTC and pay in ETH, you send ETH to an exchange smart contract. By default, you can take it back a day later. To keep the ETH, the seller posts a proof that she's sent you the BTC. This last one is especially interesting. It lets you move value between the two biggest blockchains without using a trusted custodian. I built a prototype to validate this idea, described below in the Silver Portal section. But first... ### How Bitcoin Mirror works The BtcMirror contract is responsible for knowing the canonical block hashes. It exposes these via `getBlockHash(n)` and `getLatestBlockHeight()`. Proving that a particular payment cleared, using a Merkle proof, is handled by a separate `BtcTxVerifier` contract. For example, here's a transction [submitting a block to the testnet mirror](https://ropsten.etherscan.io/tx/0x2feb771c8758855c292255ba43b980e957fd19d36dfa2c2d0d7ffcd0daa4a92c#eventlog). The contract verifies proof-of-work, keeping only the heaviest chain. Concretely, a `submit` call will revert unless it beats the previous record for heaviest chain. If the call succeeds, it sets a new tip block. As long as a majority of hashpower is honest and at least one person is running the submitter, the contract should report the correct chain. ![](https://i.imgur.com/l4SiRhQ.png) Bitcoin has a very simple header, illustrated above. We want to verify proof of work. The "difficulty bits" are a custom floating-point representation--a 24-bit mantissa and an 8-bit exponent, which combine to form a large (256-bit) integer `T` called the target. The 256-bit hash of the block must be below that target. ![](https://i.imgur.com/g0KGlUT.png) The heaviest chain is the one containing the most total proof-of-work. Calculating `D` as above, we can then calculate `W = 2^256 / D` as the work done. `W` is the expected number of hashes a miner would have to do to find a satisfying block. Summing `W` gives the total work on that chain. **A note about work.** The work done by a block depends only on its difficulty bits--the hash is pass/fail, either low enough or not. Two blocks with same difficulty bits count as an identical amount of work, even if one has a lower hash. This is key for PoW security, for reasons left as an exercise. (Consider that, while every valid block has a hash below its target, 1 in 100 valid blocks will have a hash less than 1/100th the target value, etc...) **A note on retargeting.** Bitcoin recalculates its target difficulty every two weeks. More precisely, the difficulty bits for block `n` must be identical to the parent block `n-1`, unless `n` is a multiple of 2016. At each retargeting, difficulty stays the same if the timestamp is two weeks after the previous retarget--an average of 10 minutes per block. Otherwise, it increases or decreases proportionally. **A note on eventual consistency.** In principle, a light client could omit *all* checks except for the proof-of-work. We could ignore the difficulty update rules and just track the heaviest chain. This would still be eventually consistent: an attacker could submit 1000 invalid blocks at low difficulty, and then the next real bitcoin block would arrive, replacing those 1000 with a single block of higher total difficulty. However, eventual is not quite good enough. We want to prove payments the usual way, where some number of confirmations--say 6 confirmations--means that the payment is considered final. To summarize, BtcMirror receives a list of block headers. It verifies in two steps: 1. Verify each block - For each block `i`, check that the parent hash corresponds to BtcMirror's current canonical hash for `i-1` - Check proof-of-work. Block header `i` must hash to a value below the target computed from the difficulty bits. - Check difficulty. The difficulty bits must be identical to those in the previous block, unless `i` is a multiple of `2016`, in which case a new target is computed. The target must be at most 4 times as high as the old target--Bitcoin's rules cap difficulty adjustment, so mining can become at most 75% easier per retargeting. 2. Verify total work - Sum the total $\Sigma{W_i}$ of the chain that ends with the submitted list of headers. Discard the submission unless it's higher than the total work of BtcMirror's current canonical chain. Details: [BtcMirror.sol](https://github.com/dcposch/btcmirror/blob/master/packages/contracts/src/BtcMirror.sol) ### Analysis The prototype BtcMirror hasn't been gas optimized, but its minimalism makes it reasonably efficient. Gas costs are summarized below. Most of the marginal cost of proving a block is state growth--the 20,000 gas it costs to set a single new state slot, recording the block hash. ![](https://i.imgur.com/sptJbHQ.png) **Would SNARKs help?** For bitcoin, it appears not. Even the most succinct production proving systems like Groth16 require roughly 200k gas for proof verification, so the fixed overhead per `submit()` is significantly higher. Marginal *verification* per block would be zero, but state costs--20k gas to save the block hash--would be unaffected. An alternative approach to gas optimization would be to only save every *n*th block hash, at the cost of complexity and slightly larger transaction proofs. **Succinct block validity proofs.** A deeper way in which zkSNARKs could help is to prove the validity *of the entire block*, not just of the header chain. This would give BtcMirror the guarantees of a Bitcoin full node, rather than a light node, no longer relying on an honest hashpower majority. BtcMirror would have to store a UTXO Merkle root for each block. The proof for each block would take witnesses for all UTXOs spent in that block as a private input. There are three issues, though. First, it's not clear that proofs this big are feasible in current proving systems. Second, it adds substantial complexity. Third, it's not clear that validity proofs add much security in this case. A 51% attacker would no longer be able to fool BtcMirror into following an invalid chain, but the attacker could still double spend, proving a payment via BtcMirror and then reorging it away. **Reorg or 51% attack detection.** BtcMirror can detect reorgs. The contract stores the depth of the longest reorg it has seen. This gives user contracts a signal about whether Bitcoin consensus is still trustworthy. **Daily proving costs.** Bitcoin produces about 144 blocks a day. The following is a rough estimate of BtcMirror operating costs. | Batch size | Gas/block | Gas/day | Eth/day *@50gwei* | USD/day *@$1000/eth* | | -------- | -------- | -------- | -------- | -------- | | 1, prove each block immediately | 66k | 9.5m | 0.47 | $470 | | Large batch | 27k | 3.9m | 0.19 | $190 | The estimates lose precision from left to right. Gas/day is predictable. Eth/day is rough, but a 50gwei gas price has been [the right order of magnitude since Ethereum began](https://etherscan.io/chart/gasprice). USD/day is just a directional estimate. In short, though, mainnet BtcMirror is cheap compared to other infrastructure, but too expensive to rely on altruism. It requires a mechanism to incentivize submitters. A few options exist, discussed under Next Steps. On L2, BtcMirror can be run for a few dollars a day. It can likely run without incentives, especially with the upcoming EIP 4844 further reducing costs. ### How transaction proofs work The following illustrates how we prove a payment using Bitcoin Mirror. Details: [BtcTxVerifier.sol](https://github.com/dcposch/btcmirror/blob/master/packages/contracts/src/BtcTxVerifier.sol), [BtcProofUtils.sol](https://github.com/dcposch/btcmirror/blob/master/packages/contracts/src/BtcProofUtils.sol) Bitcoin's block structure is pleasantly simple. It contains just a single data structure--the transaction list--represented as a standard binary Merkle tree. As an aside, Ethereum currently uses "hexary Merkle Patricia tries". Witnesses, aka proofs, into these tries are significantly larger than proofs in a standard binary tree. This will be fixed in The Verge, the upcoming upgrade to verkle trees. ![](https://i.imgur.com/o3zLFMe.png) A BtcMirror proof includes the following: - The transaction being proven, typically ~200 bytes. - The transaction index in the block. - The Merkle path, typically ~320 bytes, listing each sibling hash on the path from the transaction ID to the root--the gray circles above. - The block header, 80 bytes. - The block number. The verifier checks that the transaction pays the correct amount to the correct recipient. Then, it checks the Merkle proof. Finally, it hashes the block header to produce a block hash, then calls BtcMirror to ensure it's in the canonical chain. The verifier takes a `minConfirmations` parameter, checking that the block number is at least that far behind the current tip. This shows probabilistic finality--the block in question is unlikely to be reorged out. ### Prior art A few projects have shipped something related to Bitcoin Mirror in the past. #### BtcRelay [BtcRelay](https://github.com/ethereum/btcrelay) is a project from the earliest days of Ethereum. Like BtcMirror, it tracked bitcoin by allowing anyone to submit block headers, then verifying them on ethereum. The contract was written in Serpent--a precursor to Solidity. It looks monolithic (chain tracking and transaction verification in a single `.se` file) and stopped running around 2017. It also looks as though BtcRelay used more gas. The [following transaction](https://etherscan.io/tx/0xe21099d8fd1252281389fc888f23f98e60db22ecb5c149ad6fda6dccdf110b50) proves a single Bitcoin block for 194k gas, compared to <70k on BtcMirror. #### renBTC Ren is a complex cryptosystem that facilitates cross-chain transfers. Ren uses a third consensus protocol called [RenVM](https://github.com/renproject/ren/wiki), separate from Bitcoin and Ethereum. They issue renBTC; like WBTC, renBTC is backed 1-to-1 by Bitcoin. Unlike WBTC, renBTC aims to minimize custodial trust using shards of "DarkNodes" that share a Bitcoin private key as an MPC secret. The market seems to consider the complexity and contract risk of renBTC to be higher than the custodial counterparty risk of WBTC. As of today, Ren holds about 4k BTC, while WBTC holds about 250k BTC. #### starknet-btc-lightclient This appears to be an [prototype light client](https://github.com/samlaf/starknet-btc-lightclient) similar to BtcMirror, but written in Cairo to run on Starknet. ## Silver Portal **[Silver Portal](https://silverportal.org) is a prototype decentralized bitcoin/ethereum exchange.** This illustrates one of the interesting things you can do with BtcMirror. More precisely, it lets you trade Bitcoin to or from any ERC20 token, cross-chain. BTC-WBTC trades are the most practical for reasons we'll explore. > Why not just wrap BTC to WBTC directly? Wrapping is custodial, requiring identity information and an onboarding period. Centralized exchanges have similar limitations. Our goal is a decentralized and permissionless alternative. [Testnet deployment.](https://silverportal.xyz/) ![](https://i.imgur.com/EeKmZSz.png) #### Basic operation Silver Portal is a **limit order book**. Market makers, aka liquidity providers, post bids and asks. Traders buy Bitcoin, hitting an ask, or sell it, hitting a bid. Every trade creates an **escrow**. The escrow holds WBTC until the seller proves they've sent Bitcoin to the buyer--at which point they can collect their WBTC--or until a timeout expires. #### Avoiding free options An older form of cross-chain trade uses **hash timelock contracts**, or HTLCs. These essentially lock up asset A on chain A, asset B on chain B, such that both can be released with the same secret. They provide basic safety--either Alice keeps A and Bob keeps B, or they swap, but in no case does one party end up with both. However, HTLCs suffer from a free option. If Alice initiates this trade, Bob can wait until just before the timelock expiry. If the price has moved in his favor, he completes the trade. If not, he lets it expire. Silver Portal avoids this by requiring a stake proportional to the size of the trade. This stake is refunded once the seller sends bitcoin, slashed otherwise. That said, for the BTC-WBTC pair, where there's no price movement, this may not be necessary--the "free option" is worth $0 if price is constant. If that turns out to be the case, then the stake percentage can be set to 0%, simplifying the user experience. #### Achieving gas efficiency with BTC-WBTC Limit order books have historically been found a poor fit for on-chain exchanges with volatile prices. In volatile markets, LPs/MMs must frequently update their bids and asks. This creates a lot of extra transactions--transactions that are just adjusting liquidity, not actually trading. One solution is to not use an order book. Automated market makers like Uniswap were first developed on Ethereum in 2018. Their efficiency made them popular and effective. This doesn't work for cross-chain trades, though. (And it's worth noting that there's been convergence--[modern AMMs look increasingly like LOBs](https://twitter.com/hasufl/status/1559799638886170625).) The other solution is to find a non-volatile price. BTC-WBTC should trade near 1.00 outside of an emergency. This lets LPs offer deep liquidity just above and below that price. No need to update bids and asks as the market moves. It may also simplify the user experience, if we avoid charging a refundable stake. Stake is essential for volatile pairs to avoid giving the bitcoin seller a free option. Ethereum already has efficient ways to convert from WBTC to any other token. Silver Portal simply adds a trust-minimized, permissionless protocol for trading WBTC-BTC. If you hold BTC, your first stop is WBTC, and you second can be any asset on Ethereum. #### Proving transactions The hardest part of implementing this exchange was proving payment. If I initiate a trade and owe you 1 BTC, how do I prove that *I* paid it? If someone else sends you 1 BTC for an unrelated reason, it would be bad if I could prove that transaction and steal your WBTC. One option would be to include extra information in the bitcoin transaction. You could imagine a kind of "memo" field that says "I'm closing escrow #123". Unfortunately, though, Bitcoin's user experience is primitive, and popular Bitcoin wallets have no way to create custom transactions. There's also nothing like Metamask, where an app can propose a BTC transaction for a user to review. A second option is to ensure unique amounts. More precisely, the exchange contract ensures that there are never two option escrows with the same (recipient, amount). Rather than owing 1 BTC, you may owe 1.00000002 BTC--a few satoshis more. The amount must be paid exactly. This is aesthetically displeasing, but it allows the exchange to work with standard bitcoin payments sent from unmodified wallets. ### Risks Every defi construct should state risks. Here are some of ours. 1. Honest-majority assumption re: Bitcoin hashpower. This is inherent to any cross-chain protocol. A successful 51% attack on Bitcoin would allow an attacker to drain ether from the portal. Silver Portal is an exchange, not a bridge, but Vitalik's post on the security limitations of cross-chain bridges still applies. In our case, only current liquidity is at risk, not the entire value of a bridged asset. 2. Smart contract risk. These are experimental contracts. They have not been audited and are currently for testnet use only. Risk can be reduced over time through auditing, verification, and experience, but will never be zero. 3. Censorship or extreme congestion. Ethereum is designed for liveness and censorship resistance. If either of those properties fail, you may have sent bitcoin and be unable to prove it within the escrow window. 4. Price exposure. If you're providing liquidity, the standard market risks apply. 5. (Mild) counterparty risk. If you're swapping ether for bitcoin and there's an extreme price movement in your favor, the other party might accept being slashed rather than complete the trade. They may also fail to complete unintentionally. Either way, you'll simply get your ETH back plus slashing proceeds after the escrow period. ## Next Steps ### Bitcoin mirror #### Testing and review The next step is getting test coverage up, then getting more pairs of eyes. I like the [roast concept](https://twitter.com/isonemal/status/1517692511078207488). It's about expert review and improving the codebase. More than a regular code review, but short of a formal audit. #### Paying submitters To deploy BtcMirror on mainnet, we'd need a way to incentivize submitters. The most direct way is a funding pool contract that reimburses gas costs for successful `submit()` calls. The pool could be funded as a public good, either by grants or by a system like Gitcoin. An indirect, more speculative way to incentivize would be via a token minted to successful submitters. For example, an NFT that mints with 1/144 probability for every submitted block, so on average once a day. ### Silver Portal #### Testing and review As above. #### Liquidity providers The most important actor the protocol needs are LPs. If you're interested in making a market on a decentralized BTC-WBTC dex, please reach out. --- *Big thanks to [gubsheep](https://twitter.com/gubsheep) and [JosephC](https://twitter.com/JosephCh) for feedback.*