Skip to main content

Reading the Bitcoin state

Advanced
Bitcoin
Tutorial

Overview

To read information from the Bitcoin network's state, the Bitcoin integration API exposes the following methods:

  • bitcoin_get_utxos: Returns the unspent transaction outputs (UTXOs) of a Bitcoin address.

  • bitcoin_get_balance: Returns the balance of a Bitcoin address.

  • bitcoin_get_current_fee_percentiles: Returns the percentiles of the fees for the last 10_000 transactions. Returns the fee in millisatoshi per virtual byte.

Standard Bitcoin addresses (P2PKH, P2SH, P2WPKH, etc) are supported.

Bitcoin networks

Both the Bitcoin testnet and mainnet networks are supported. The network can be specified as a parameter in each function.

API costs

Each call to the API has a cost of cycles, therefore a sufficient amount of cycles must be sent with each call.

Cycles costs will vary between the Bitcoin testnet and mainnet. For a breakdown of the costs, see Bitcoin API costs.

Reading unspent transaction outputs

To read unspent transaction outputs from the Bitcoin network, make a call to the bitcoin_get_utxos Bitcoin API method. You can create a function in your canister to call this method such as:

type ManagementCanisterActor = actor {
bitcoin_get_utxos : GetUtxosRequest -> async GetUtxosResponse;
};

public func get_utxos(network : Network, address : BitcoinAddress) : async GetUtxosResponse {
ExperimentalCycles.add(GET_UTXOS_COST_CYCLES);
await management_canister_actor.bitcoin_get_utxos({
address;
network;
filter = null;
})
};

Then make a call to this canister's function with the command:

dfx canister --network=ic call CANISTER_NAME get_utxos '("ADDRESS")'

Replace CANISTER_NAME with your canister's name and replace ADDRESS with your Bitcoin address. Learn more about Bitcoin addresses.

Reading current balance

To read the current balance of a Bitcoin address, make a call to the bitcoin_get_balance Bitcoin API method. You can create a function in your canister to call this method such as:

  type ManagementCanisterActor = actor {
bitcoin_get_balance : GetBalanceRequest -> async Satoshi;
};

let management_canister_actor : ManagementCanisterActor = actor("aaaaa-aa");

public func get_balance(network : Network, address : BitcoinAddress) : async Satoshi {
ExperimentalCycles.add(GET_BALANCE_COST_CYCLES);
await management_canister_actor.bitcoin_get_balance({
address;
network;
min_confirmations = null;
})
};

Then make a call to this canister's function with the command:

dfx canister --network=ic call CANISTER_NAME get_balance '("ADDRESS")'

Replace CANISTER_NAME with your canister's name and replace ADDRESS with your Bitcoin address. Learn more about Bitcoin addresses.

Reading the fee percentile

The transaction fees in the Bitcoin network change dynamically based on the number of pending transactions. In order to get fee percentiles for the last few blocks (4 - 10), call bitcoin_get_current_fee_percentiles.

The function returns 101 numbers that are fees measured in millisatoshi per virtual byte. The i-th element of the result corresponds to the i-th percentile fee. For example, to get the median fee over the last few blocks, look at the 50-th element of the result.

  type ManagementCanisterActor = actor {
bitcoin_get_current_fee_percentiles : GetCurrentFeePercentilesRequest -> async [MillisatoshiPerVByte];
};

let management_canister_actor : ManagementCanisterActor = actor("aaaaa-aa");

public func get_current_fee_percentiles(network : Network) : async [MillisatoshiPerVByte] {
ExperimentalCycles.add(GET_CURRENT_FEE_PERCENTILES_COST_CYCLES);
await management_canister_actor.bitcoin_get_current_fee_percentiles({
network;
})
};

Then make a call to this canister's function with the command:

dfx canister --network=ic call CANISTER_NAME get_current_fee_percentiles

Replace CANISTER_NAME with your canister's name.

Resources