Skip to content

Instantly share code, notes, and snippets.

@setavenger
Created June 4, 2024 19:45
Show Gist options
  • Save setavenger/f2a300e298769be05ee636c97840d1a8 to your computer and use it in GitHub Desktop.
Save setavenger/f2a300e298769be05ee636c97840d1a8 to your computer and use it in GitHub Desktop.
Simple Send to SP using bitcoin-js lib and blindbitd devtools cli

Standard Funding Process

Use this address-key pair (or any other pair):

Mnemonic: zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo mammal

Address: tb1qs7k3knzplrzegwja45suv30584t4ryafk0hyfq (signet/testnet)

Address: bcrt1qs7k3knzplrzegwja45suv30584t4ryaf5xwf7f (regtest)

PrivateKey: 864f2a0f1696d41bf1e5878653df39dd8467a1acf2c88cd5183cf09b4a92a7a2

const bitcoin = require('bitcoinjs-lib');
const {ECPairFactory} = require('ecpair');
const ecc = require('tiny-secp256k1');
const bip39 = require('bip39');
const {BIP32Factory} = require('bip32');

bitcoin.initEccLib(ecc);
const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
// Regtest network details
const network = bitcoin.networks.testnet;

(async function () {
  // todo use proper derivation paths for this test showcase
  const seed = await bip39.mnemonicToSeed(
    'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo mammal', // might want to choose mnemonic to avoid collisions with others
  );
  const privateKey = bip32.fromSeed(seed);
  const keyPair = ECPair.fromPrivateKey(privateKey.privateKey, {
    network: network,
  }); // derive private key from seed
  const {address} = bitcoin.payments.p2wpkh({
    pubkey: keyPair.publicKey,
    network: network,
  });

  // --- these below will obviously change if different seed is used ---
  
  // address is important
  console.log('Source Address:', address);
  // tb1qs7k3knzplrzegwja45suv30584t4ryafk0hyfq testnet/signet
  // bcrt1qs7k3knzplrzegwja45suv30584t4ryaf5xwf7f regtest
  console.log('PrivateKey:', privateKey.privateKey.toString('hex'));
  // 864f2a0f1696d41bf1e5878653df39dd8467a1acf2c88cd5183cf09b4a92a7a2 this is currently the correct one
  // afa1f1d207afee740da43290c173e770e15fc298b6bcd8729b5d77dcbd63ced0
})();

Spend to SP address

use cli devtools (inside blindbitd) to compute the x-only pub key based on the needed information address, txid, vout, privatekey

Then use the javascript script to create and sign the tx.

const bitcoin = require('bitcoinjs-lib');
const {ECPairFactory} = require('ecpair');
const ecc = require('tiny-secp256k1');

bitcoin.initEccLib(ecc);
const ECPair = ECPairFactory(ecc);
const network = bitcoin.networks.testnet;

const inputValue = 1_000_000; // replace with actual amount
const fee = 200;
const targetValue = inputValue - fee;
const targetXOnlyKey = '<x-only key here>'; // replace with actual private key

(async function () {
  const keyPair = ECPair.fromPrivateKey(
    Buffer.from(
      '864f2a0f1696d41bf1e5878653df39dd8467a1acf2c88cd5183cf09b4a92a7a2',
      'hex',
    ),
    {network: network},
  ); // derive private key from seed

  const psbt = new bitcoin.Psbt({network: network});

  psbt.addInput({
    hash: '4f0481def3200ab4525670a614cd165ea87d0561ff5bfd9e686fd6a04407247f',
    index: 0,
    witnessUtxo: {
      // will vary, check in a block explorer to find this information easily
      script: Buffer.from(
        '001487ad1b4c41f8c5943a5dad21c645f43d575193a9',
        'hex',
      ),
      value: inputValue,
    },
  });

  psbt.addOutput({
    // add the op codes
    script: Buffer.from('5120' + targetXOnlyKey, 'hex'),
    value: targetValue,
  });

  psbt.signInput(0, keyPair);
  // psbt.validateSignaturesOfInput(0);
  psbt.finalizeAllInputs();

  const txHex = psbt.extractTransaction(true).toHex();
  console.log(psbt.extractTransaction().getId());
  console.log('Transaction Hex:', txHex);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment