Derive Stacks address from keys
Generate Stacks addresses from private or public keys using multiple methods
import { getPublicKeyFromPrivate } from "@stacks/encryption";import {getAddressFromPrivateKey,getAddressFromPublicKey} from "@stacks/transactions";// Derive address from private keyconst privateKey = process.env.PRIVATE_KEY; // Keep this secret!const addressFromPrivate = getAddressFromPrivateKey(privateKey, "testnet");// Derive public key and addressconst publicKey = getPublicKeyFromPrivate(privateKey);const addressFromPublic = getAddressFromPublicKey(publicKey, "testnet");console.log("Address:", addressFromPrivate);console.log("Public key:", publicKey);console.log("Same address:", addressFromPrivate === addressFromPublic); // true
Use cases
- Wallet address generation
- Key pair validation
- Address recovery from backup keys
- Multi-signature wallet setup
Key concepts
Stacks addresses are derived through:
- Private key: 32-byte random number (keep secret!)
- Public key: Derived from private key using ECDSA
- Address: Base58check-encoded hash of public key
- Network: Different prefixes for mainnet (SP/SM) vs testnet (ST/SN)
Generate new key pair
import { randomPrivateKey } from "@stacks/transactions";import { getPublicKeyFromPrivate } from "@stacks/encryption";// Generate random private keyconst privateKey = randomPrivateKey();const publicKey = getPublicKeyFromPrivate(privateKey);// Derive addresses for both networksconst mainnetAddress = getAddressFromPrivateKey(privateKey, "mainnet");const testnetAddress = getAddressFromPrivateKey(privateKey, "testnet");console.log({privateKey,publicKey,mainnetAddress, // SP...testnetAddress // ST...});
Compressed vs uncompressed keys
import {publicKeyToAddress,AddressVersion} from "@stacks/transactions";// Public key formatsconst compressedPubKey = "03ef788b3830c00abe8f64f62dc32fc863bc0b2cafeb073b6c8e1c7657d9c2c3ab";const uncompressedPubKey = "04ef788b3830c00abe8f64f62dc32fc863bc0b2cafeb073b6c8e1c7657d9c2c3ab5c392bbf70494b84fd7388e6a89811c8f2bc2aca41d3c5a9f7d95f8ed8f8e1a1";// Both generate same addressconst address1 = publicKeyToAddress(AddressVersion.TestnetSingleSig,compressedPubKey);const address2 = publicKeyToAddress(AddressVersion.TestnetSingleSig,uncompressedPubKey);console.log(address1 === address2); // true
Address validation
import { validateStacksAddress } from "@stacks/transactions";function isValidAddress(address: string, network: "mainnet" | "testnet"): boolean {try {return validateStacksAddress(address, network);} catch {return false;}}// Examplesconsole.log(isValidAddress("SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159", "mainnet")); // trueconsole.log(isValidAddress("ST3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159", "testnet")); // trueconsole.log(isValidAddress("SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159", "testnet")); // false
Security warning
Never expose private keys in code or logs. Use environment variables and secure key management systems. Consider hardware wallets for production use.
Batch address generation
import { randomPrivateKey, getAddressFromPrivateKey } from "@stacks/transactions";interface KeyPair {index: number;privateKey: string;address: string;}// Generate multiple addressesfunction generateKeyPairs(count: number, network: "mainnet" | "testnet"): KeyPair[] {return Array.from({ length: count }, (_, index) => {const privateKey = randomPrivateKey();const address = getAddressFromPrivateKey(privateKey, network);return { index, privateKey, address };});}// Generate 5 testnet addressesconst keyPairs = generateKeyPairs(5, "testnet");keyPairs.forEach(({ index, address }) => {console.log(`Address ${index}: ${address}`);});
HD wallet derivation
import { deriveStxAddressChain } from "@stacks/wallet-sdk";import { generateMnemonic } from "@stacks/encryption";// Generate or use existing mnemonicconst mnemonic = generateMnemonic();// Derive addresses from seed phraseconst { address, privateKey, publicKey } = deriveStxAddressChain(mnemonic,0, // account index0 // address index);console.log({address, // Stacks addresspublicKey, // Compressed public keyprivateKey // Private key for this address});// Derive multiple addresses from same seedconst addresses = Array.from({ length: 5 }, (_, i) =>deriveStxAddressChain(mnemonic, 0, i).address);