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()

typescript
How to create an address using its 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()

Warning

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().

typescript
How to Create an address from a hex string
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 P2OP

With fromBigInt()

typescript
How to Create an address from a bigint
import { Address } from '@btc-vision/transaction';

const address = Address.fromBigInt(12345678901234567890n);

fromUint64Array()

typescript
How to Create an address from a Uint64Array
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.

typescript
How to get the dead address
// Special "dead" address (all zeros)
const deadAddress = Address.dead();
console.log('Dead address:', deadAddress.toHex());
// Output: 0x0000000000000000000000000000000000000000000000000000000000000000
console.log(deadAddress.isDead());  
// Output: true

Network Support

Remember, address formats vary depending on the network. The following examples demonstrate how to specify a network when working with the Address class.

typescript
How to use address with networks
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.

typescript
How to compare 2 addresses
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.

typescript
How to sort addresses
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.

typescript
How to use the CSV feature
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.

typescript
How to securely dispose address
{
    using address = Address.fromString('0x...', '0x...');
    const taproot = address.p2tr(networks.bitcoin);
    // ... use address
} // address is securely zeroed when it goes out of scope

Complete Example

typescript
How to get all supported address types
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));