Skip to main content
Smart contracts in BRC2.0 follow a familiar lifecycle. The key difference from Ethereum is how each action is submitted: rather than broadcasting to an EVM mempool, every operation is inscribed onto Bitcoin and processed when confirmed.

Overview

 Deploy          Call             Persist State     Emit Logs      Withdraw
   │               │                    │               │              │
Inscribe       Inscribe             Committed        Standard       Released
bytecode   →   calldata   →       on success   →   EVM events  →  to BRC-20
to module      to module           Replayed from    Reproducible   No bridge
                                   Bitcoin history  by indexers    required

Deploy

1

Compile your contract

Compile your Solidity contract to EVM bytecode using the standard toolchain (Hardhat, Foundry, etc.). The output is identical to what you would deploy on Ethereum.
forge build
2

Inscribe the bytecode

Create an Ordinals inscription that contains your compiled bytecode and submit it to the BRC2.0 Programmable Module address. This is the equivalent of sending a deployment transaction on Ethereum.
3

Wait for Bitcoin confirmation

The deployment is executed deterministically when the inscription is indexed. The contract address is derived using standard EVM creation semantics — the same formula as CREATE on Ethereum.
4

Contract is live

Once indexed, the contract is part of the global execution state. Any subsequent inscription can call it.
There is no deployment transaction in the Ethereum sense. Deployment is triggered by a Bitcoin transaction carrying the inscription data. The contract address is deterministic and can be computed before the Bitcoin transaction confirms.

Call

Contracts are invoked by inscribing calldata and submitting it to the module. From the contract’s perspective, the call behaves exactly like a normal EVM transaction:
  • Calldata is ABI-encoded
  • Execution either succeeds or reverts
  • All EVM opcodes behave as expected
// Standard ABI-encoded calldata — no changes needed
bytes memory calldata = abi.encodeWithSelector(
    MyContract.transfer.selector,
    recipient,
    amount
);
Calls may be authenticated using either:
  • Bitcoin-native identity — via BIP-322 signature passed as calldata
  • Signed EVM transactions — using the transact operation, if explicitly supported
Multiple contracts can be composed and called within a single execution, subject to gas limits derived from inscription size.
Minimize calldata size to reduce Bitcoin fees. Use tightly packed ABI encoding and consider compression (NADA or ZSTD) for large payloads.

Persist state

Contract state is persisted exactly as in Ethereum:
  • Storage writes are committed on successful execution
  • Reverted calls do not modify state
  • State transitions are deterministic and replayable
State is not stored on Bitcoin directly. Instead, it is reconstructed by replaying all valid inscriptions in order. As long as two indexers process the same Bitcoin history, they will arrive at identical contract state.
This is conceptually similar to Ethereum archive node replay. Any compliant indexer can reconstruct the full state from the Bitcoin chain alone — no external data source is required.

Emit logs

Contracts emit standard EVM events. These logs:
  • Follow Ethereum’s event model exactly (emit, indexed topics, ABI-encoded data)
  • Can be indexed by off-chain services and frontends using standard EVM tooling
  • Are deterministic and replayable from Bitcoin history
event Transfer(address indexed from, address indexed to, uint256 value);

function transfer(address to, uint256 amount) external {
    // ... transfer logic
    emit Transfer(msg.sender, to, amount);
}
Logs are not written to Bitcoin. They are derived from execution and can be reproduced by any compliant indexer.
Standard Ethereum event indexers and subgraph tooling can be adapted to consume BRC2.0 logs, since the event format is identical to Ethereum.

Withdraw back to BRC-20

Contracts can release assets back to base BRC-20 balances via withdrawals. How it works:
  • Assets are locked under contract control during execution
  • A withdrawal reduces the contract’s internal balance
  • The corresponding BRC-20 balance becomes spendable on Bitcoin again
Withdrawals are finalized through Bitcoin transactions and do not rely on bridges or custodians. From your contract’s perspective, this behaves like exiting from a smart contract back to the base asset layer, with Bitcoin providing final settlement.
// Conceptual example — actual withdrawal interface defined in protocol docs
function withdraw(address recipient, uint256 amount) external {
    require(balances[msg.sender] >= amount, "Insufficient balance");
    balances[msg.sender] -= amount;
    // Triggers BRC-20 release back to the recipient's Bitcoin address
    BRC20_MODULE.withdraw(recipient, amount);
}
Withdrawals are finalized on Bitcoin and are irreversible once confirmed. Ensure your contract’s authorization logic is correct before releasing assets.

Lifecycle summary

PhaseSubmitted asEthereum equivalent
DeployInscription (bytecode)eth_sendTransaction (contract creation)
CallInscription (calldata)eth_sendTransaction (contract call)
State persistenceDeterministic replayEVM state trie update
LogsDerived from executionEVM receipt logs
WithdrawBitcoin transactionN/A (exits to native BTC layer)