0

So I am using this NPM package ( https://www.npmjs.com/package/bitcore-lib ) to create and sign a Bitcoin legacy transaction locally and it was working fine for legacy. But when I tried to do the same for segwit addresses I started getting this error when i submit that raw into sendrawtransasction node method.

mandatory-script-verify-flag-failed (Witness requires empty scriptSig)

So I think the issue is with this package as the structure of this payment is not what is required for a SegWit transaction.

So my main question is is there any package in javascript I can use to create and sign a transaction? the main payload I have is

receipentAddress, senderAddress, amount ( in satoshis ), and privateKey in WIF. 

any help or clue is highly appreciated.

//edit:

rawhex:

02000000017d155e9418b60ee26fe189d4381a1fcd5aac1d8eed5216c210e6f6e7a6d86b37010000006a47304402204d6b08238b2eafbf18b7b940a4bbb59c1cc610a1d5e05d2ed72f78f9a6035b890220513a33b2461f12f711776063a54d62913adef76eb40f62ad0eac3f16577c572e01210312bc181f50c9dff7d5ebe77d4df32a9ae2e5b0530b5a4a9c4b8b88647911a883ffffffff029065000000000000160014dc804b4f932f37f77ff9a4f843c845dc3cc3d30164f20300000000001600149518ea8b88e82e82d9003fa3f7518e15180cc58500000000

edit: added code below

const axios = require('axios');
const bitcore = require('bitcore-lib');

async function generateAndSignTransaction(payload) {
  let { address, privateKey, recipientAddress, satoshis, chain } = payload;

  try {
    async function fees() {
      try {
        let key;
        if (chain === "testnet"){
          key = 'test3'
        }else {
          key = 'main'
        }

        let r = await axios.get(`https://api.blockcypher.com/v1/btc/${key}`);
        let feeObj = new Object;
        feeObj["High_fee"] = r.data.high_fee_per_kb;
        feeObj["Medium_fee"] = r.data.medium_fee_per_kb;
        feeObj["Low_fee"] = r.data.low_fee_per_kb;
        return feeObj;
      } catch (error) {
        console.error(error);
        throw error; // Propagate error
      }
    }


    let res = await fees();
    let fee = res.Low_fee;


    let url = `https://blockstream.info/${chain}/api/address/${address}/utxo`;
    res = await axios.get(url);

    console.log('UTXOS: ', res.data);


    let i = 0;
    let utxos = [];
    let balance_utxos = 0;

    while (balance_utxos <= satoshis + fee && i < res.data.length) {
      let utxo = {
        "txId": res.data[i].txid,
        "outputIndex": res.data[i].vout,
        "script": bitcore.Script.buildPublicKeyHashOut(address).toString(),
        "satoshis": res.data[i].value
      };
      utxos.push(utxo);
      balance_utxos += res.data[i].value;
      i++;
    }
    console.log('UTXOS 02: ', utxos);

    let tx = new bitcore.Transaction();
    tx.from(utxos);
    tx.to(recipientAddress, satoshis);
    tx.change(address);
    tx.fee(fee);
    tx.inputs.forEach(input => {
      input.setScript(bitcore.Script.empty());
    });
    tx.sign(privateKey);


    console.log('Tramsactopnm: ', tx);
    console.log('Tramsactopnm data: ', tx.serialize());

    let txnHex = tx.toString();

    return { txid: txnHex }; // Return the serialized transaction
  } catch (error) {
    console.error('Error:', error);
    throw error; // Propagate error
  }
}


module.exports = { generateAndSignTransaction };

1 Answer 1

1

From error message, I guess you sign your transaction in a same way when spend legacy address, because it literally means your script sig is not empty(it must be empty for segwit spend as script sig must be placed into witness stack). I don't think it would be problem with bitcore-lib, but you might use my open source bitcoin-sdk-js as an alternative as it supports segwit spend.

Below code works.

import * as bitcoin from 'bitcoin-sdk-js';

const privkey =
  'e6c58327b4bf1314296bba7adb66f94c36ea5611ac07830c229aa7ee6f9caac3';
const toAddress = 'tb1qmjqyknun9umlwlle5nuy8jz9ms7v85cp7k2nfe';
const toValue = 300000;
const txHash =
  '8bcd197873dbff5cc67cb3e0b1cbbdf097c7af94b0e9365adecb424e408294bf';
const inputValue = 310981;

const tx = new bitcoin.Transaction();

await tx.addInput({
  txHash: txHash,
  index: 1,
  value: inputValue,
});
await tx.addOutput({
  address: toAddress,
  value: toValue,
});
await tx.signInput(privkey, 0);

const txHex = await tx.getSignedHex();

11
  • here is the raw hex 02000000017d155e9418b60ee26fe189d4381a1fcd5aac1d8eed5216c210e6f6e7a6d86b37010000006a47304402204d6b08238b2eafbf18b7b940a4bbb59c1cc610a1d5e05d2ed72f78f9a6035b890220513a33b2461f12f711776063a54d62913adef76eb40f62ad0eac3f16577c572e01210312bc181f50c9dff7d5ebe77d4df32a9ae2e5b0530b5a4a9c4b8b88647911a883ffffffff029065000000000000160014dc804b4f932f37f77ff9a4f843c845dc3cc3d30164f20300000000001600149518ea8b88e82e82d9003fa3f7518e15180cc58500000000 and the error is mandatory-script-verify-flag-failed (Witness requires empty scriptSig), checking on this pkg, will keep you updated. Commented May 17 at 7:58
  • As I guessed you are trying to spend segwit output in a legacy way(which is wrong). You must move script sig part(which is 47304402204d6b08238b2eafbf18b7b940a4bbb59c1cc610a1d5e05d2ed72f78f9a6035b890220513a33b2461f12f711776063a54d62913adef76eb40f62ad0eac3f16577c572e01210312bc181f50c9dff7d5ebe77d4df32a9ae2e5b0530b5a4a9c4b8b88647911a883) to witness stack(at the end of tx hex) and also need to add segwit flag, mark and witness item count. I think the signature itself would be also wrong as the segwit message to sign is different from legacy. You can check BIP143 for specific semantic.
    – Hyunhum
    Commented May 17 at 8:37
  • brother, i dont understand all these that much, I just want a tool or pacakge to work, and i will only provide the payload which is { address: 'tb1qj5vw4zugaqhg9kgq873lw5vwz5vqe3v9uldtdu', privateKey: 'L4xJPRKG4QpqeFraSqJQiY6iPd364H8E9jrmtZkqVw2WQVCejBcj', recipientAddress: 'tb1qmjqyknun9umlwlle5nuy8jz9ms7v85cp7k2nfe', satoshis: 26000, chain: 'testnet' } and the code should give me hex which works. the package you shared doesn't have a proper doc, and code is also outdated. anyways I'll try to make it work. thanks for the time. Commented May 17 at 9:06
  • I'm sorry I just pushed tx to testnet for test accidentally with the private key you provided and it works well. I edited my answer with code. If you need testnet btc let me know I will send to you.
    – Hyunhum
    Commented May 17 at 9:34
  • Hi Hyunhum, that's really great that this code works I also want to try this but i have nothing left unspent, i have tried many faucets but haven't received any yet, can you please send me back? Commented May 17 at 10:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.