BRC20 Programmable Module
Written By zbam
Last updated 5 days ago
BRC2.0 extends BRC-20's inscription-based token standard with an EVM-compatible execution layer, enabling smart contracts, DeFi primitives, and composable applications on Bitcoin. While BRC-20 provides token operations (deploy, mint, transfer), BRC2.0 provides a programmable computing environment where Solidity contracts can execute with full access to Bitcoin's state.
What BRC2.0 Adds to BRC-20
BRC2.0 introduces four major capabilities:
Smart contracts: Deploy Solidity contracts inscribed on Bitcoin, with state transitions validated by indexers running EVM execution Deposit/Withdraw bridge: Move BRC-20 tokens into BRC2.0 contracts as ERC-20-compatible assets Bitcoin precompiles: Native access to Bitcoin transaction verification, signature validation (BIP322), and UTXO queries Event system: Contract logs that applications can subscribe to for real-time updates
The core insight: BRC2.0 maintains the metaprotocol model—execution happens off Bitcoin's base layer with results tracked by indexers—but adds computational expressiveness previously impossible with BRC-20 alone.
Architecture and Execution Model
BRC2.0 indexers run an EVM-compatible execution environment alongside traditional BRC-20 state tracking. When you inscribe a BRC2.0 operation (deploy contract, call function, deposit tokens), indexers:
Parse the inscription: Extract BRC2.0 JSON from the Ordinals envelope
Validate the operation: Check signature, nonce, and gas limits
Execute EVM bytecode: Run the transaction in their local EVM instance
Update state: Commit storage changes, logs, and balance updates
Achieve consensus: All indexers must produce identical state transitions
This creates a deterministic state machine whose history is anchored in Bitcoin inscriptions but whose execution happens off-chain.
State Separation
BRC2.0 maintains two distinct state domains:
BRC-20 state: Traditional token balances tracked by BRC-20 inscriptions
BRC2.0 contract state: EVM storage, contract accounts, and internal token balances
You can move assets between these domains using deposit/withdraw operations, creating a bridge between Bitcoin-native tokens and smart contract applications.
BRC2.0 Operation Types
BRC2.0 defines three new operation types beyond BRC-20's deploy/mint/transfer:
Deploy Operation
Deploy a Solidity contract to the BRC2.0 execution layer:
{
"p": "brc20-prog",
"op": "deploy", // or d for short
"d": "0x608060405234801561001057600080fd5b50...",
}The bytecode is compiled Solidity (use Hardhat, Foundry, or Remix). Indexers execute the constructor and assign the contract an address derived from the inscription ID.
Call Operation
Invoke a function on a deployed contract:
{
"p": "brc20-prog",
"op": "call", // or c for short
"c": "<CONTRACT_ADDRESS>,
"b": "<BASE64_ENCODED_CALLDATA>”
}This triggers EVM execution of the specified function with provided arguments. Indexers validate gas limits and update contract state accordingly.
Transact Operation
Combined deposit/withdraw with contract call—move BRC-20 tokens into a contract and invoke a function in one operation:
{
"p": "brc20-prog",
"op": "transact", // or t for short
"b": "<BASE64_ENCODED_COMPRESSED_EVM_TRANSACTION>
}This is the primary pattern for DeFi interactions: deposit tokens, execute trade/stake/lend, and optionally withdraw results.
Deposit and Withdraw Mechanics
BRC2.0 includes a built-in bridge for moving BRC-20 tokens into smart contracts:
Deposit Flow
Create deposit inscription: Specify ticker and amount to deposit
Indexers lock BRC-20 balance: Tokens move from BRC-20 state to "deposited" state
Mint internal BRC-20: Contract receives equivalent tokens as ERC-20 balance
You can use tokens: Trade, stake, lend, etc. using Solidity logic
Deposit 1000 ORDI into BRC2.0
{
"p": "brc-20",
"op": "deposit",
"tick": "ordi",
"amt": "1000"
}Sending this inscription to OP_RETURN "BRC20PROG" will transfer your ORDI into BRC2.0 programmable module.
Withdraw Flow
Create an inscription with the amount to withdraw
{
"p": "brc20-module",
"op": "withdraw",
"tick": "ordi",
"amt": "10",
"module": "BRC20PROG"
}Sending this to any address other than `OP_RETURN` will withdraw the balance from BRC2.0 into base BRC20
This creates a trustless bridge—no multisig or validator set required. Indexers enforce the rules deterministically based on inscriptions and EVM execution.
Precompiles
BRC2.0 introduces specialized precompiled contracts for Bitcoin-native operations:
BIP-322 Verifier Precompile
EVM addresses are generated from Bitcoin scripts, and they can’t sign messages, instead, you can use a precompile to validate BIP-322 signatures instead using this precompile:
// Precompile address at 0xFE
/**
* @dev BIP322 verification method
*/
interface IBIP322_Verifier {
function verify(
bytes calldata pkscript,
bytes calldata message,
bytes calldata signature
) external returns (bool success);
}Use cases: Caller verification, authentication and authorization using Bitcoin wallets
BTC Transaction Verification Precompile
Verify Bitcoin transactions and extract data from them:
// Precompile address at 0xFD
/**
* Get Bitcoin transaction details using tx ids.
*/
interface IBTC_Transaction {
function getTxDetails(
bytes32 txid
)
external
view
returns (
uint256 block_height,
bytes32[] memory vin_txids,
uint256[] memory vin_vouts,
bytes[] memory vin_scriptPubKeys,
uint256[] memory vin_values,
bytes[] memory vout_scriptPubKeys,
uint256[] memory vout_values
);
}Use case: Trustless Bitcoin payment verification—contracts can confirm that specific Bitcoin transactions occurred, enabling payment-triggered logic.
Last Satoshi Location Precompile
Find the last location of an individual satoshi
// Precompile address at 0xFC
/**
* @dev Get last satoshi location of a given sat location in a transaction.
*/
interface IBTC_LastSatLoc {
function getLastSatLocation(
bytes32 txid,
uint256 vout,
uint256 sat
) external view returns (
bytes32 last_txid,
uint256 last_vout,
uint256 last_sat,
bytes memory old_pkscript,
bytes memory new_pkscript
);
}Lock PkScript Precompile
Check if a BRC-20 token holder has locked their inscriptions to a specific Bitcoin script:
// Precompile address at 0xFB
/**
* @dev Get locked pkscript of a given Bitcoin wallet script.
*/
interface IBTC_LockedPkscript {
function getLockedPkscript(
bytes calldata pkscript,
uint256 lock_block_count
) external view returns (bytes memory locked_pkscript);
}Use case: Staking and governance—users lock ordinals on Bitcoin to prove commitment, contracts verify the lock status and grant voting rights or rewards.
BIP322 Signature Precompile
Verify BIP-322 signatures (generic Bitcoin message signing):
// Precompile at address 0xFE
/**
* @dev BIP322 verification method
*/
interface IBIP322_Verifier {
function verify(
bytes calldata pkscript,
bytes calldata message,
bytes calldata signature
) external returns (bool success);
}Use case: Bitcoin identity verification—users sign messages with their Bitcoin private keys, contracts verify signatures to authorize actions without requiring users to hold Ethereum-style keys.
These precompiles bridge Bitcoin's UTXO model with BRC2.0's account model, enabling hybrid applications that leverage both ecosystems.
OP_RETURN TX ID precompile
Transaction that activates the BRC2.0 inscription (TX that sends the inscription to OP_RETURN) can be retrieved from a smart contract using this precompile:
// Precompile at address 0xFA
interface TxIdPrecompile {
function getBtcTxId() external view returns (bytes32);
}Use cases: Binding contract state or events to a specific bitcoin transaction, deterministic linkage between on-chain btc activity and evm-level logic, implementing receipt-style verification, replay protection, or audit trails
EVM Compatibility and Limitations
BRC2.0 aims for Solidity compatibility but has key differences from Ethereum:
Supported:
Solidity syntax and features
Standard library contracts (OpenZeppelin, etc.)
Events and logs
Storage operations (SSTORE, SLOAD)
Standard opcodes (ADD, MUL, CALL, etc.)
Modified:
Block time: ~10 minutes (Bitcoin's block interval)
Gas model: Different gas costs due to indexer execution constraints
Address format: Uses generated EVM addresses from Bitcoin-native addresses (bc1p...), hence, the EVM addresses cannot sign messages
block.number refers to Bitcoin block height
block.timestamp is Bitcoin block time (less granular), bitcoin block times can go backwards, so this is a less reliable metric
msg.value in native ETH doesn't exist (use token deposits instead)
Gas Model
BRC2.0 uses a Bitcoin-anchored gas model:
Gas limits prevent infinite loops during indexer execution
If execution exceeds gas limit, the transaction reverts and state is not updated—standard EVM behavior.
When to Use BRC2.0 vs BRC-20
Use BRC-20 when:
Simple token operations suffice (hold, send, receive)
You want maximum compatibility with existing wallets/tools
Lower complexity and gas costs are priorities
No programmable logic is required
Use BRC2.0 when:
Building DeFi protocols (DEXes, lending, staking)
Requiring conditional logic or multi-party interactions
Implementing governance or DAO functionality
Need access to Bitcoin state (transaction verification, locks)
Building composable applications that interact with other contracts
Example: DEX Implementation
A simple constant product AMM in BRC2.0:
contract SimpleDEX {
mapping(address => uint256) public balancesA;
mapping(address => uint256) public balancesB;
uint256 public reserveA;
uint256 public reserveB;
event Swap(address indexed user, uint256 amountIn, uint256 amountOut);
function deposit(string calldata tick, uint256 amount) external {
// Called via BRC2.0 deposit operation
if (keccak256(bytes(tick)) == keccak256("ordi")) {
balancesA[msg.sender] += amount;
reserveA += amount;
} else if (keccak256(bytes(tick)) == keccak256("sats")) {
balancesB[msg.sender] += amount;
reserveB += amount;
}
}
function swap(uint256 amountIn, bool aToB) external {
uint256 amountOut;
if (aToB) {
require(balancesA[msg.sender] >= amountIn, "Insufficient balance");
amountOut = getAmountOut(amountIn, reserveA, reserveB);
balancesA[msg.sender] -= amountIn;
balancesB[msg.sender] += amountOut;
reserveA += amountIn;
reserveB -= amountOut;
} else {
require(balancesB[msg.sender] >= amountIn, "Insufficient balance");
amountOut = getAmountOut(amountIn, reserveB, reserveA);
balancesB[msg.sender] -= amountIn;
balancesA[msg.sender] += amountOut;
reserveB += amountIn;
reserveA -= amountOut;
}
emit Swap(msg.sender, amountIn, amountOut);
}
function withdraw(string calldata tick, uint256 amount) external {
// Burns internal balance, indexer credits BRC-20
if (keccak256(bytes(tick)) == keccak256("ordi")) {
require(balancesA[msg.sender] >= amount);
balancesA[msg.sender] -= amount;
reserveA -= amount;
} else {
require(balancesB[msg.sender] >= amount);
balancesB[msg.sender] -= amount;
reserveB -= amount;
}
emit Withdraw(msg.sender, tick, amount);
}
function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut)
internal pure returns (uint256)
{
uint256 amountInWithFee = amountIn * 997;
uint256 numerator = amountInWithFee * reserveOut;
uint256 denominator = (reserveIn * 1000) + amountInWithFee;
return numerator / denominator;
}
}Users interact by:
Depositing ORDI or SATS into the contract (moves from BRC-20 to contract state)
Calling swap() to trade (pure EVM execution, instant)
Withdrawing back to BRC-20 balance (returns to Bitcoin-native tokens)
This is impossible with BRC-20 alone—you'd need centralized order books and manual matching. BRC2.0 enables automatic execution with deterministic pricing.
Indexer Requirements and Node Operation
Running a BRC2.0 indexer requires:
Bitcoin full node: ~600GB storage, validates all transactions Ordinals indexer: Tracks inscription data and satoshi ownership EVM execution engine: Modified geth or similar (provided by BRC2.0 implementation) State database: Stores BRC-20 and BRC2.0 state (PostgreSQL, LevelDB, etc.)
Most developers will query public indexers rather than running their own:
Lower operational complexity
No infrastructure costs
Faster time to market
Run your own indexer if you need:
Custom validation rules
High query throughput
Independence from third-party services
Ability to audit state transitions
Security Model and Trust Assumptions
BRC2.0 inherits BRC-20's trust model with additional considerations:
Immutability: Contract bytecode inscribed on Bitcoin cannot be changed Determinism: All indexers must produce identical state given same inscriptions Social consensus: If indexers diverge, community must choose canonical implementation Upgradability: Use proxy patterns (similar to Ethereum) for upgradeable contracts Precompile trust: Bitcoin verification precompiles rely on correct implementation in indexer code
Critical insight: BRC2.0 security depends on indexer correctness. If the EVM implementation has bugs or deviates from specification, contract execution may diverge across indexers. This is why reference implementations and test suites are essential.
Comparison to Other Bitcoin Smart Contract Solutions
BRC2.0 vs Lightning Network:
Lightning: Payment channels for Bitcoin transfers (no tokens, no arbitrary computation)
BRC2.0: Full smart contracts with token support
BRC2.0 vs Stacks:
Stacks: Separate blockchain with its own consensus (Proof of Transfer)
BRC2.0: Metaprotocol anchored directly to Bitcoin inscriptions
BRC2.0 vs Rootstock (RSK):
RSK: Sidechain with merge-mining and 2-way peg bridge
BRC2.0: No separate chain, state tracked by indexers
BRC2.0 vs RGB:
RGB: Client-side validation for asset transfers
BRC2.0: Server-side (indexer) validation with EVM compatibility
Development Workflow
Typical BRC2.0 development process:
Write Solidity contracts: Use Hardhat, Foundry, or Remix as usual
Test locally: Deploy to local BRC2.0 node or testnet
Compile to bytecode: Generate deployment bytecode and ABI
Inscribe contract: Create deploy inscription with bytecode
Wait for confirmation: Bitcoin block must confirm (~10 minutes)
Interact via inscriptions: Call functions by inscribing call operations
Monitor events: Subscribe to indexer APIs for contract logs
The cycle time is slower than Ethereum due to Bitcoin's block interval, but inscriptions provide permanent on-chain history of all interactions.
Ecosystem Readiness
As of launch (2025), BRC2.0 is in early stages with growing infrastructure:
Available:
Reference indexer implementation
Solidity compiler support
Block explorers for contracts
Developer documentation and SDKs
In development:
Wallet integrations (MetaMask-style for BRC2.0)
Developers building on BRC2.0 today are pioneers—expect rough edges but also opportunities to define standards and capture early ecosystem value.
To start building with BRC2.0:
Review the BRC2.0 JSON Schema documentation for operation formats
Explore BRC2.0 Deposit/Withdraw mechanics for token bridges
Study Bitcoin Precompiles for native Bitcoin integration
Build a simple contract following the guides
BRC2.0 represents the evolution of Bitcoin from settlement layer to programmable platform, while maintaining the inscription-based guarantees that made BRC-20 successful.
Further reading:BRC2.0 Specification |Solidity Documentation