Using P2OP
How to use P2OP in OP_NET
P2OP addresses are used exclusively for OP_NET smart contract addresses. The Address class provides a static p2op() method to generate P2OP addresses from contract bytes.
P2OP addresses use a custom HRP (Human-Readable Part) defined in the network configuration as bech32Opnet. Ensure your network configuration includes this property.
Generating a P2OP Address
Use the static Address.p2op() method to generate a P2OP address from contract bytes. The method accepts the contract bytes, network configuration, and an optional deployment version.
import { Address } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
// Contract bytes (e.g., from deployment or contract identifier)
const contractBytes = Buffer.from('your-contract-identifier', 'utf8');
// Generate P2OP address for mainnet
const p2opAddress = Address.p2op(contractBytes, networks.bitcoin);
console.log('P2OP Address:', p2opAddress);
// Output: opnet1s...
// Generate P2OP address for testnet
const p2opTestnet = Address.p2op(contractBytes, networks.testnet);
console.log('P2OP Testnet:', p2opTestnet);
// Output: optest1s...
// Generate P2OP address with custom deployment version
const p2opV1 = Address.p2op(contractBytes, networks.bitcoin, 1);
console.log('P2OP Version 1:', p2opV1);Method Signature
The p2op() method has the following signature:
public static p2op(
bytes: Buffer | Uint8Array,
network: Network = networks.bitcoin,
deploymentVersion: number = 0,
): stringParameters
- bytes: The contract identifier bytes as a Buffer or Uint8Array.
- network: The Bitcoin network configuration (default: networks.bitcoin).
- deploymentVersion: The deployment version byte (default: 0).
Returns
Returns the Bech32m-encoded P2OP address string.
Internal Implementation
The P2OP address generation follows these steps internally:
// 1. Create witness program with deployment version prefix
const witnessProgram = Buffer.concat([
Buffer.from([deploymentVersion]),
bitcoin.crypto.hash160(Buffer.from(bytes)),
]);
// 2. Validate witness program length (2-40 bytes required)
if (witnessProgram.length < 2 || witnessProgram.length > 40) {
throw new Error('Witness program must be 2-40 bytes.');
}
// 3. Compile script with OP_16 (SegWit version 16)
const scriptData = script.compile([opcodes.OP_16, witnessProgram]);
// 4. Encode using Bech32m with custom OP_NET HRP
return fromOutputScript(scriptData, network);Network Configuration
P2OP addresses require the network to have a bech32Opnet property defined. This custom HRP ensures P2OP addresses are distinguishable from standard Bitcoin addresses.
const customNetwork: Network = {
...networks.bitcoin,
bech32Opnet: 'opnet', // Custom HRP for P2OP addresses
};If the network does not have bech32Opnet defined, the toFutureOPNetAddress() encoding function will throw an error: "Network does not support opnet".
Bech32m Encoding for P2OP
P2OP uses the toFutureOPNetAddress() function which handles the Bech32m encoding for SegWit versions 2-16:
import { bech32m } from 'bech32';
export function toFutureOPNetAddress(output: Buffer, network: Network): string {
if (!Buffer.isBuffer(output)) throw new TypeError('output must be a Buffer');
if (!network.bech32Opnet) throw new Error('Network does not support opnet');
const opcode = output[0];
// Parse the push-data to extract the witness program
let pushPos = 1, progLen: number;
if (output[1] < 0x4c) {
progLen = output[1];
pushPos = 2;
} else if (output[1] === 0x4c) {
progLen = output[2];
pushPos = 3;
} else {
throw new TypeError('Unsupported push opcode in script');
}
const program = Buffer.from(output.subarray(pushPos, pushPos + progLen));
// Determine SegWit version from opcode
const version =
opcode === opcodes.OP_0
? 0
: opcode >= opcodes.OP_1 && opcode <= opcodes.OP_16
? opcode - (opcodes.OP_1 - 1)
: -1;
// Encode with Bech32m and custom HRP
const words = [version, ...bech32m.toWords(program)];
return bech32m.encode(network.bech32Opnet, words);
}Use Cases
P2OP addresses are primarily used for:
- Contract Deployment: Generating deterministic addresses for deployed contracts.
- Contract Interaction: Specifying the target contract in transaction outputs.
- Contract Discovery: Sharing readable contract addresses with users.
- Cross-Version Compatibility: The deployment version allows for future contract format upgrades.