Address Class

OP_NET provides the Address class to manage all address requirements. This class offers a comprehensive set of methods and properties for address generation, validation, conversion, and manipulation across all supported address types and networks.

Address Creation

The Address class can be instantiated using two methods:

  • constructor: Creates an address from raw key data.
  • fromString(): Parses an address from its hexadecimal string representation.

Using constructor()

The Address constructor accepts two optional parameters:

  • mldsaPublicKey: The quantum-resistant ML-DSA public key.
  • publicKeyOrTweak: The classical public key or tweak value. Valid lengths are 32, 33, or 65 bytes.

If no parameters are provided, an empty address instance is created. If only mldsaPublicKey is provided, the address is initialized with quantum-resistant key data only.

The following example shows how to create an Address using its constructor:
typescript
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);

// Generate addresses
const p2op = address.p2op(networks.bitcoin);
const p2tr = address.p2tr(networks.bitcoin);

Using fromString()

The static fromString() method creates an Address instance from hexadecimal strings. It accepts the ML-DSA public key as the first parameter and an optional classical public key as the second. Both parameters must be in hexadecimal format. The '0x' prefix is automatically stripped if present.

The following example shows how to create an Address from a hex string:
typescript
import { Address } from '@btc-vision/transaction';

// Create address from hex strings
const address = Address.fromString(
    '0xabcdef1234567890...',  // ML-DSA public key hash (32 bytes hex)
    '0x02...'                 // Classical public key (33 bytes hex)
);

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.

The following example shows how to get the dead address:
typescript
// Special "dead" address (all zeros)
const deadAddress = Address.dead();
console.log('Dead address:', deadAddress.toHex());
// Output: 0x0000000000000000000000000000000000000000000000000000000000000000

Address Methods and Properties

The Address class exposes multiple methods and properties such as mldsaPublicKey for accessing the quantum-resistant public key and originalPublicKey for the classical public key. It also provides utility methods including toHex() for hexadecimal representation and toBuffer() for binary conversion, among others.

See Address.ts source code for the Address class definition.

The following code snippet shows how to use some methods and properties:
typescript
const address = wallet.address;

// Quantum address (SHA-256 hash of ML-DSA public key) - Universal public key
console.log('Quantum address:', address.toHex());
console.log('Quantum address buffer:', address.toBuffer());

// Classical public key
console.log('Classical key (hex):', address.tweakedToHex());
console.log('Classical key (buffer):', address.tweakedPublicKeyToBuffer());

// Original keys
console.log('Full ML-DSA public key:', address.mldsaPublicKey);  // 1312-2592 bytes
console.log('Original classical key:', address.originalPublicKey);

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.

Mainnet

The following example shows how to use Address with Mainnet:
typescript
import { Mnemonic, Address } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';

const mnemonic = Mnemonic.generate();

const wallet = mnemonic.derive(0);

// All mainnet addresses
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

The following example shows how to use Address with Testnet:
typescript
import { Mnemonic, MLDSASecurityLevel, Address } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';

// Testnet with different prefixes
const mnemonic = Mnemonic.generate(
    undefined,                            // Default strength (24 words)
    '',                                   // No passphrase
    networks.testnet,                     // Testnet network
    MLDSASecurityLevel.LEVEL2             // Security level
);

const wallet = mnemonic.derive(0);

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

The following example shows how to use Address with Regtest:
typescript
import { Mnemonic, MLDSASecurityLevel, Address } from '@btc-vision/transaction';

// Regtest for local development
const regtestMnemonic = Mnemonic.generate(
    undefined,                            // Default strength (24 words)
    '',                                   // No passphrase
    networks.regtest,                     // Regtest network
    MLDSASecurityLevel.LEVEL2             // Security level
);

const wallet = regtestMnemonic.derive(0);

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.

The following example shows how to compare 2 addresses:
typescript
import { Mnemonic, MLDSASecurityLevel } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';

const wallet1 = mnemonic.derive(0);
const wallet2 = mnemonic.derive(0);
const wallet3 = mnemonic.derive(1);

const addr1 = wallet1.address;
const addr2 = wallet2.address;
const addr3 = wallet3.address;

// Same derivation index = same address
console.log(addr1.equals(addr2));  // true

// Different index = different address
console.log(addr1.equals(addr3));  // false

Ordering

For ordering comparisons, use the lessThan() and greaterThan() methods. These methods enable sorting and ordering operations on address collections.

The following example shows how to sort addresses:
typescript
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.

The following example shows how to use the CSV feature:
typescript
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);

Complete Example

The following example shows how to get all supported address types:
typescript
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));