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 Bridge contract that is simultaneously the rawBTC ERC20 token and the bridge logic. This means rawBTC has no separate token contract — the bridge contract is the token.
  • Internal _mint() and _burn() functions are the only paths that modify balances and total_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
Share this project:

Updates