Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Interact with Dogecoin from a smart contract on the Internet Computer

Introduction

Work In Progress

🚧 The developer documentation is under construction.

The Build on Dogecoin book is intended for developers to explain how smart contracts on the Internet Computer, often referred as canisters, can interact with the Dogecoin blockchain.

Background

Through a protocol-level integration with the Dogecoin network, canisters deployed on ICP can interact with the Dogecoin network directly without using a bridge or oracle.

To interact with the Dogecoin blockchain, your canister will make use of the following:

  • Dogecoin canister: Think of it as your decentralized gateway to reach the Dogecoin blockchain. This canister provides an API that can be used by others to query information about the Dogecoin network state, for example, unspent transaction outputs (UTXOs), block headers, or the balance of any Dogecoin address; and to send transactions to the network.

  • Threshold ECDSA: Your canister can have a secret key that is stored in a secure and decentralized manner using chain-key cryptography (several such keys can be computed by key derivation). Messages sent by the canister can be signed using this key, enabling your canister to send signed transactions to the Dogecoin network through the Dogecoin canister.

To submit a Dogecoin transaction from a canister, the following steps are typically performed:

  • Request a public key from the threshold ECDSA API
  • Derive a Dogecoin address from the public key
  • Read UTXOs from the Dogecoin API
  • Build the transaction payload
  • Sign the transaction using the threshold ECDSA API
  • Submit the transaction to the Dogecoin API

Getting Started

First, set up your development environment. Then, to build canisters interacting with the Dogecoin network, you will need to know how to:

Additional resources

Building Dogecoin applications is not trivial. It’s beneficial to understand core Bitcoin concepts which underpin Dogecoin, including transactions, UTXOs, the Script language, and hash formats.

Developer Environment

To develop Dogecoin applications to be deployed on ICP, your local developer environment will need to include:

  • A local Dogecoin regtest node.

  • The Rust toolchain for installing Rust crates and compiling Rust code.

  • The IC SDK for creating, deploying, and managing canisters. You can install it natively on macOS and Linux; however, Windows users will need to set up WSL 2 before installing the IC SDK.

Create a local Dogecoin network (regtest) with dogecoind

It is recommended to set up a local Dogecoin regtest network to mine blocks quickly and at will, which facilitates testing various cases without having to rely on the Dogecoin mainnet where blocks are produced every minute on average.

Example for a Linux machine:

# Download the binary
curl -L -O https://github.com/dogecoin/dogecoin/releases/download/v1.14.9/dogecoin-1.14.9-x86_64-linux-gnu.tar.gz

# Unpack
tar -xvf dogecoin-1.14.9-x86_64-linux-gnu.tar.gz

# Add binaries to the PATH environment variable
export PATH="$(pwd)/dogecoin-1.14.9/bin:$PATH"

Mac OS X users

There are currently no released binaries for Mac OS X. You will need to build Dogecoin Core from source. Follow the instructions in the Dogecoin Core repository.

This should be created in the project folder root. This allows you to run different local Dogecoin regtest networks for different projects.

mkdir dogecoin_data
cat > dogecoin_data/dogecoin.conf <<EOF
regtest=1
txindex=1
rpcuser=ic-doge-integration
rpcpassword=QPQiNaph19FqUsCrBRN0FII7lyM26B51fAMeBQzCb-E=
rpcauth=ic-doge-integration:cdf2741387f3a12438f69092f0fdad8e\$62081498c98bee09a0dce2b30671123fa561932992ce377585e8e08bb0c11dfa
EOF

Explanation of settings:

  • regtest=1: Enables Dogecoin’s regression test mode for local testing.

  • txindex=1: Maintains a full transaction index to support lookups by transaction ID.

  • rpcuser=ic-doge-integration: Sets a default username for JSON-RPC authentication.

  • rpcpassword=QPQ…b-E=: Sets the password for JSON-RPC authentication.

  • rpcauth=ic-doge-integration:cdf…dfa: Uses an alternative authentication method for RPC, combining the username and a salted hash.

Find more details about the dogecoin.conf settings in the Dogecoin Core Daemon documentation.

dogecoind -datadir=$(pwd)/dogecoin_data -printoconsole --port=18444 

This command assumes that port 18444 on your machine is available. If it isn't, change the specified port accordingly.

Deploy your first app locally

Work In Progress

🚧 Coming soon!

Dogecoin API Endpoints

To be able to reach the Dogecoin network, your canister needs to target one of the available endpoints on the Dogecoin canister.

Dogecoin Canister

Dogecoin canister principal ID: gordg-fyaaa-aaaan-aaadq-cai

Testnet?

Dogecoin testnet is not supported.

Available Endpoints

dogecoin_get_utxos

Returns the UTXOs associated with a Dogecoin address. UTXOs can be filtered by minimum confirmations (only UTXOs with at least the provided number of confirmations are returned, with some upper bound which varies with the current difficulty target) or via a page reference when pagination is used for addresses with many UTXOs.

dogecoin_get_utxos_query

Queries dogecoin_get_utxos using a query call. Since this is a query call, it returns quickly but results are not trustworthy.

dogecoin_get_balance

Returns the balance of a Dogecoin address in koinus (1 DOGE = 100,000,000 koinus). Takes an optional argument min_confirmations which can be used to limit the set of considered UTXOs for the calculation of the balance to those with at least the provided number of confirmations.

dogecoin_get_balance_query

Queries dogecoin_get_balance using a query call. Since this is a query call, it returns quickly but results are not trustworthy.

dogecoin_get_current_fee_percentiles

Returns fee percentiles (in millikoinus/byte) from the most recent 1,000 Dogecoin transactions.

dogecoin_get_block_headers

Returns raw block headers for a given range of heights. At most 100 block headers are returned per request.

dogecoin_send_transaction

Sends a raw Dogecoin transaction to the specified network (mainnet or regtest).

Further references

See the Dogecoin canister interface specification for more details.

Cycles Cost

The costs of API calls in cycles and USD for the Dogecoin Mainnet APIs are presented in the following table. As a general principle for the Dogecoin API, some API calls must have a minimum number of cycles attached to them, as indicated in the column Minimum cycles to send with call. Requiring a relatively large minimum number of cycles makes it possible to change the pricing of API calls without breaking existing canisters when the Dogecoin subnet grows in terms of its replication factor in the future. Cycles not consumed by the call are returned to the caller.

The call for submitting a Dogecoin transaction to the Dogecoin network does not require a minimum number of cycles to send with the call as the charged cost is independent of the replication factor of the subnet.

The cost per API call in USD uses the XDR/USD exchange rate of November 25, 2025 (1 XDR = 1.411492 USD).

API callDescriptionPrice (Cycles)Price (USD)Minimum cycles to send with call
dogecoin_get_utxosRetrieve the UTXO set for a Dogecoin address50_000_000 + 1 cycle per Wasm instruction$0.00007058 + Wasm instruction cost10_000_000_000
dogecoin_get_current_fee_percentilesObtain the fee percentiles of the most recent transactions10_000_000$0.00001412100_000_000
dogecoin_get_balanceRetrieve the balance of a given Dogecoin address10_000_000$0.00001412100_000_000
dogecoin_send_transactionSubmit a Dogecoin transaction to the Dogecoin network, per transaction5_000_000_000$0.00706N/A
dogecoin_send_transactionSubmit a Dogecoin transaction to the Dogecoin network, per byte of payload20_000_000$0.00002823N/A
dogecoin_get_block_headersRetrieve the block headers in specified range50_000_000 + 1 cycle per Wasm instruction$0.00007058 + Wasm instruction cost10_000_000_000

Note

Fees for calling the dogecoin_get_utxos and dogecoin_get_block_headers endpoints depend on the number of Wasm instructions that the Dogecoin canister consumes when processing the requests to ensure fair charging.

Dogecoin Transactions

Generating a Dogecoin address

Dogecoin, like Bitcoin, doesn't use accounts; instead, it uses a UTXO model. A UTXO is a Dogecoin transaction output that is unspent.

Each UTXO is associated with a Dogecoin address that is derived from either a public key or a script that defines the conditions under which the UTXO can be spent. A Dogecoin address is often used as a single-use invoice instead of a persistent address to increase privacy.

Dogecoin P2PKH addresses

Pay-to-public-key-hash (P2PKH) addresses are the most common types of addresses in Dogecoin. On mainnet, they start with the prefix D. They encode the hash of an ECDSA public key.

Dogecoin P2SH addresses

Another type of address is pay-to-script-hash (P2SH) address. It encodes the hash of a Dogecoin script and starts with a A or 9 on mainnet. The script can define complex locking conditions such as multisig or timelocks.

Generating addresses with threshold ECDSA

To generate a Dogecoin address, you need to generate an ECDSA public key. An ECDSA public key can be retrieved using the ecdsa_public_key system API endpoint. The basic Dogecoin example demonstrates how to generate a P2PKH address from a public key:

#[update]
pub async fn get_p2pkh_address() -> String {
    let ctx = DOGE_CONTEXT.with(|ctx| ctx.get());

    // Unique derivation paths are used for every address type generated, to ensure
    // each address has its own unique key pair.
    let derivation_path = DerivationPath::p2pkh(0, 0);

    // Get the ECDSA public key of this smart contract at the given derivation path
    let public_key = get_ecdsa_public_key(&ctx, derivation_path.to_vec_u8_path()).await;

    // Convert the public key to the format used by the Dogecoin library
    let public_key = PublicKey::from_slice(&public_key).unwrap();

    // Generate a P2PKH address from the public key.
    // The address encoding (Base58) depends on the network type.
    Address::p2pkh(public_key, ctx.dogecoin_network).to_string()
}

View the source on GitHub: get_p2pkh_address.rs

/// Retrieves the ECDSA public key for the given derivation path from the ECDSA API.
///
/// This function checks the local in-memory cache first. If no cached key exists,
/// it queries the ECDSA API for the public key at the given derivation path
/// and stores the result in the cache.
pub async fn get_ecdsa_public_key(ctx: &DogecoinContext, derivation_path: Vec<Vec<u8>>) -> Vec<u8> {
    // Check in-memory cache first.
    if let Some(key) = ECDSA_KEY_CACHE.with_borrow(|map| map.get(&derivation_path).cloned()) {
        return key;
    }

    // Request the ECDSA public key from the ECDSA API.
    let public_key = management_canister::ecdsa_public_key(&EcdsaPublicKeyArgs {
        canister_id: None,
        derivation_path: derivation_path.clone(),
        key_id: EcdsaKeyId {
            curve: EcdsaCurve::Secp256k1,
            name: ctx.key_name.to_string(),
        },
    })
    .await
    .unwrap()
    .public_key;

    // Store it in the in-memory cache for future reuse.
    ECDSA_KEY_CACHE.with_borrow_mut(|map| {
        map.insert(derivation_path, public_key.clone());
    });

    public_key
}

View the source on GitHub: ecdsa.rs

Resources

Learn more about Dogecoin P2PKH addresses.

Learn more about the ecdsa_public_key API.

Creating Dogecoin Transactions

Unspent transaction outputs (UTXOs) are used as inputs to build Dogecoin transactions. Every Dogecoin transaction spends one or more UTXOs and in return creates new UTXOs. A UTXO exists until it is used as input in a transaction. In order to create a Dogecoin transaction, you need to:

  1. Get the available UTXOs corresponding to a Dogecoin address controlled by your canister using the dogecoin_get_utxos API endpoint.

  2. Calculate an appropriate transaction fee using the dogecoin_get_current_fee_percentiles API endpoint.

  3. Select a subset of the available UTXOs to spend that covers the transaction amount and fee.

  4. Create a transaction that spends the selected UTXOs and creates new UTXOs. You will need at least one for the recipient and, in most cases, one to collect the change.

A UTXO has the following structure:

// Unspent transaction output (UTXO).
pub struct Utxo {
    /// See [Outpoint].
    pub outpoint: Outpoint,
    /// Value in the units of koinu.
    pub value: Koinu,
    /// Height in the blockchain.
    pub height: u32,
}

/// Identifier of [Utxo].
pub struct Outpoint {
    /// Transaction Identifier.
    pub txid: Vec<u8>,
    /// The output index in the transaction.
    pub vout: u32,
}

Get available UTXOs

To get the available UTXOs for a Dogecoin address, use the dogecoin_get_utxos API endpoint. The following example demonstrates how to retrieve UTXOs for a given Dogecoin P2PKH address.

use crate::{dogecoin_get_utxos, DOGE_CONTEXT};
use ic_cdk::{
    bitcoin_canister::{GetUtxosRequest, GetUtxosResponse},
    update,
};

/// Returns the UTXOs of the given Dogecoin address.
#[update]
pub async fn get_utxos(address: String) -> GetUtxosResponse {
    let ctx = DOGE_CONTEXT.with(|ctx| ctx.get());

    dogecoin_get_utxos(&GetUtxosRequest {
        address,
        network: ctx.network.into(),
        filter: None,
    })
    .await
    .unwrap()
}

View the source on GitHub: get_utxo.rs

pub async fn dogecoin_get_utxos(arg: &GetUtxosRequest) -> CallResult<GetUtxosResponse> {
    let canister_id = get_dogecoin_canister_id(&into_dogecoin_network(arg.network));
    // same cycles cost as for the Bitcoin canister
    let cycles = bitcoin_canister::cost_get_utxos(arg);
    Ok(Call::bounded_wait(canister_id, "dogecoin_get_utxos")
        .with_arg(arg)
        .with_cycles(cycles)
        .await?
        .candid()?)
}

View the source on GitHub: lib.rs

Calculate transaction fee per byte

The transaction fee of a Dogecoin transaction is calculated based on the size of the transaction in bytes. An appropriate fee per byte can be determined by looking at the fees of recent transactions on the Dogecoin mainnet. The following snippet shows how to estimate the fee per byte for a transaction using the dogecoin_get_current_fee_percentiles API endpoint and choosing the 50th percentile.

use crate::{dogecoin_get_fee_percentiles, MillikoinuPerByte, DOGE_CONTEXT};
use ic_cdk::{bitcoin_canister::GetCurrentFeePercentilesRequest, update};

/// Returns the 100 fee percentiles measured in millikoinu/byte.
/// Percentiles are computed from the last 10,000 transactions (if available).
#[update]
pub async fn get_current_fee_percentiles() -> Vec<MillikoinuPerByte> {
    let ctx = DOGE_CONTEXT.with(|ctx| ctx.get());

    dogecoin_get_fee_percentiles(&GetCurrentFeePercentilesRequest {
        network: ctx.network.into(),
    })
    .await
    .unwrap()
}

View the source on GitHub: get_current_fee_percentiles.rs

pub async fn dogecoin_get_fee_percentiles(
    arg: &GetCurrentFeePercentilesRequest,
) -> CallResult<Vec<MillikoinuPerByte>> {
    let canister_id = get_dogecoin_canister_id(&into_dogecoin_network(arg.network));
    // same cycles cost as for the Bitcoin canister
    let cycles = bitcoin_canister::cost_get_current_fee_percentiles(arg);
    Ok(
        Call::bounded_wait(canister_id, "dogecoin_get_current_fee_percentiles")
            .with_arg(arg)
            .with_cycles(cycles)
            .await?
            .candid()?,
    )
}

View the source on GitHub: lib.rs

Build the transaction

Now the transaction can be built. Since the fee of a transaction is based on its size, the transaction has to be built iteratively and signed with a mock signer that adds the respective size of the signature. Each selected UTXO is used as an input for the transaction and requires a signature.

The following snippet shows a simplified version of how to build a transaction that will be signed by a P2PKH address:

// Builds a transaction to send the given `amount` of koinu to the
// destination address.
pub async fn build_transaction(
    ctx: &DogecoinContext,
    own_public_key: &PublicKey,
    own_address: &Address,
    own_utxos: &[Utxo],
    primary_output: &PrimaryOutput,
    fee_per_byte: MillisatoshiPerByte,
) -> Transaction {
    // We have a chicken-and-egg problem where we need to know the length
    // of the transaction in order to compute its proper fee, but we need
    // to know the proper fee in order to figure out the inputs needed for
    // the transaction.
    //
    // We solve this problem iteratively. We start with a fee of zero, build
    // and sign a transaction, see what its size is, and then update the fee,
    // rebuild the transaction, until the fee is set to the correct amount.

    let amount = match primary_output {
        PrimaryOutput::Address(_, amt) => *amt, // grab the amount
        PrimaryOutput::OpReturn(_) => trap("expected an address output, got OP_RETURN"),
    };

    let mut fee = 0;
    loop {
        let utxos_to_spend = select_utxos_greedy(own_utxos, amount, fee).unwrap();
        let transaction =
            build_transaction_with_fee(utxos_to_spend, own_address, primary_output, fee).unwrap();

        // Sign the transaction. In this case, we only care about the size
        // of the signed transaction, so we use a mock signer here for efficiency.
        let signed_transaction = sign_transaction(
            ctx,
            own_public_key,
            own_address,
            transaction.clone(),
            vec![], // mock derivation path
            mock_sign_with_ecdsa,
        )
        .await;

        let tx_vsize = signed_transaction.vsize() as u64;

        if (tx_vsize * fee_per_byte) / 1000 == fee {
            return transaction;
        } else {
            fee = (tx_vsize * fee_per_byte) / 1000;
        }
    }
}

View the source on GitHub: p2pkh.rs

Signing Transactions

Before a transaction can be sent to the Dogecoin network, each input must be signed. Canisters can sign transactions with threshold ECDSA through the sign_with_ecdsa system API endpoint.

Threshold ECDSA

The following snippet shows a simplified example of how to sign a Dogecoin transaction where all UTXOs are owned by own_address and own_address is a P2PKH address.

pub async fn sign_transaction<SignFun, Fut>(
    ctx: &DogecoinContext,
    own_public_key: &PublicKey,
    own_address: &Address,
    mut transaction: Transaction,
    derivation_path: Vec<Vec<u8>>,
    signer: SignFun,
) -> Transaction
where
    SignFun: Fn(String, Vec<Vec<u8>>, Vec<u8>) -> Fut,
    Fut: std::future::Future<Output = SecpSignature>,
{
    assert_eq!(
        own_address.address_type(),
        Some(AddressType::P2pkh),
        "Only P2PKH addresses are supported"
    );

    let transaction_clone = transaction.clone();
    let sighash_cache = SighashCache::new(&transaction_clone);

    for (index, input) in transaction.input.iter_mut().enumerate() {
        let sighash = sighash_cache
            .legacy_signature_hash(
                index,
                &own_address.script_pubkey(),
                EcdsaSighashType::All.to_u32(),
            )
            .unwrap();

        let signature = signer(
            ctx.key_name.to_string(),
            derivation_path.clone(),
            sighash.as_byte_array().to_vec(),
        )
        .await;

        let mut signature = signature.serialize_der().to_vec();
        signature.push(EcdsaSighashType::All.to_u32() as u8);

        let sig_bytes = PushBytesBuf::try_from(signature).unwrap();
        let pubkey_bytes = PushBytesBuf::try_from(own_public_key.to_bytes()).unwrap();

        input.script_sig = Builder::new()
            .push_slice(sig_bytes)
            .push_slice(pubkey_bytes)
            .into_script();
    }

    transaction
}

View the source on GitHub: p2pkh.rs

The signature function signer: SignFun passed as argument is shown below. This function makes a call to the sign_with_ecdsa system API endpoint to sign the provided transaction sighash.

/// Signs a 32-byte message hash using the ECDSA key derived from the given path.
///
/// This function uses the ICP ECDSA signing API to produce a compact, 64-byte signature.
pub async fn sign_with_ecdsa(
    key_name: String,
    derivation_path: Vec<Vec<u8>>,
    message_hash: Vec<u8>,
) -> Signature {
    let signature = management_canister::sign_with_ecdsa(&SignWithEcdsaArgs {
        message_hash,
        derivation_path,
        key_id: EcdsaKeyId {
            curve: EcdsaCurve::Secp256k1,
            name: key_name,
        },
    })
    .await
    .unwrap()
    .signature;

    Signature::from_compact(&signature).unwrap()
}

View the source on GitHub: ecdsa.rs

Resources

Complete flow

The following snippet shows the full process, from generating a transaction to submitting it to the Dogecoin network:

use crate::{
    common::{get_fee_per_byte, DerivationPath, PrimaryOutput},
    dogecoin_get_utxos, dogecoin_send_transaction,
    ecdsa::{get_ecdsa_public_key, sign_with_ecdsa},
    p2pkh::{self},
    SendRequest, DOGE_CONTEXT,
};
use bitcoin::{consensus::serialize, dogecoin::Address, PublicKey};
use ic_cdk::{
    bitcoin_canister::{GetUtxosRequest, SendTransactionRequest},
    trap, update,
};
use std::str::FromStr;

/// Sends the given amount of dogecoin from this smart contract's P2PKH address to the given address.
/// Returns the transaction ID.
#[update]
pub async fn send_from_p2pkh_address(request: SendRequest) -> String {
    let ctx = DOGE_CONTEXT.with(|ctx| ctx.get());

    if request.amount_in_koinu == 0 {
        trap("Amount must be greater than 0");
    }

    // Parse and validate the destination address. The address type needs to be
    // valid for the Dogecoin network we are on.
    let dst_address = Address::from_str(&request.destination_address)
        .unwrap()
        .require_network(ctx.dogecoin_network)
        .unwrap();

    // Unique derivation paths are used for every address type generated, to ensure
    // each address has its own unique key pair. To generate a user-specific address,
    // you would typically use a derivation path based on the user's identity or some other unique identifier.
    let derivation_path = DerivationPath::p2pkh(0, 0);

    // Get the ECDSA public key of this smart contract at the given derivation path.
    let own_public_key = get_ecdsa_public_key(&ctx, derivation_path.to_vec_u8_path()).await;

    // Convert the public key to the format used by the rust-dogecoin library.
    let own_public_key = PublicKey::from_slice(&own_public_key).unwrap();

    // Generate a P2PKH address from the public key.
    let own_address = Address::p2pkh(own_public_key, ctx.dogecoin_network);

    // Note that pagination may have to be used to get all UTXOs for the given address.
    // For the sake of simplicity, it is assumed here that the `utxo` field in the response
    // contains all UTXOs.
    let own_utxos = dogecoin_get_utxos(&GetUtxosRequest {
        address: own_address.to_string(),
        network: ctx.network.into(),
        filter: None,
    })
    .await
    .unwrap()
    .utxos;

    // Build the transaction.
    let fee_per_byte = get_fee_per_byte(&ctx).await;
    let transaction = p2pkh::build_transaction(
        &ctx,
        &own_public_key,
        &own_address,
        &own_utxos,
        &PrimaryOutput::Address(dst_address, request.amount_in_koinu),
        fee_per_byte,
    )
    .await;

    // Sign the transaction.
    let signed_transaction = p2pkh::sign_transaction(
        &ctx,
        &own_public_key,
        &own_address,
        transaction,
        derivation_path.to_vec_u8_path(),
        sign_with_ecdsa,
    )
    .await;

    // Send the transaction to the Dogecoin API.
    dogecoin_send_transaction(&SendTransactionRequest {
        network: ctx.network.into(),
        transaction: serialize(&signed_transaction),
    })
    .await
    .unwrap();

    // Return the transaction ID.
    signed_transaction.compute_txid().to_string()
}

View the source on GitHub: send_from_p2pkh_address.rs

/// Input structure for sending Dogecoin.
/// Used in P2PKH transfer endpoint.
#[derive(candid::CandidType, candid::Deserialize)]
pub struct SendRequest {
    pub destination_address: String,
    pub amount_in_koinu: u64,
}

View the source on GitHub: lib.rs

To submit transactions to the Dogecoin network, the Dogecoin API exposes the dogecoin_send_transaction method.

pub async fn dogecoin_send_transaction(arg: &SendTransactionRequest) -> CallResult<()> {
    let canister_id = get_dogecoin_canister_id(&into_dogecoin_network(arg.network));
    // same cycles cost as for the Bitcoin canister
    let cycles = bitcoin_canister::cost_send_transaction(arg);

    Ok(
        Call::unbounded_wait(canister_id, "dogecoin_send_transaction")
            .with_arg(arg)
            .with_cycles(cycles)
            .await?
            .candid()?,
    )
}

View the source on GitHub: lib.rs

Reading the Dogecoin State

Canisters can query information about the Dogecoin mainnet programmatically.

Reading unspent transaction outputs (UTXOs)

To read unspent transaction outputs (UTXOs) associated with an address from the Dogecoin network, make a call to the dogecoin_get_utxos Dogecoin API method.

use crate::{dogecoin_get_utxos, DOGE_CONTEXT};
use ic_cdk::{
    bitcoin_canister::{GetUtxosRequest, GetUtxosResponse},
    update,
};

/// Returns the UTXOs of the given Dogecoin address.
#[update]
pub async fn get_utxos(address: String) -> GetUtxosResponse {
    let ctx = DOGE_CONTEXT.with(|ctx| ctx.get());

    dogecoin_get_utxos(&GetUtxosRequest {
        address,
        network: ctx.network.into(),
        filter: None,
    })
    .await
    .unwrap()
}

View the source on GitHub: get_utxo.rs

/// Gets the UTXOs of a specified address.
///
/// **Bounded-wait call**
///
/// Check the [Dogecoin Canisters Interface Specification](https://github.com/dfinity/dogecoin-canister/blob/master/INTERFACE_SPECIFICATION.md#dogecoin_get_utxos) for more details.
pub async fn dogecoin_get_utxos(arg: &GetUtxosRequest) -> CallResult<GetUtxosResponse> {
    let canister_id = get_dogecoin_canister_id(&into_dogecoin_network(arg.network));
    // same cycles cost as for the Bitcoin canister
    let cycles = bitcoin_canister::cost_get_utxos(arg);
    Ok(Call::bounded_wait(canister_id, "dogecoin_get_utxos")
        .with_arg(arg)
        .with_cycles(cycles)
        .await?
        .candid()?)
}

View the source on GitHub: lib.rs

Reading current balance

To read the current balance of a Dogecoin address, make a call to the dogecoin_get_balance Dogecoin API method.

use crate::{dogecoin_get_balance, Amount, DOGE_CONTEXT};
use ic_cdk::{bitcoin_canister::GetBalanceRequest, update};

/// Returns the balance of the given Dogecoin address.
#[update]
pub async fn get_balance(address: String) -> Amount {
    let ctx = DOGE_CONTEXT.with(|ctx| ctx.get());

    dogecoin_get_balance(&GetBalanceRequest {
        address,
        network: ctx.network.into(),
        min_confirmations: None,
    })
    .await
    .unwrap()
}

View the source on GitHub: get_balance.rs

/// Gets the current balance of a Dogecoin address in Koinu.
///
/// **Bounded-wait call**
///
/// Check the [Dogecoin Canisters Interface Specification](https://github.com/dfinity/dogecoin-canister/blob/master/INTERFACE_SPECIFICATION.md#dogecoin_get_balance) for more details.
pub async fn dogecoin_get_balance(arg: &GetBalanceRequest) -> CallResult<Amount> {
    let canister_id = get_dogecoin_canister_id(&into_dogecoin_network(arg.network));
    // same cycles cost as for the Bitcoin canister
    let cycles = bitcoin_canister::cost_get_balance(arg);
    Ok(Call::bounded_wait(canister_id, "dogecoin_get_balance")
        .with_arg(arg)
        .with_cycles(cycles)
        .await?
        .candid()?)
}

View the source on GitHub: lib.rs

Reading the fee percentiles

The transaction fees on the Dogecoin network change dynamically based on the number of pending transactions. In order to get fee percentiles of the last 1,000 transactions, call the dogecoin_get_current_fee_percentiles Dogecoin API method.

This endpoint returns 101 numbers that are fees measured in millikoinus (1,000 millikoinus = 1 koinu; 100,000,000 koinus = 1 DOGE) per byte. The ith element of the result corresponds to the ith percentile fee. For example, to get the median fee over the last few blocks, look at the 50th element of the result.

use crate::{dogecoin_get_fee_percentiles, MillikoinuPerByte, DOGE_CONTEXT};
use ic_cdk::{bitcoin_canister::GetCurrentFeePercentilesRequest, update};

/// Returns the 100 fee percentiles measured in millikoinu/byte.
/// Percentiles are computed from the last 10,000 transactions (if available).
#[update]
pub async fn get_current_fee_percentiles() -> Vec<MillikoinuPerByte> {
    let ctx = DOGE_CONTEXT.with(|ctx| ctx.get());

    dogecoin_get_fee_percentiles(&GetCurrentFeePercentilesRequest {
        network: ctx.network.into(),
    })
    .await
    .unwrap()
}

View the source on GitHub: get_current_fee_percentiles.rs

/// Gets the current transaction fee percentiles on the Dogecoin network.
///
/// **Bounded-wait call**
///
/// Check the [Dogecoin Canisters Interface Specification](https://github.com/dfinity/dogecoin-canister/blob/master/INTERFACE_SPECIFICATION.md#dogecoin_get_current_fee_percentiles) for more details.
pub async fn dogecoin_get_fee_percentiles(
    arg: &GetCurrentFeePercentilesRequest,
) -> CallResult<Vec<MillikoinuPerByte>> {
    let canister_id = get_dogecoin_canister_id(&into_dogecoin_network(arg.network));
    // same cycles cost as for the Bitcoin canister
    let cycles = bitcoin_canister::cost_get_current_fee_percentiles(arg);
    Ok(
        Call::bounded_wait(canister_id, "dogecoin_get_current_fee_percentiles")
            .with_arg(arg)
            .with_cycles(cycles)
            .await?
            .candid()?,
    )
}

View the source on GitHub: lib.rs

Reading the block headers

To read the block headers within a provided range of start and end heights, make a call to the dogecoin_get_block_headers Dogecoin API method. Note that at most 100 block headers are returned per request.

use crate::{dogecoin_get_block_headers, DOGE_CONTEXT};
use ic_cdk::{
    bitcoin_canister::{GetBlockHeadersRequest, GetBlockHeadersResponse},
    update,
};

/// Returns the block headers in the given height range.
#[update]
pub async fn get_block_headers(
    start_height: u32,
    end_height: Option<u32>,
) -> GetBlockHeadersResponse {
    let ctx = DOGE_CONTEXT.with(|ctx| ctx.get());

    dogecoin_get_block_headers(&GetBlockHeadersRequest {
        start_height,
        end_height,
        network: ctx.network.into(),
    })
    .await
    .unwrap()
}

View the source on GitHub: get_block_headers.rs

/// Gets the block headers in the provided range of block heights.
///
/// **Bounded-wait call**
///
/// Check the [Dogecoin Canisters Interface Specification](https://github.com/dfinity/dogecoin-canister/blob/master/INTERFACE_SPECIFICATION.md#dogecoin_get_block_headers) for more details.
pub async fn dogecoin_get_block_headers(
    arg: &GetBlockHeadersRequest,
) -> CallResult<GetBlockHeadersResponse> {
    let canister_id = get_dogecoin_canister_id(&into_dogecoin_network(arg.network));
    // same cycles cost as for the Bitcoin canister
    let cycles = bitcoin_canister::cost_get_block_headers(arg);
    Ok(
        Call::bounded_wait(canister_id, "dogecoin_get_block_headers")
            .with_arg(arg)
            .with_cycles(cycles)
            .await?
            .candid()?,
    )
}

View the source on GitHub: lib.rs