Inspiration
What it does
Bitcoin is the most secure and decentralized monetary network ever built,
but it has always been siloed from the programmability of modern smart
contract platforms. Existing solutions like wBTC require trusting a
custodian, which fundamentally contradicts Bitcoin's core value
proposition. I wanted to build something different — a bridge where
Bitcoin remains Bitcoin, just represented natively on Starknet as
rawBTC, a 1:1 satoshi-backed ERC20 token with no custodial middlemen
in the token layer.
The question that drove the entire project was simple:
"What is the minimum trust a user must extend to move BTC onto Starknet and back?"
What I Built
The rawBTC Bridge is a Cairo smart contract deployed on Starknet that enables two core flows:
Bitcoin → Starknet:
A user sends BTC to the bridge's Bitcoin address. An off-chain relayer
monitors the Bitcoin network and, after $n \geq 6$ confirmations, calls
settle_btc_deposit() on the contract, minting rawBTC 1:1 to the
recipient's Starknet wallet.
Starknet → Bitcoin:
A user calls bridge_rawbtc_to_btc(), which burns their rawBTC
immediately and emits a withdrawal event. The relayer watches for this
event and sends real BTC to the user's Bitcoin address on-chain.
The exchange rate for STRK↔BTC conversions uses a fixed-point rate $r$ stored on-chain, where:
$$ \text{amount_strk} = \frac{\text{amount_rawbtc} \times r}{10^{18}} $$
$$ \text{amount_btc} = \frac{\text{amount_strk} \times r^{-1}}{10^{18}} $$
Both rates are updated by the authorized relayer and expose a confidence interval in basis points so the contract can reject stale pricing.
How I Built It
The stack has two layers:
On-Chain (Cairo / Starknet)
- A single
Bridgecontract that is simultaneously the rawBTC ERC20 token and the bridge logic. This meansrawBTChas no separate token contract — the bridge contract is the token. - Internal
_mint()and_burn()functions are the only paths that modifybalancesandtotal_supply, making the token accounting impossible to accidentally bypass. - Swap IDs are generated with Poseidon hashing over a monotonic nonce, block timestamp, and caller address, giving collision resistance:
$$ \text{swap_id} = \text{Poseidon}(\text{nonce},\; \text{salt},\; \text{caller},\; t_{\text{block}}) $$
- Replay protection on deposits uses a
btc_tx_minted: Map<felt252, bool>so the same Bitcoin transaction hash can never mint rawBTC twice.
Off-Chain (Rust / WASM)
- A Rust library compiled to WASM mirrors the contract logic for frontend simulation and testing without requiring a live Starknet node.
- Bitcoin transaction verification uses SPV (Simplified Payment Verification) — the relayer checks the Merkle proof of a BTC transaction against its block header before calling the contract.
Challenges
1. The Dual-Storage Trap
The hardest bug to catch was having two separate ERC20 storage systems —
rawbtc_balance for bridge operations and balances for ERC20
functions. Tokens would mint into one and become invisible to the other.
The fix was enforcing a strict rule: one storage system, two internal
functions (_mint and _burn), used everywhere without exception.
2. Swap ID Collisions
My original swap ID was: $$ \text{swap_id} = \text{amount.low} + \text{btc_address} $$ Two users bridging the same amount from the same address produce identical IDs, causing the relayer to misroute withdrawals. Replacing this with Poseidon hashing over a nonce eliminated all collisions.
3. Cairo's Felt252 Limitations
Bitcoin addresses are base58 or bech32 strings. Cairo's native type is
felt252, a 251-bit field element. Full address checksum validation
inside Cairo is impractical — the language has no string processing
primitives. The solution was to validate format off-chain in the relayer
and only enforce non-zero presence on-chain.
4. Preventing Free Minting
Without an authorization guard on settle_btc_deposit, any wallet
could call it and mint rawBTC for free. Adding assert_only_relayer()
— which checks that the caller is either the registered relayer address
or the admin — closes this completely.
What I Learned
- Token accounting must be centralized. Any system with more than one code path that modifies token supply will eventually diverge.
- Burn before you bridge. For withdrawals, burning tokens on Starknet before the relayer acts on Bitcoin means supply is always correct, even if the relayer is temporarily offline.
- Off-chain and on-chain share the burden. A Bitcoin bridge is not purely a smart contract problem. The relayer's correctness is equally critical, and its trust assumptions must be made explicit to users.
What's Next
- Decentralizing the relayer using a threshold signature scheme so no single party controls withdrawals
- Integrating Pragma or RedStone oracle feeds for trustless BTC/STRK pricing
- Adding a Bitcoin SPV light client directly in Cairo using recursive STARKs for trustless deposit verification ## How we built it
Challenges we ran into
Accomplishments that we're proud of
What we learned
What's next for bitstark
Built With
- bitcoin
- blockchain
- bridges
- cairo
- defi
- erc20
- ethereum
- layer2
- next.js
- node.js
- opensource
- openzeppelin
- poseidon
- relayer
- rust
- scarb
- serde
- smartcontracts
- spv
- starknet
- starknet-rs
- typescript
- wasm-pack
- webassembly
- zeroknowledge
Log in or sign up for Devpost to join the conversation.