Using Address
OP_NET provides the Address class as the unified representation for all address operations throughout the library. This class offers methods and properties for creating addresses from various input formats, validating address correctness, converting between address types and extracting the underlying public key data, all while enforcing network-specific encoding rules.
Refers to the Address Reference section for technical information about the Address class.
Address Creation
The Address class provides several ways to create an instance, depending on the input format available:
- constructor(): Creates an address directly from raw public key bytes
- fromString(): Parses an address from its hexadecimal string representation.
- fromBigInt(): Creates an address from a 256-bit unsigned integer.
- fromUint64Array(): Creates an address from four 64-bit big-endian unsigned integers.
Using constructor()
import { Address } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
// From ML-DSA public key hash and classical public key
const mldsaHash = Buffer.alloc(32, 0x01); // SHA256 of ML-DSA public key
const classicalKey = Buffer.from('02...', 'hex'); // 33-bytes compressed key
const address = new Address(mldsaHash, classicalKey);
// Get addresses
const p2op = address.p2op(networks.bitcoin);
const p2tr = address.p2tr(networks.bitcoin);Using static Methods
fromString()
This method takes hex-encoded public keys, NOT bech32 addresses. Passing bc1q... or bc1p... will throw an error. If you only have an address string, resolve it to a public key first via provider.getPublicKeyInfo().
import { Address } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
const address = Address.fromString(
'0x9a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b',
'0x020373626d317ae8788ce3280b491068610d840c23ecb64c14075bbb9f670af52c',
);
// Get various address formats
console.log(address.toHex()); // ML-DSA hash (universal ID)
console.log(address.p2tr(networks.bitcoin)); // bc1p...
console.log(address.p2wpkh(networks.bitcoin)); // bc1q...
console.log(address.p2pkh(networks.bitcoin)); // 1...
console.log(address.p2shp2wpkh(networks.bitcoin)); // 3...
console.log(address.p2op(networks.bitcoin)); // bech32m P2OPWith fromBigInt()
import { Address } from '@btc-vision/transaction';
const address = Address.fromBigInt(12345678901234567890n);fromUint64Array()
import { Address } from '@btc-vision/transaction';
const address = Address.fromUint64Array(111111111n, 222222222n, 333333333n, 444444444n);Dead Address
The dead address is a special address for which no private key exists. The Address class provides the dead() method to retrieve the standard dead address.
// Special "dead" address (all zeros)
const deadAddress = Address.dead();
console.log('Dead address:', deadAddress.toHex());
// Output: 0x0000000000000000000000000000000000000000000000000000000000000000
console.log(deadAddress.isDead());
// Output: trueNetwork Support
Remember, address formats vary depending on the network. The following examples demonstrate how to specify a network when working with the Address class.
import { Mnemonic, Address } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
const mnemonic = Mnemonic.generate();
const wallet = mnemonic.derive(0);
// Mainnet
console.log('P2OP:', wallet.address.p2op(networks.bitcoin)); // bc1s...
console.log('P2TR:', wallet.address.p2tr(networks.bitcoin)); // bc1p...
console.log('P2WPKH:', wallet.address.p2wpkh(networks.bitcoin)); // bc1q...
console.log('P2PKH:', wallet.address.p2pkh(networks.bitcoin)); // 1...
// Testnet
console.log('P2OP:', wallet.address.p2op(networks.testnet)); // tb1s...
console.log('P2TR:', wallet.address.p2tr(networks.testnet)); // tb1p...
console.log('P2WPKH:', wallet.address.p2wpkh(networks.testnet)); // tb1q...
console.log('P2PKH:', wallet.address.p2pkh(networks.testnet)); // m... or n...
// Regtest
console.log('P2OP:', wallet.address.p2op(networks.regtest)); // bcrt1s...
console.log('P2TR:', wallet.address.p2tr(networks.regtest)); // bcrt1p...Address Comparison
Equality
To compare two Address instances, use the equals() method. This method performs a proper comparison of the underlying address data and returns true if both addresses are identical.
import { Mnemonic, MLDSASecurityLevel } from '@btc-vision/transaction';
const addr1 = Address.fromString('0xaabb...', '0x02...');
const addr2 = Address.fromString('0xaabb...', '0x03...');
const addr3 = Address.fromString('0xccdd...', '0x02...');
console.log(addr1.equals(addr2)); // true (same ML-DSA hash)
console.log(addr1.equals(addr3)); // false (different ML-DSA hash)Ordering
For ordering comparisons, use the lessThan() and greaterThan() methods. These methods enable sorting and ordering operations on address collections.
import { Mnemonic, MLDSASecurityLevel } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
// Generate wallet with ML-DSA support
const mnemonic = Mnemonic.generate(
undefined, // Default strength (24 words)
'', // No passphrase
networks.bitcoin, // Mainnet
MLDSASecurityLevel.LEVEL2 // Security level
);
const wallet = mnemonic.derive(0);
const addresses = [
mnemonic.derive(5).address,
mnemonic.derive(2).address,
mnemonic.derive(8).address,
mnemonic.derive(1).address,
];
// Less than comparison
console.log(addresses[0].lessThan(addresses[1]));
// Greater than comparison
console.log(addresses[0].greaterThan(addresses[1]));
// Sort addresses
addresses.sort((a, b) => {
if (a.lessThan(b)) return -1;
if (a.greaterThan(b)) return 1;
return 0;
});Time-Locked Addresses (CSV)
CSV (CheckSequenceVerify) addresses enable time-locked transactions where funds can only be spent after a specified number of blocks have passed. Use the toCSV() method to generate a CSV address from an existing Address instance. This method accepts two parameters: the the lock duration in blocks and network configuration.
import { Mnemonic, MLDSASecurityLevel } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
// Generate wallet with ML-DSA support
const mnemonic = Mnemonic.generate(
undefined, // Default strength (24 words)
'', // No passphrase
networks.bitcoin, // Mainnet
MLDSASecurityLevel.LEVEL2 // Security level
);
const wallet = mnemonic.derive(0);
// Create time-locked address (100 blocks)
const duration = 100;
const csvAddress = wallet.address.toCSV(duration, networks.bitcoin);
console.log('CSV Address (100 blocks):', csvAddress);
// Different durations
const addr1Day = wallet.address.toCSV(144, networks.bitcoin); // ~1 day
const addr1Week = wallet.address.toCSV(1008, networks.bitcoin); // ~1 week
const addr1Month = wallet.address.toCSV(4320, networks.bitcoin); // ~1 month
// Valid range: 1 to 65535 blocks
const minLock = wallet.address.toCSV(1, networks.bitcoin);
const maxLock = wallet.address.toCSV(65535, networks.bitcoin);Secure disposal
The Address class implements the disposable pattern, allowing sensitive key material to be securely zeroed when the object goes out of scope. Using the using keyword ensures automatic cleanup without manual intervention, preventing key data from persisting in memory after use.
{
using address = Address.fromString('0x...', '0x...');
const taproot = address.p2tr(networks.bitcoin);
// ... use address
} // address is securely zeroed when it goes out of scopeComplete Example
import { Mnemonic, MLDSASecurityLevel } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
// Generate wallet with ML-DSA support
const mnemonic = Mnemonic.generate(
undefined, // Default strength (24 words)
'', // No passphrase
networks.bitcoin, // Mainnet
MLDSASecurityLevel.LEVEL2 // Security level
);
const wallet = mnemonic.derive(0);
const address = wallet.address;
console.log('=== Universal Public Key (Quantum Address) ===');
console.log('Quantum Address:', address.toHex()); // SHA-256 hash of ML-DSA public key
console.log('ML-DSA Key Size:', address.mldsaPublicKey?.length, 'bytes');
console.log('\n=== P2OP Address (Contract Address) ===');
console.log('P2OP:', address.p2op(networks.bitcoin)); // Encoded form of quantum address
console.log('\n=== Classical Addresses ===');
console.log('P2TR (Taproot):', address.p2tr(networks.bitcoin));
console.log('P2WPKH (SegWit):', address.p2wpkh(networks.bitcoin));
console.log('P2PKH (Legacy):', address.p2pkh(networks.bitcoin));
console.log('P2SH-P2WPKH:', address.p2shp2wpkh(networks.bitcoin));
console.log('\n=== Testnet Addresses ===');
console.log('P2OP:', address.p2op(networks.testnet));
console.log('P2TR:', address.p2tr(networks.testnet));
console.log('\n=== Time-Locked Address ===');
console.log('CSV (100 blocks):', address.toCSV(100, networks.bitcoin));