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