Verifying Bitcoin Transactions in Clarity
Trustlessly validate Bitcoin data on-chain.

Intro
One of the unique features of the Stack chain and the Clarity language is that it allows for using read-only functions to trustlessly validate on-chain Bitcoin activity from Clarity smart contracts. This enables developers to build applications that react to real Bitcoin activity — such as deposits, transfers, and proofs of inclusion — without relying on off-chain indexers or oracles. In this guide, you’ll learn how to verify Bitcoin transactions in Clarity and safely bridge Bitcoin state into on-chain logic.
Knowledge of Bitcoin state: has knowledge of the full Bitcoin state; it can trustlessly read Bitcoin transactions and state changes and execute smart contracts triggered by Bitcoin transactions. The Bitcoin read functionality helps to keep the decentralized peg state consistent with BTC locked on Bitcoin L1, amongst other things. - Stacks Whitepaper
tl;dr
We'll be using a popular smart contract
clarity-bitcoin-libto verify bitcoin transactions on-chain in Clarity.Allows contracts to enforce logic based on Bitcoin events—deposits, withdrawals, lockups, or multisig activity.
Powers designs like wrapped assets, and deposits that mint or unlock value only after provable Bitcoin transactions.
Steps
Fetch bitcoin transaction metadata: block height and header, transaction hex, and the transaction's merkle proof of inclusion.
Pass in transaction metadata as arguments to
clarity-bitcoin-libcontract'swas-tx-mined-compactread-only function.Returns
(ok <txid>)if the proof checks out and the transaction is indeed mined in the specified Bitcoin block.
Key Tools To Use
Clarity Bitcoin library: A Clarity library for parsing Bitcoin transactions and verifying Merkle proofs.
mempool.space APIs: Bitcoin explorer APIs used to fetch bitcoin transaction metadata.
Bitcoin Transaction Proof [optional]: A TypeScript library for generating Bitcoin transaction proofs, including witness data and merkle proofs.
Clarity Bitcoin Client [optional]: Clarity Bitcoin Client is an open-source TypeScript library for interacting with the
clarity-bitcoin-libcontract on Stacks.
Complete Code
If you want to jump straight to the full implementation, the complete working code used in this guide is shown below.
The below consists of the main client side code of preparing the bitcoin transaction metadata and passing them into a contract call to the clarity-bitcoin-lib contract.
Helper functions to fetch the bitcoin transaction metadata from an explorer's API.
This is a snippet of the contract function we invoke to verify a bitcoin transaction.
Walkthrough
Prepare metadata as Clarity arguments
Let's circle back to the was-tx-mined-compact function of the clarity-bitcoin-lib contract for a second and analyze the order/type of parameters.
You can see that it intakes the parameters with a certain typing and order:
(height uint)the block height you are looking to verify the transaction within(tx (buff 1024))the raw transaction hex of the transaction you are looking to verify(header (buff 80))the block header of the block(proof { tx-index: uint, hashes: (list 14 (buff 32)), tree-depth: uint})a merkle proof formatted as a Clarity tuple
In short, the was-tx-mined-compact function takes the block height, the transaction hex, the block header, and a merkle proof, and determines that:
the block header corresponds to the block that was mined at the given Bitcoin height
the transaction's merkle proof links it to the block header's merkle root.
So after you've fetched the bitcoin tx metadata and have removed the witness data from the original transaction hex, let's go ahead and prepare the metadata into it's Clarity parameter values.
Invoke `was-tx-mined-compact` function
Construct a read-only function call, pass in the contract call options, and await the results. If the bitcoin transaction in question is indeed mined in an existing Bitcoin block, the contract will return a response that looks like:
(ok 0xfb88309b4041f76bea0c196633c768dca82bb0dd424cbfe19be38569007f92d9)
You'll see your exact bitcoin txid returned wrapped in an ok response.
That's the end-to-end flow: fetch the bitcoin transaction metadata and its merkle proof, prepare and assemble the data for the contract's read-only function call, and finally call the Clarity contract function that verifies inclusion in a Bitcoin block.
Example Usage
Here are some example projects/contracts that would leverage the clarity-bitcoin-lib contract in their own code.
Square Runes
A Clarity implementation for parsing Bitcoin Runes protocol data. Check out the project repo here.
Bitcoin Transaction Enabled NFT
This contract example implements a basic NFT collection that is mintable only upon a user's bitcoin transaction. You can find this template available in the Hiro Platform.
Additional Resources
Last updated
Was this helpful?
