Skip to content

Addresses

An Address is the base58check encoding of a Public Key hash (or, for P2SH, a script hash) along with a network prefix. What an Address is, and why it is only a wallet convention, is covered in the guide’s Addresses page.

The same key gives a different Address string on each network, while the hash inside it stays the same.

final publicKey = SVPrivateKey.fromWIF('cVVvUsNHhbrgd7aW3gnuGo2qJM45LhHhTCVXrDSJDDcNGE6qmyCs').publicKey;
final testnet = Address.fromPublicKey(publicKey, NetworkType.TEST);
final mainnet = Address.fromPublicKey(publicKey, NetworkType.MAIN);
// testnet: mu4DpTaD75nheE4z5CQazqm1ivej1vzL4L
// mainnet: 1EYGXQVEJ4MSs7bNMdSDAvYgrw42Aoe4FU

Both privateKey.toAddress(networkType: ...) and publicKey.toAddress(network) are shortcuts for the same thing.

Address(String) decodes a base58 Address, and reads its network and type from the prefix.

final address = Address('mu4DpTaD75nheE4z5CQazqm1ivej1vzL4L');
address.networkType; // NetworkType.TEST
address.addressType; // AddressType.PUBKEY_HASH
address.pubkeyHash160; // the 20-byte hash160 of the public key, hex-encoded
address.toBase58(); // the original string; toString() is the same

If all we hold is the 20-byte hash, we can build the Address from that:

final address = Address.fromPubkeyHash(hash, NetworkType.MAIN); // hash: 40 hex characters

Parsing throws on bad input, so validation becomes a try/catch. It is worth checking the network as well. A mainnet Address is well-formed, but it is the wrong Address for a testnet wallet.

bool isValidAddress(String input, NetworkType expected) {
try {
return Address(input).networkType == expected;
} on BadChecksumException {
return false; // mistyped, or not base58check at all
} on AddressFormatException {
return false; // unknown version byte
}
}

To pay an Address, the Transaction Output carries a P2PKH Locking Script built from the Address’s hash. TransactionBuilder.spendToPKH does this for us. P2PKHLockBuilder does it on its own, and can also read the Address back out of a script.

final address = Address('mu4DpTaD75nheE4z5CQazqm1ivej1vzL4L');
final lockingScript = P2PKHLockBuilder.fromAddress(address).getScriptPubkey();
// OP_DUP OP_HASH160 20 0x94837d2d5d6106aa97db38957dcc294181ee91e9 OP_EQUALVERIFY OP_CHECKSIG
// Reading an Output's script back into an Address, we name the network ourselves.
final recovered = P2PKHLockBuilder.fromScript(lockingScript, networkType: NetworkType.TEST).address;

Do note that a Locking Script contains no network. P2PKHLockBuilder.fromScript defaults to mainnet unless you pass networkType.

Address.fromScript hashes a script and encodes it as a P2SH Address (prefix 3 on mainnet, 2 on testnet). Since the Genesis upgrade, Bitcoin SV no longer accepts new P2SH Outputs as standard. See P2SH for the cases where you will still meet them.

final redeemScript = SVScript.fromString('OP_1'); // any script
final p2shAddress = Address.fromScript(redeemScript, NetworkType.MAIN);
p2shAddress.toString(); // 3MaB7QVq3k4pQx3BhsvEADgzQonLSBwMdj
p2shAddress.addressType; // AddressType.SCRIPT_HASH