Welcome to Bitcoin Cash development! If you're coming from other blockchain platforms or traditional web development, the UTXO (Unspent Transaction Output) model might be a new concept to grasp. This guide will break down how UTXOs work in Bitcoin Cash and provide insights on how to design effective smart contracts using this model.
In Bitcoin Cash, think of UTXOs as individual digital bills in your wallet. Unlike account-based blockchains (like Ethereum) that track a single balance for each address, Bitcoin Cash tracks specific "bills" of cryptocurrency.
When you create a transaction in Bitcoin Cash:
- You're consuming existing UTXOs as inputs
- Creating new UTXOs as outputs
- The sum of outputs cannot exceed the sum of inputs
- Any difference between input and output amounts becomes the miner fee
This model might seem less intuitive at first, but it offers excellent parallelization capabilities and privacy benefits.
Each UTXO in Bitcoin Cash has a "locking script" (also called a scriptPubKey) attached to it. As a developer, you'll be designing these scripts to define the conditions under which a UTXO can be spent.
Think of a locking script as a list of requirements that must be met. When someone wants to spend a UTXO, they must provide an "unlocking script" (scriptSig) that satisfies all conditions in the locking script.
This differs fundamentally from Solidity smart contracts on EVM chains. In Bitcoin Cash:
- Code doesn't define actions to be executed
- Code defines constraints that must be satisfied
- Anything not explicitly constrained is permitted
This last point is crucial to internalize as you design contracts.
The most common contract in Bitcoin Cash is P2PKH (Pay-to-Public-Key-Hash). It requires:
- A valid signature matching a specified public key hash
- The signature must cover the transaction data
As you build your first contracts, you'll likely use this pattern often. It ensures only the holder of a specific private key can spend the funds.
With Bitcoin Cash's enhanced script capabilities, you can develop more complex contracts. For example, using CashScript (a high-level language for Bitcoin Cash contracts), you could write:
contract SplitPayment {
function spend(pubkey pk, sig s) {
// Verify signature
require(checkSig(s, pk));
// Ensure 50% goes to each recipient
int amount = tx.inputs[this.activeInputIndex].value;
require(tx.outputs[0].value == amount / 2);
require(tx.outputs[0].address == 0x123...);
require(tx.outputs[1].value == amount / 2);
require(tx.outputs[1].address == 0x456...);
}
}
Important Developer Note: When your locking script doesn't require a signature verification (like checkSig
), any third party on the network can create a transaction spending that UTXO. This can be intentional—allowing for trustless, automatic execution—but make sure you understand the implications. Without signature requirements, you're creating a contract that anyone can trigger, not just specific users or yourself.
Many developers new to Bitcoin Cash make the mistake of under-constraining their contracts. For example:
// Problematic contract
contract IncompleteDistribution {
function spend() {
// Only constrain one output
require(tx.outputs[0].value == tx.inputs[this.activeInputIndex].value / 2);
require(tx.outputs[0].address == 0x123...);
// Remaining 50% not constrained!
}
}
In this example, the second 50% is unconstrained. The person creating the transaction can send it anywhere—likely to themselves! Don't assume that funds automatically return to you or your contract; explicitly constrain every output you care about.
When testing your Bitcoin Cash contracts:
- Use testnet or local regtest environments first
- Consider all possible transaction structures that could satisfy your constraints
- Remember that miners will include any valid transaction regardless of your intentions
- Test edge cases like zero amounts or maximum integer values
The UTXO model in Bitcoin Cash offers powerful capabilities for creating trustless, secure, and efficient smart contracts. As you develop, always remember the fundamental principle: explicitly constrain everything you care about, because anything not constrained is permitted.
By thinking in terms of constraints rather than procedures, you'll be able to create robust contracts that behave exactly as intended. Welcome to Bitcoin Cash development—we're excited to see what you'll build!