Wednesday, December 6, 2023

javascript – Methods to signal a PSBT with BitcoinerLAB?


To begin with, We’re utilizing bitcoinerLab.

Example

From the seed, we generate the Grasp Key, and with the trail, we create the kid key 0 (the mother or father’s) and youngster key 1 (the kid’s). Now, from these keys, we get hold of the Grandchild keys with which we are going to generate infinite addresses containing the next coverage:

or(pk(@dadKey),and(pk(@sonKey),after(20)))

What we would like is that by means of a Grandchild deal with, which could have funds locked by the earlier coverage, we want both the mother or father or the kid to attempt to create a transaction and unlock these funds.

Within the descriptor that I create, I go the GrandChildKey’s public key.

var publickeydad=masterNode.derivePath(`m${ORIGIN_PATH}${KEY_PATH}/0`).publicKey;

    const wshDescriptor = new Descriptor({
        expression: wshExpression,
        community,
        signersPubKeys: [publickeydad] 
    });

Now, the difficulty arises when signing the PSBT. We need to signal it with ChildKey 0, which can correspond to ‘dadKey’ in our coverage. The error happens proper right here within the ‘masterNode’ attribute. How ought to we signal it?

descriptors.signers.signBIP32({ psbt, masterNode: descriptors.keyExpressionBIP32({
        masterNode: masterNode,
        originPath: ORIGIN_PATH,
        keyPath: `${KEY_PATH}`
    })});

In abstract, we need to generate infinite GrandChild addresses with the beforehand described coverage, and we need to signal transactions both with ChildKey0 or ChildKey1 to unlock the funds within the GrandChild addresses:

The total code:


import * as bitcoin from "bitcoinjs-lib";
import { Psbt, networks } from 'bitcoinjs-lib';
import * as ecpair from "ecpair";
import * as secp from "tiny-secp256k1";
const ECPair = ecpair.ECPairFactory(secp);
import * as fs from 'fs';
import * as secp256k1 from '@bitcoinerlab/secp256k1';
import * as descriptors from '@bitcoinerlab/descriptors';
import { compilePolicy } from '@bitcoinerlab/miniscript';
import { generateMnemonic, mnemonicToSeedSync } from 'bip39';
import { encode as afterEncode } from 'bip65';

const ORIGIN_PATH = `/69420'/1'/0'`; 
const KEY_PATH = `/0/0`; 
const community = networks.testnet;
const { Descriptor, BIP32, ECPair2 } = descriptors.DescriptorsFactory(secp256k1);
var coverage =`or(pk(@dadKey),and(pk(@sonKey),after(20)))`;


async perform send_tx(){
    const toAddress="mqCMd6LtWXLqKgCiPyVzzhKQvb1AKixgtu"
    const community = networks.testnet;
    const EXPLORER = 'https://blockstream.data/testnet';

    const masterNode = BIP32.fromSeed(mnemonicToSeedSync('uncle business hospital amused when paper timber actual accuse unique squeeze vote'),community); 
    const wshAddress="tb1q8rnzmm5ttrl8fc94y94vpyzf62e69cq85v7dwvve33h3ta85xlpqe7wdhl"
    const utxo = await (
    await fetch(`${EXPLORER}/api/deal with/${wshAddress}/utxo`)
    ).json();

    if (utxo?.[0]) {
        const txHex = await (
        await fetch(`${EXPLORER}/api/tx/${utxo?.[0].txid}/hex`)
    ).textual content();
    const inputValue = utxo[0].worth;
    const psbt = new Psbt({ community });
    
    const wshExpression = "wsh(andor(pk([57836ab7/69420'/1'/0']tpubDDLpvA16cXnaKBY4r8sy7fmZV5ATP9a2ik7kycRKn3twfEFngNGPk8u2CYfR2yrLqLJFdHjh2Pm3YWHTFoepVaFeewHaqoSmFUbxbbLzhfa/0/1/0),after(20),pk([57836ab7/69420'/1'/0']tpubDDLpvA16cXnaKBY4r8sy7fmZV5ATP9a2ik7kycRKn3twfEFngNGPk8u2CYfR2yrLqLJFdHjh2Pm3YWHTFoepVaFeewHaqoSmFUbxbbLzhfa/0/0/0)))"

    // La clave publica del GRANDchild del padre
    var publickeydad=masterNode.derivePath(`m${ORIGIN_PATH}${KEY_PATH}/0`).publicKey;

    const wshDescriptor = new Descriptor({
        expression: wshExpression,
        community,
        signersPubKeys: [publickeydad] 
    });
    
    wshDescriptor.updatePsbt({ psbt, txHex, vout: utxo[0].vout });
   
    psbt.addOutput({
        deal with: toAddress,
        worth: inputValue - 1000
    });

    descriptors.signers.signBIP32({ psbt, masterNode: descriptors.keyExpressionBIP32({
        masterNode: masterNode,
        originPath: ORIGIN_PATH,
        keyPath: `${KEY_PATH}`
    })});
    

    wshDescriptor.finalizePsbtInput({ index: 0, psbt });
    const spendTx = psbt.extractTransaction();
    const spendTxPushResult = await (
        await fetch(`${EXPLORER}/api/tx`, {
        methodology: 'POST',
        physique: spendTx.toHex()
        })
    ).textual content();
    console.log(`Pushing: ${spendTx.toHex()}`);
    console.log(`Tx pushed with consequence: ${spendTxPushResult}`);

    }


}


send_tx()

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles