PHP code example of nova-carnivore / bolt12-php

1. Go to this page and download the library: Download nova-carnivore/bolt12-php library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

nova-carnivore / bolt12-php example snippets


use Nova\Bitcoin\Bolt12\Decoder;

$offer = Decoder::decode('lno1...');      // Returns Offer object
$invReq = Decoder::decode('lnr1...');     // Returns InvoiceRequest object
$invoice = Decoder::decode('lni1...');    // Returns Invoice object

use Nova\Bitcoin\Bolt12\Encoder;
use Nova\Bitcoin\Bolt12\Signer;

$encoded = Encoder::encodeOffer(
    issuerId: $myPublicKeyHex,
    description: 'Buy a coffee',
    amountMsat: gmp_init(100000),
    issuer: 'CoffeeShop',
);
// Returns: 'lno1...'

$invReq = Encoder::encodeInvoiceRequest(
    invreqMetadata: bin2hex(random_bytes(32)),
    payerId: $myPublicKeyHex,
    payerPrivateKey: $myPrivateKeyHex,
    offerDescription: 'Buy a coffee',
    offerIssuerId: $merchantPubkey,
    offerAmountMsat: gmp_init(100000),
);
// Returns: 'lnr1...' (signed with BIP-340 Schnorr)

use Nova\Bitcoin\Bolt12\BlindedPath;
use Nova\Bitcoin\Bolt12\BlindedPayInfo;
use Nova\Bitcoin\Bolt12\OnionMessageHop;

$invoice = Encoder::encodeInvoice(
    nodeId: $myNodePubkey,
    nodePrivateKey: $myNodePrivkey,
    createdAt: gmp_init(time()),
    paymentHash: hash('sha256', $preimage),
    amountMsat: gmp_init(100000),
    invoicePaths: [
        new BlindedPath($blindingKey, [
            new OnionMessageHop($nodeId, $encryptedData),
        ]),
    ],
    blindedPayInfo: [
        new BlindedPayInfo(
            feeBaseMsat: 1000,
            feeProportionalMillionths: 100,
            cltvExpiryDelta: 144,
            htlcMinimumMsat: gmp_init(1000),
            htlcMaximumMsat: gmp_init(1000000000),
        ),
    ],
);
// Returns: 'lni1...' (signed with BIP-340 Schnorr)

use Nova\Bitcoin\Bolt12\Signer;

$invReq = Decoder::decode('lnr1...');
$valid = Signer::verifyInvoiceRequest($invReq);  // Returns bool

$invoice = Decoder::decode('lni1...');
$valid = Signer::verifyInvoice($invoice);  // Returns bool

// Encode
$errorBytes = Encoder::encodeInvoiceError(
    error: 'Amount too low',
    erroneousField: gmp_init(82),  // invreq_amount
    suggestedValue: '0186a0',      // 100000 as tu64 hex
);

// Decode
$invoiceError = Decoder::decodeInvoiceError($errorBytes);
echo $invoiceError->error;  // 'Amount too low'

use Nova\Bitcoin\Bolt12\{Decoder, Encoder, Signer, BlindedPath, BlindedPayInfo, OnionMessageHop};

// 1. Merchant creates an offer
$offer = Encoder::encodeOffer(
    issuerId: $merchantPubkey,
    description: 'Buy a coffee',
    amountMsat: gmp_init(100000),
);
$decoded = Decoder::decode($offer);

// 2. Payer creates invoice request (mirrors offer fields)
$invReq = Encoder::encodeInvoiceRequest(
    invreqMetadata: bin2hex(random_bytes(32)),
    payerId: $payerPubkey,
    payerPrivateKey: $payerPrivkey,
    offerDescription: $decoded->description,
    offerIssuerId: $decoded->issuerId,
    offerAmountMsat: $decoded->amountMsat,
);

// 3. Merchant creates and signs invoice
$invoice = Encoder::encodeInvoice(
    nodeId: $merchantPubkey,
    nodePrivateKey: $merchantPrivkey,
    createdAt: gmp_init(time()),
    paymentHash: hash('sha256', $preimage),
    amountMsat: gmp_init(100000),
    invoicePaths: [$blindedPath],
    blindedPayInfo: [$payInfo],
);

// 4. Payer verifies invoice signature
$inv = Decoder::decode($invoice);
assert(Signer::verifyInvoice($inv));

use Nova\Bitcoin\Bolt12\Exception\{
    Bolt12Exception,       // Base exception
    DecodeException,       // Malformed input
    EncodeException,       // Missing/invalid fields
    SignatureException,    // Signature issues
};

try {
    $offer = Decoder::decode($bolt12String);
} catch (DecodeException $e) {
    // Malformed string or TLV data
} catch (Bolt12Exception $e) {
    // Any BOLT 12 error
}
bash
composer