secretkeylabs / sats-connect-example

39 stars 28 forks source link

signTransaction fails to add digital signature to TapRoot Ordinal address #12

Open msxakk89 opened 1 year ago

msxakk89 commented 1 year ago

When I use the sats-connect-example app as it is without any changes, and generate a PSBT and sign it it fails to broadcast it onto the network. I did some digging by copying base64 of signed transaction, and it fails to broadcast it even on Sparrow wallet:

non-mandatory-script-verify-flag (Witness program was passed an empty witness)

I checked and there is no signature for the Ordinal lock script to unlock the funds. So it means the signTransaction fails to add the signature. It does add for Paying address but not for Ordinal address.

yknl commented 1 year ago

What was the error response from the broadcast in Xverse? And what does the UTXO set look like from your wallet addresses?

yknl commented 1 year ago

Might be related to https://github.com/secretkeylabs/sats-connect-example/pull/13. Can you try with the latest version of the example?

msxakk89 commented 1 year ago

The error message is: "Transaction Failed Request failed with status code 400"

I'm selecting a specific txid:vout. I'm also paying a network fee (can see it on sign transaction Xverse wallet pop-up). I checked that UTXO is spendable.

When I get base64 representation of transaction that I got from Xverse, convert it to hex, and inspect I fail to see digital signature added:

02000000012cfc36d5630c29c4f36e7729d50503023864a49828d82178ec39e76bb46ecddb0100000000ffffffff02640000000000000022512018922857578488fbe5c3b2954d02433bf3c773949deaf7fd21c3908ea37ffbc12003000000000000225120ecbda109982214d25e63afc76642a5b58defa8a2ef3c9bdbe60301bb9ae89d5300000000

If you run it through decoderawtransaction of bitcoin core you can see it misses the signature:

{
      "txid": "dbcd6eb46be739ec7821d82898a46438020305d529776ef3c4290c63d536fc2c",
      "vout": 1,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },

This is my way of creating the PSBT for the TapRoot Ordinal address (I'm using this type of address):

const createPSBT = async (
    pubKey,
    tapRootPubKey,
    UTXO,
    amount_to_recipient,
    output_address_recipient,
    output_address_change,
    feeRate
  ) => {
    const bitcoinTestnet = {
      bech32: "tb",
      pubKeyHash: 0x6f,
      scriptHash: 0xc4,
      wif: 0xef,
    };
    const publicKey = hex.decode(pubKey);
    const p2wpkh = btc.p2wpkh(paymentPublicKey, bitcoinTestnet);
    const p2sh = btc.p2sh(p2wpkh, bitcoinTestnet);
    const internalPubKey = hex.decode(tapRootPubKey);
    const p2tr = btc.p2tr(internalPubKey, undefined, bitcoinTestnet);
    // obtain TxHash and Vout from selected UTXO
    const { TxHash, Vout } = await getTxHashAndVoutFromUTXO(UTXO);
    // obtain UTXO value
    const UTXOvalue = await fetchUTXOvalue(utxosOrdinalAddr, UTXO);
    // Create a new transaction object
    const tx = new btc.Transaction({
      allowUnknowOutput: true,
    });
    // add input
    tx.addInput({
      txid: TxHash,
      index: Vout,
      witnessUtxo: {
        script: p2tr.script,
        // script: p2sh.script,
        amount: BigInt(UTXOvalue),
      },
      redeemScript: p2tr.redeemScript,
      // witnessScript: witnessScript,
      // tapInternalKey: internalPubKey,
      sighashType: btc.SignatureHash.SINGLE | btc.SignatureHash.ANYONECANPAY,
    });
    // add output
    const recipient = output_address_recipient;
    const changeAddress = output_address_change;

    const fee = Math.round(UTXOvalue * feeRate);
    const feeBigInt = BigInt(fee);
    const amountToRecipientBigInt = BigInt(amount_to_recipient); // Ensure amount_to_recipient is BigInt
    const changeAmount =
      BigInt(UTXOvalue) - amountToRecipientBigInt - feeBigInt;

    if (changeAmount < 0) {
      console.error("Change is negative!");
      return;
    }
    // return parseInt(amount_to_recipient);
    tx.addOutputAddress(
      recipient,
      BigInt(amountToRecipientBigInt),
      bitcoinTestnet
    );
    tx.addOutputAddress(changeAddress, BigInt(changeAmount), bitcoinTestnet);

    // Generate the base64 encoded PSBT that can be
    // passed to a compatible wallet for signing
    const psbt0 = tx.toPSBT(0);
    const psbtB64 = base64.encode(psbt0);
    return psbtB64;
  };

Am I doing something obviously wrong? The reason I suspect the issue is with the sats-connect library is because I encounter the same problem when using the demo example.

msxakk89 commented 1 year ago

Using "Sats Connect Test App" fails to add signatures for a PSBT (clicking Sign Transaction):

 "vin": [
    {
      "txid": "435a438f35d64d27b287d4ba9fdb00911f469f2490cb539bc8f546750c402809",
      "vout": 1,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967295
    },
    {
      "txid": "dbcd6eb46be739ec7821d82898a46438020305d529776ef3c4290c63d536fc2c",
      "vout": 1,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967295
    }
  ],