ordinals / ord

👁‍🗨 Rare and exotic sats
https://ordinals.com
Creative Commons Zero v1.0 Universal
3.81k stars 1.35k forks source link

Runes Etching | revealTx transaction error | non-mandatory-script-verify-flag (Witness program hash mismatch) #3821

Closed VictorZhang2014 closed 3 months ago

VictorZhang2014 commented 3 months ago

Hi

The issue has stuck on me for weeks, because I always got an error when submitting a reveal transaction.

The error I always got is {"code":-26,"message":"non-mandatory-script-verify-flag (Witness program hash mismatch)"}

Your assistance or code guide is much appreciated!

node v22.1.0

"bitcoinjs-lib": "^6.1.6",
"tiny-secp256k1": "^2.2.3",
"ecpair": "^2.1.0"
const bitcoin = require('bitcoinjs-lib'); 
const ecc = require('tiny-secp256k1'); 
const ecpair = require('ecpair'); 
bitcoin.initEccLib(ecc);

const { witnessStackToScriptWitness } = require('bitcoinjs-lib/src/psbt/psbtutils')

const ECPair = ecpair.ECPairFactory(ecc);  
const toXOnly = (pubKey) => pubKey.length === 32 ? pubKey : pubKey.slice(1, 33);

const LEAF_VERSION_TAPSCRIPT = 0xc0;
const SEQUENCE = 0xfffffffd;

const fromAddr = "bc1p2fx670j2nxljmwy5k5k99gg6wejq8q3893glyyusesjkmmfsp8jq0mvnng"
const fromPubKey = "024b316fcbe104029ca8d17b361bf07205822063464704c57953023032889b3eee" 
const fromPrivateKey = "THE PRIVATE KEY"

const t1 = () => {
    const network = bitcoin.networks.bitcoin;

    const keyPair = ECPair.fromPrivateKey(Buffer.from(fromPrivateKey, 'hex'), { network });  

    const tweakedPublicKey = toXOnly(keyPair.publicKey) 

    const etching_script = Buffer.from("204b316fcbe104029ca8d17b361bf07205822063464704c57953023032889b3eeeac00630b0a6bc5b1f67df96acb22b768", "hex");  

    const scriptTree = { output: etching_script }

    const redeemScript = {
        output: etching_script,
        redeemVersion: LEAF_VERSION_TAPSCRIPT
    }

    const p2trObj = bitcoin.payments.p2tr({ 
        internalPubkey: tweakedPublicKey,
        network: network,
        scriptTree: scriptTree,
        redeem: redeemScript
    });

    const commitAndRevealAddress = p2trObj.address;
    console.log(`commit_and_reveal_address = `, commitAndRevealAddress)

    return {
        network,
        keyPair,
        tweakedPublicKey, 
        scriptTree,
        commitAndRevealAddress,
        output: p2trObj.output,
        witness: p2trObj.witness,
        hash: p2trObj.hash,
        etchingScript: etching_script
    }
} 

const t2 = async () => {
    const {
        network,
        keyPair,
        tweakedPublicKey, 
        scriptTree,
        commitAndRevealAddress,
        output,
        witness,
        hash,
        etchingScript
    } = t1(); 

    const utxo = {
        txid: 'e1202106feb4a2b43b09d3160f890bdb8e796c5dc2edfd272b0f293c7190ac76',
        vout: 0,
        value: 4500
    } 

    const runestoneScript = Buffer.from("6a5d20020304eb8ac7b5dfafbeb5cbc5dc0503900405bf4106000a904e08a09c011601", "hex");

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

    const controlBlock = witness[witness.length - 1];
    psbt.addInput({
        hash: utxo.txid,
        index: utxo.vout,
        tapInternalKey: tweakedPublicKey,
        witnessUtxo: { value: utxo.value, script: output },
        tapLeafScript: [
            {
                leafVersion: 192,
                script: etchingScript,
                controlBlock, 
            }
        ],  
        sequence: SEQUENCE,
    });

    psbt.addOutput({
        script: runestoneScript,
        value: 0
    }) 
    psbt.addOutput({
        address: commitAndRevealAddress,  
        value: 546
    });

    psbt.signInput(0, keyPair); 

    const customFinalizer = (_inputIndex, input) => {
        const witness = [input.tapScriptSig[0].signature]
          .concat(etchingScript)
          .concat(controlBlock)
        return {
          finalScriptWitness: witnessStackToScriptWitness(witness),
        }
    }
    psbt.finalizeInput(0, customFinalizer)

    let feeRate1 = psbt.getFeeRate();
    const rawTxHex = psbt.extractTransaction().toHex() 

    console.log({rawTxHex, feeRate1}) 
}

t2()

The output is

{
  rawTxHex: '0200000000010176ac90713c290f2b27fdedc25d6c798edb0b890f16d3093bb4a2b4fe062120e10000000000fdffffff020000000000000000236a5d20020304eb8ac7b5dfafbeb5cbc5dc0503900405bf4106000a904e08a09c01160122020000000000002251200c87fb9c67984b4fafc7283b9c685025ec3a94943f20e01128214c00d551b5760340f56b0d8d1b9c3931a6c5db4e6e83e4aaeffed77ed03181496d31960390cb009724ae84299b9fb9105f8922359f00551d5c3bf6352c315d2cf1587b632ad09ed831204b316fcbe104029ca8d17b361bf07205822063464704c57953023032889b3eeeac00630b0a6bc5b1f67df96acb22b76821c04b316fcbe104029ca8d17b361bf07205822063464704c57953023032889b3eee00000000',
  feeRate1: 22
}
Arunpandiaraja commented 2 months ago

@VictorZhang2014 I'm also running into same issue, Found any solution?