Git Product home page Git Product logo

tapscript's Issues

How to generate secret keys

I'm familiar with generating secret keys randomly and also from a secret phrase using bitcoinjs-lib.

How do I do the same thing with Tapscript? For instance, I have my secret phrase but I'm not sure how to format it to a hex string as shown in the examples.

Taptree Example sounds strange

It seems that the example is generating a public key (to which the funds need to be sent) in such a way that the pubkey depends on the target script that we want the spender to verify.

If I'm not mistaken the power of Taproot is to enable the commitment of funds to a not-pubic unlocking MAST (the whole Tree) and allow the spender to satisfy just one of the possible alternatives, inside the MAST. that way we are actually not using the MAST feature. The pubkey actually depends on the unlock script

Tap script inquiry

I want to create a specific transaction using tapscript similar to the ones shown in this example and I can't figure out how to put a 7 before the sig inside the witness. Can you please help ?

`const test = async () => {
// Switch this to true to enable console output.
const VERBOSE = true

    // Create a keypair to use for testing.
    const secret = '0a7d01d1c2e1592a02ea7671bb79ecd31d8d5e660b008f4b10e67787f4f24712'
    const seckey = utils.getSecretKey(secret)
    const pubkey = utils.getPublicKey(seckey, true)

    // Specify an array of scripts to use for testing.
    const scripts = [
        [ 7, 'OP_EQUALVERIFY', pubkey, 'OP_CHECKSIG' ],
        [ 8, 'OP_EQUALVERIFY', pubkey, 'OP_CHECKSIG' ],
    ]

    // Convert our array of scripts into tapleaves.
    const tree = scripts.map(s => Tap.encodeScript(s))

    if (VERBOSE) console.log('tree:', tree)

    // Pick one of our scripts as a target for spending.
    const index  = 0
    const script = scripts[index]
    const target = Tap.encodeScript(script)

    if (VERBOSE) console.log('target:', target)

    // Generate a tapkey that includes our tree. Also, create a merlke proof 
    // (cblock) that targets our leaf and proves its inclusion in the tapkey.
    const [ tpubkey, cblock ] = Tap.getPubKey(pubkey, { tree, target })

    // A taproot address is simply the tweaked public key, encoded in bech32 format.
    const address = Address.p2tr.fromPubKey(tpubkey, 'testnet')
    if (VERBOSE) console.log('Your address:', address)

    /* NOTE: To continue with this example, send 100_000 sats to the above address.
    You will also need to make a note of the txid and vout of that transaction,
    so that you can include that information below in the redeem tx.
    */ 

    const txdata = Tx.create({
        vin  : [{
            // Use the txid of the funding transaction used to send the sats.
            txid: '3a9e52dc01bdb22c4b36a0490d73b06392bccf635e06ba3913339e733e7ab9a2',
            // Specify the index value of the output that you are going to spend from.
            vout: 0,
            // Also include the value and script of that ouput.
            prevout: {
            // Feel free to change this if you sent a different amount.
            value: 10_000,
            // This is what our address looks like in script form.
            scriptPubKey: [ 'OP_1', tpubkey ]
            },
        }],
        vout : [{
            // We are leaving behind 1000 sats as a fee to the miners.
            value: 9_000,
            // This is the new script that we are locking our funds to.
            scriptPubKey: Address.toScriptPubKey('2MzcAVUFfHb1ni46AXCn5z7ADQKrKvz52nn')
        }]
    })

    // For this example, we are signing for input 0 of our transaction,
    // using the untweaked secret key. We are also extending the signature 
    // to include a commitment to the tapleaf script that we wish to use.
    const sig = Signer.taproot.sign(seckey, txdata, 0, { extension: target })

    // Add the signature to our witness data for input 0, along with the script
    // and merkle proof (cblock) for the script.
    txdata.vin[0].witness = [ sig, script, cblock ]

    // Check if the signature is valid for the provided public key, and that the
    // transaction is also valid (the merkle proof will be validated as well).
    const isValid = await Signer.taproot.verify(txdata, 0, { pubkey })

    if (VERBOSE) {
        console.log('Your txhex:', Tx.encode(txdata).hex)
        console.dir(txdata, { depth: null })
    }
}`

Public key version reserved for soft-fork upgrades

Hi, I'm playing with taproot scripts via tapscript and bumped into this blocker when trying to send raw transaction on Bitcoin Signet via bitcoin-cli -signet sendrawtransaction:

error code: -26
error message:
non-mandatory-script-verify-flag (Public key version reserved for soft-fork upgrades)

Here is the code I'm using:

const {Address, Script, Signer, Tap, Tx} = require('@cmdcode/tapscript')
const utils = require('@cmdcode/crypto-utils')

const secret = '.....'
const seckey = utils.keys.get_seckey(secret)
const pubkey = utils.keys.get_pubkey(seckey)

const script = [....]
const tapleaf = Tap.encodeScript(script)
const [tpubkey, cblock] = Tap.getPubKey(pubkey, {target: tapleaf})
const address = Address.p2tr.fromPubKey(tpubkey, 'signet')

const txdata = Tx.create({
      vin: [{
          txid: '.....',
          vout: 1,
          prevout: {
              value: 100000,
              scriptPubKey: ['OP_1', tpubkey]
          },
      }],
      vout: [
          {
              value: 90000,
              scriptPubKey: Address.toScriptPubKey('tb1p.....')
          }
      ]
  })
const sig = Signer.taproot.sign(seckey, txdata, 0, {extension: tapleaf, throws: true})
txdata.vin[0].witness = [sig.hex, script, cblock]

await Signer.taproot.verify(txdata, 0, {pubkey, throws: true})

Is there anything wrong with how get_pubkey derives public key? Or any other reason I might be getting this strange error? Thanks!

`Tx.encode` fail for file larger than 260 byte

I have tried to inscribe file has size < 260b successfully according to the example, but for files larger than 260b it seems that encoding tx is having problems. it seems the 520 byte limit is misdefined leading to the wrong encoding (personally)

ReferenceError: crypto is not defined

I got this error:

C:\path\to\my\project\node_modules\@cmdcode\tapscript\node_modules\@cmdcode\buff-utils\dist\module.mjs:353
const { getRandomValues } = crypto ?? globalThis.crypto ?? window.crypto;
                            ^
ReferenceError: crypto is not defined
    at Object.<anonymous> (C:\path\node_modules\@cmdcode\tapscript\node_modules\@cmdcode\buff-utils\dist\module.mjs:353:29)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Object.require.extensions.<computed> [as .js] (C:\path\to\AppData\Local\npm-cache\_npx\<random looking num here>\node_modules\ts-node\src\index.ts:1608:43)       
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Function.Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (C:\path\to\my\project\index.ts:1:1)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)

When I try to run my script that looks like this "index.ts.":

const { Address, Signer, Tap, Tx, } = require('@cmdcode/tapscript')

function main() {
    const address = 'address here'
    const decoded = Address.decode(address)
    console.log(decoded)
}

main()

Error: Size greater than stream: 38133322 > 56518

I like this library a lot, but I have hit a blocker.
Tx.decode() fails with this error for some transactions that have already been confirmed.
The error message is always the same: 38133322 > 56518 for the txn in my repro, below.

I notice this tends to happen with txns with many inputs, or many outputs.

Here's my repro script (node 19.9.0):

// Version 1.4.4 from npm.
import { Tx } from "@cmdcode/tapscript";
import * as lib_bitcoin_rpc from './lib_bitcoin_rpc.js'

async function main() {
  // The following txid causes a decode script crash.
  const txid = '74424af880bad9a82b0969b241fc8ee15db56ef5b852fc81649a7545a1e27036'
  // The following txid does not cause a crash.
  //const txid = '1cd87feb39f3696a0573cdfc5b981f6040954817fb1d59a082fec749693625b9'

  // Get txn as hexstring.
  const { result: rawTxn } = await lib_bitcoin_rpc.getRawTransaction(txid)
  console.log(rawTxn)

  const tx = Tx.decode(rawTxn)
  console.log('Done.')
}

main()

Output:

020000000001fd24021615950c0d6e983937ca8cf33e8b94ec90b51b67868e66e1626170f942b2b2e80500000000fdffffff374f40f1b0b08e7f7ff144a5266c7e9ecdc3b8d30a7afec3ebd1b0e927ad3f812200000000fdffffff94090c725875db7194e1f47b2f1f1f8ef9c3c4aea3ea487e1c8b66fbadbfbaa60300000000fdfffffffb21f9f7c8b3028afac209af3c7d14e57e6e7dd3b45a452b37324892c71da8100600000000fdffffff8234d40bdb83594b8f9f6bc0f3889007f0ebfaea46bd38fb47de59a85821642b0100000000fdffffff60811e1de61a40b4ad98b55562461d5f380163d8682a1c39
...
c68c914817c641f4a29ae40121023e043fd3e13df9c2a8640adc0d07842fb490f93c5f307ce7d859ed277b83e14f16ae0c00
file:///home/donn/workspace/gitlab.com/proj/inscribe/node_modules/@cmdcode/tapscript/dist/module.mjs:1069
            throw new Error(`Size greater than stream: ${size} > ${this.size}`);
                  ^

Error: Size greater than stream: 38133322 > 56518
    at Stream.peek (file:///home/donn/workspace/gitlab.com/proj/inscribe/node_modules/@cmdcode/tapscript/dist/module.mjs:1069:19)
    at Stream.read (file:///home/donn/workspace/gitlab.com/proj/inscribe/node_modules/@cmdcode/tapscript/dist/module.mjs:1075:28)
    at readData (file:///home/donn/workspace/gitlab.com/proj/inscribe/node_modules/@cmdcode/tapscript/dist/module.mjs:6684:18)
    at readScript (file:///home/donn/workspace/gitlab.com/proj/inscribe/node_modules/@cmdcode/tapscript/dist/module.mjs:6688:18)
    at readInput (file:///home/donn/workspace/gitlab.com/proj/inscribe/node_modules/@cmdcode/tapscript/dist/module.mjs:6651:20)
    at readInputs (file:///home/donn/workspace/gitlab.com/proj/inscribe/node_modules/@cmdcode/tapscript/dist/module.mjs:6643:21)
    at Object.decodeTx [as decode] (file:///home/donn/workspace/gitlab.com/proj/inscribe/node_modules/@cmdcode/tapscript/dist/module.mjs:6613:17)
    at main (file:///home/donn/workspace/gitlab.com/proj/inscribe/hello_repro_decode_txn_error_for_publishing_to_issue.js:18:17)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Node.js v19.9.0

I hope this can be investigated because I would hate to port all my code to another lib.
Please let me know if there's more info I can provide.
Thank you

A test failure

Just a small problem, in "inscribe.test.ts", L21, new URL() failed in the windowOS, and it should use absolute URL

crypto is not defined

I keep getting this error
I dont want to use patch-package (by making changes to the file)

Is there any other easier way to solve this error?
Please do reply fast!!

image

Sign problem

Error: crypto.getRandomValues must be defined
    at randomBytes$2 (/Users/sonpin/Documents/bitcoin/new/node_modules/@cmdcode/tapscript/dist/main.cjs:106:11)
    at Function.random (/Users/sonpin/Documents/bitcoin/new/node_modules/@cmdcode/tapscript/dist/main.cjs:1480:25)
    at sign (/Users/sonpin/Documents/bitcoin/new/node_modules/@cmdcode/tapscript/dist/main.cjs:7661:46)
    at Object.signTx [as sign] (/Users/sonpin/Documents/bitcoin/new/node_modules/@cmdcode/tapscript/dist/main.cjs:7656:17)

I've got this issue when sign

Signer.taproot.sign(seckey, txdata, 0, { extension: tapleaf })

{"code":-26,"message":"non-mandatory-script-verify-flag (Witness program hash mismatch)"}

when i push tx i got this error...

here is my code

async function deploy(
    secret: string,
    brc20: string,
    totalSupply: number,
    mintLimit: number,
    input: {txId: string; index: number; amount: number},
    network: Networks,
) {
    const text = `{"p":"brc-20","op":"deploy","tick":"${brc20}","max":"${totalSupply}","lim":"${mintLimit}"}`
    const inscription = createTextInscription(text)

    const seckey = keys.get_seckey(secret)
    const pubkey = keys.get_pubkey(secret, true)
    const tweakKey = Tap.tweak.getPubKey(pubkey)

    const script = [
        tweakKey,
        "OP_CHECKSIG",
        "OP_0",
        "OP_IF",
        Buffer.from(encoder.encode("ord")),
        "01",
        inscription.contentType,
        "OP_0",
        inscription.content,
        "OP_ENDIF",
    ]
    const tapleaf = Tap.encodeScript(script)
    const [tpubkey, cblock] = Tap.getPubKey(tweakKey, {target: tapleaf})
    const address = Address.p2tr.fromPubKey(tweakKey, network)
    // const address = Address.p2tr.fromPubKey(tpubkey, network)
    console.log(address, "address")
    const txdata = Tx.create({
        vin: [
            {
                // Use the txid of the funding transaction used to send the sats.
                txid: input.txId,
                // Specify the index value of the output that you are going to spend from.
                vout: input.index,
                // Also include the value and script of that ouput.
                prevout: {
                    // Feel free to change this if you sent a different amount.
                    value: input.amount,
                    // This is what our address looks like in script form.
                    scriptPubKey: ["OP_1", tpubkey],
                },
            },
        ],
        vout: [
            {
                // We are leaving behind 1000 sats as a fee to the miners.
                value: 1000,
                // This is the new script that we are locking our funds to.
                scriptPubKey: Address.toScriptPubKey("tb1q7gnys2cwhkm7r73px6nus0g9dcr8mjh6fe2ums"),
            },
            {
                value: input.amount - 5000,
                scriptPubKey: Address.toScriptPubKey(address),
            },
        ],
    })
    const sig = Signer.taproot.sign(seckey, txdata, 0, {extension: tapleaf})
    txdata.vin[0].witness = [sig, script, cblock]
    const isValid = Signer.taproot.verify(txdata, 0, {pubkey, throws: true})
    console.log("Your txhex:", Tx.encode(txdata).hex, isValid)
    // console.dir(txdata, {depth: null})
    await boardCast(Tx.encode(txdata).hex)
}

Did I get something wrong?
Thanks!

How can I decode script from tpubkey

const script  = [ pubkey, 'OP_CHECKSIG', 'OP_0', 'OP_IF', marker, '01', mimetype, 'OP_0', imgdata, 'OP_ENDIF' ]

const tapleaf = Tap.encodeScript(script)

const [ tpubkey, cblock ] = Tap.getPubKey(pubkey, { target: tapleaf })

How can I decode script from tpubkey

Invalid Schnorr Siganture - Example: Basic Pay-to-Pubkey Spending

Hi, when I follow the example “Basic Pay-to-Pubkey Spending” the Signature check at the end of the script returns True, however, when I submit the transaction hash to mempool.space, it tells me: non-mandatory-script-verify-flag Invalid-Schnorr-Signature.

Is the script correct? I am using testnet.

Add multiple parent to a child inscription

I was trying to add multiple parent to a child inscription .
So , according the the "Ordinal Theory Handbook" ,

image

I follow the first 2 points .According to the second bullet point I spend both parent inscription as first 2 inputs , and the creation of the child inscription is the 3rd input.

But my doubt is in the 3rd bullet point , Which serialised binary inscription ID should I include in the tag 3 the first parent's or the seconds , if i have to add both how do i do it?

According to @cmdcode/tapscript , how will I include 2 parent serialised binary inscription ids whiie designing the script manually

In the examples, where is the scriptPubKey address comming from?

This seemingly random address appears in several places but I will use the inscribe.test.ts file as an example https://github.com/cmdruid/tapscript/blob/master/test/example/taproot/inscribe.test.ts. Notice this code:

const txdata = Tx.create({
      vin  : [{
        // Use the txid of the funding transaction used to send the sats.
        txid: 'b8ed81aca92cd85458966de90bc0ab03409a321758c09e46090988b783459a4d',
        // Specify the index value of the output that you are going to spend from.
        vout: 0,
        // Also include the value and script of that ouput.
        prevout: {
          // Feel free to change this if you sent a different amount.
          value: 100_000,
          // This is what our address looks like in script form.
          scriptPubKey: [ 'OP_1', tpubkey ]
        },
      }],
      vout : [{
        // We are leaving behind 1000 sats as a fee to the miners.
        value: 99_000,
        // This is the new script that we are locking our funds to.
        scriptPubKey: Address.toScriptPubKey('bcrt1q6zpf4gefu4ckuud3pjch563nm7x27u4ruahz3y')
      }]
    })

See scriptPubKey: Address.toScriptPubKey('bcrt1q6zpf4gefu4ckuud3pjch563nm7x27u4ruahz3y')... Why is bcrt1q6zpf4gefu4ckuud3pjch563nm7x27u4ruahz3y being used as the script that is locking the funds? Is this just an address chosen at random or is it derived from another piece of code that I'm missing?

Does it just mean that address where the UTXO is being spent chosen at random?

Runes

Will this this work for Runes also or do you have to change up a lot to make it work for Runes?

Witness program hash mismatch

test/example/taproot/inscribe.test.ts
`
import { Buff } from '@cmdcode/buff'
import { taproot } from '../../../src/lib/sig/index.js'
import { tap_pubkey } from '../../../src/lib/tap/index.js'
import { assert } from '../../../src/index.js'

import {
get_seckey,
get_pubkey
} from '@cmdcode/crypto-tools/keys'

import {
parse_addr,
P2TR
} from '../../../src/lib/addr/index.js'

import {
encode_tx,
parse_tx
} from '../../../src/lib/tx/index.js'

import { Buffer } from 'buffer/'

const VERBOSE = false

function inscription() {

const ret_addr = "tb1ptv0luvng53jlddlae7y2898pgs9cqfxsaw0qsrcz4k0kvjsdtnsqvkvyzg"
const encoder = new TextEncoder()
try {
const text = {"p":"brc-20","op":"deploy","tick":"hffp","max":"210000","lim":"1"}
const imgdata = Buffer.from(encoder.encode(text))
const marker = Buff.encode('ord')
const mimetype = Buffer.from(encoder.encode('text/plain;charset=utf-8'))
const secret = 'your secret'
const seckey = get_seckey(secret)
const pubkey = get_pubkey(seckey, true)
const script = [pubkey, 'OP_CHECKSIG', 'OP_0', 'OP_IF', marker, '01', mimetype, 'OP_0', imgdata, 'OP_ENDIF']
const { tapkey, cblock } = tap_pubkey(pubkey, { script })
const address = P2TR.create(tapkey, 'testnet')
const txinput = {
"txid": "201d025a29b20985a329947910c293ce9640c639c834c416dcf6440d3ad4697d",
"vout": 0,
"satoshi": 4000000,
"scriptType": "5120",
"scriptPk": "51206602f211fb1a7a56c3c45422fdc5509876af35c095c4973029ae57ea7974edbc",
"codeType": 9,
"address": "tb1pvcp0yy0mrfa9ds7y2s30m32snpm27dwqjhzfwvpf4et757t5ak7qq66r4h",
"height": 2543743,
"idx": 67,
"isOpInRBF": false,
"inscriptions": []
}

const txdata = parse_tx({
  vin: [{
    // Use the txid of the funding transaction used to send the sats.
    txid: txinput.txid,
    // Specify the index value of the output that you are going to spend from.
    vout: txinput.vout,
    // Also include the value and script of that ouput.
    prevout: {
      // Feel free to change this if you sent a different amount.
      value: txinput.satoshi,
      // This is what our address looks like in script form.
      scriptPubKey: ["OP_1", tapkey],
    },
  }],
  vout: [{
    value: 5000,
    scriptPubKey: parse_addr(ret_addr).asm
  }]
})

const sig = taproot.sign_tx(seckey, txdata, { script, txindex: 0 })

txdata.vin[0].witness = [sig, script, cblock]

const is_valid = taproot.verify_tx(txdata, { txindex: 0, pubkey, throws: true })
assert.ok(is_valid, 'Transaction failed validation.')
const txhex = encode_tx(txdata)
console.log(txhex.toString())

} catch (err) {
}
}

inscription()
`

020000000001017d69d43a0d44f6dc16c434c839c64096ce93c210799429a38509b2295a021d200000000000fdffffff0188130000000000002251205b1ffe3268a465f6b7fdcf88a394e1440b8024d0eb9e080f02ad9f664a0d5ce00340477a3553bc207d380298787fa597e40cd67fa92b5304f1e3826477c9e7792259e75cf72132c0c834d72717aa60ea019146b241ba77a4d08cfb24a24fc8f55cf18820fcf61b477e3ba7ed2fe14521da13960b61332f660204f6089bae65c6ba145685ac0063036f72645118746578742f706c61696e3b636861727365743d7574662d3800437b2270223a226272632d3230222c226f70223a226465706c6f79222c227469636b223a2268666670222c226d6178223a22323130303030222c226c696d223a2231227d6821c0fcf61b477e3ba7ed2fe14521da13960b61332f660204f6089bae65c6ba14568500000000

sendrawtransaction RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Witness program hash mismatch)"}

witness problem

I performed a sats token mint transaction using the go-ord-tx repository without much knowledge. I did not know that the mempool limit was 25. My transaction was approved, but the script did not execute after 25 transactions. How can I make the utxos at the tahhahut address execute the script using this library? I'm having trouble creating the 1st and 3rd witness values. I'm just starting to learn. Can you help me?

Broadcast error, Public key version reserved for soft-fork upgrades

follow inscribe.test.ts, broadcast tx to the mainnet, get error!

const txdata = Tx.create({
  vin  : [{
    txid: '30fcb229bdef4ab1a9d864e2cb4b562c99b8ea00d68ff156f31ec1468ba6d893',
    vout: 0,
    prevout: {
      value: 4_000,
      scriptPubKey: [ 'OP_1', tpubkey ]
    },
  }],
  vout : [{
    value: 1_000,
    scriptPubKey: Address.toScriptPubKey('bc1p93mun355nyke02gvdhx7vmes5l8enh2yw86r8x0fl98hwlug2dvq3xqj66')
  }]
})

const sig = Signer.taproot.sign(seckey, txdata, 0, { extension: tapleaf })
txdata.vin[0].witness = [ sig, script, cblock ]

const response = await axios.post('https://blockstream.info/api/tx', Tx.encode(txdata).hex)
console.log(response.data)
print:
sendrawtransaction RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Public key version reserved for soft-fork upgrades)"}

How to use sequence in input?

here is my code

    const txdata = Tx.create({
        vin: [{
            txid: '5b8ce54ca0993713552939b3d248c1f1b98c3ba18575f0d34f6b5ae13d58eac0',
            vout: 0,
            prevout: {
                value: 5000,
                scriptPubKey: ['OP_1', tpubkey]
            }
        }],
        vout: [
            {
                value: 4000,
                scriptPubKey: Address.toScriptPubKey(receiverAddress)
            }
        ]
    })
    console.log(txdata)
    const sig = Signer.taproot.sign(senderSeckey, txdata, 0, { extension: lockTapleaf })
    txdata.vin[0].witness = [sig.hex, puzzle.toString('hex'), lockScript, cblock]

then, I want to set sequence in input like this

const txdata = Tx.create({
        vin: [{
            txid: '5b8ce54ca0993713552939b3d248c1f1b98c3ba18575f0d34f6b5ae13d58eac0',
            vout: 0,
            prevout: {
                value: 5000,
                scriptPubKey: ['OP_1', tpubkey]
            },
            sequence: 6,
        }],
        vout: [
            {
                value: 4000,
                scriptPubKey: Address.toScriptPubKey(receiverAddress)
            }
        ]
    })

But I always got error "Transaction has superfluous witness data", what should I do?

Question: Order of inputs in a transaction.

The way address spending works is:

  1. First inputs' sats cover the output amount.
  2. Remaining inputs' sats, which didn't fit into the output amount, go to miners.

But how do I specify the order of input UTXOs with this library?
I want to make sure inscription UTXOs are first, while ordinary sats are last, so that inscriptions don't leak to miners.

ReferenceError: crypto is not defined

ReferenceError: crypto is not defined
at Object. (node_modules/.store/@cmdcode[email protected]/node_modules/@cmdcode/tapscript/dist/main.cjs:339:48)
at Module._compile (node:internal/modules/cjs/loader:1105:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Module._load (node:internal/modules/cjs/loader:827:12)
at Module.require (node:internal/modules/cjs/loader:1005:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object. (/Users/JunK/messi/king_chain/temp_typscript/index.js:2:46)
at Module._compile (node:internal/modules/cjs/loader:1105:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)

Custom Address Prefix

It would be useful to have the ability to use custom address prefixes while doing address encoding. For example Litecoin. Found the encoding for it here.

crypto.getRandomValues must be defined node js error

Hello I get the following error in node js:

/@cmdcode/tapscript/dist/module.js:104
    throw new Error('crypto.getRandomValues must be defined');

As a local work around I changed (line 56 in module.js)

const crypto$2 = typeof globalThis === 'object' && 'crypto' in globalThis ? globalThis.crypto : undefined;

to

import * as crypto$2  from 'crypto';

OP_RETURN in output

@cmdruid was trying to implement the runes specification on my existing codebase used for inscriptions.

I feel like this should be a straightforward task but for whatever reason once my txn is broadcast the block explorers show UNKNOWN rather than the OP_RETURN. runes protocol aside, i should be able to use an OP_RETURN with any data following it, right?

Here is some sample code

var payload = hexToBytes( '148dde9d011427' );
var rune   = [ 'OP_RETURN', 'OP_13', payload ]
var runestone = Script.encode(rune);

i then add runestone as the scriptpubkey of a 0 value txn output. the txn signs and broadcasts no problem.

here are some examples on testnet that shown UNKNOWN

It should look something like the OP_RETURN here.

any thoughts appreciated!

Ordinal Provenance

@cmdruid appreciate all the work and examples in this library!

I had a question regarding ordinal provenance as documented here.

I have an inscription flow in place which generally follows the example you provided for inscriptions. While I believe i have followed the ordinal provenance documentation correctly as far as the script construction and input values, I am having issues signing the transaction.

Code snippets below, any thoughts/suggestions on how to get this working is appreciated! I am currently getting RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Invalid Schnorr signature)"}. The ordinal I am trying to use as the parent is here: https://mempool.space/testnet/tx/e13f106578fe0955b375cfb66e4a212fd794b7168a7da5873fada2b78c47e035

image
image
image

Sign transaction error

My code in Typescript const init_sig = Signer.taproot.sign(seckey, init_redeemtx, 0, { extension: init_leaf }); but it throws error:
throw new Error('crypto.getRandomValues must be defined');

I can't get my Azure function to work in Docker when importing @cmdcode/tapscript

I created an Azure function locally with the following commands in powershell:
func init --worker-runtime node --language typescript --docker func new --name generateBitcoinAddress --template "HTTP trigger"
This creates a boilerplate Azure function that looks like this:

import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";

export async function generateBitcoinAddress(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    context.log(`Http function processed request for url "${request.url}"`);

    const name = request.query.get('name') || await request.text() || 'world';

    return { body: `Hello, ${name}!` };
};

app.http('generateBitcoinAddress', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: generateBitcoinAddress
});

I built it and deployed it on docker:

npm run clean
npm run build
docker build --tag YOUR_DOCKER_ID_HERE/azurefunctionsimage:v1.0.0 . docker run -p 8080:80 -it YOUR_DOCKER_ID_HERE/azurefunctionsimage:v1.0.0

It works, I hit the API with Postman using this post request:

curl --location 'http://localhost:8080/api/generateBitcoinAddress' 
--header 'Content-Type: application/json' 
--data 'Chris'

It printed:
Hello, Chris!
And I ran this locally without Docker as well:

npm run clean
npm run build
func start

To hit this local non-docker API, I altered my Postman command to use port 7071 instead of 8080 and it succeeded.
Now is the weird part. I modified the code to do something more complex. I took this test from @cmdcode/tapscript, https://github.com/cmdruid/tapscript/blob/master/test/example/taproot/keyspend.test.ts and converted it into an Azure Function:

import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
import { keys } from '@cmdcode/crypto-tools';
import { Address, Tap, Tx, Signer } from '@cmdcode/tapscript';

export async function generateBitcoinAddress(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    try {
        const body: any = await request.json();
        const secret_key = body.secret;
        const seckey = keys.get_seckey(secret_key)
        const pubkey = keys.get_pubkey(seckey, true)

        // For key spends, we need to get the tweaked versions
        // of the secret key and public key.
        const [ tseckey ] = Tap.getSecKey(seckey)
        const [ tpubkey ] = Tap.getPubKey(pubkey)

        // A taproot address is simply the tweaked public key, encoded in bech32 format.
        const address = Address.p2tr.fromPubKey(tpubkey, 'regtest')
        console.log('Your address:', address)

        /* NOTE: To continue with this example, send 100_000 sats to the above address.
        You will also need to make a note of the txid and vout of that transaction,
        so that you can include that information below in the redeem tx.
        */ 

        const txdata = Tx.create({
        vin  : [{
            // Use the txid of the funding transaction used to send the sats.
            txid: '1ec5b5403bbc7f26a5d3a3ee30d69166a19fa81b49928f010af38fa96986d472',
            // Specify the index value of the output that you are going to spend from.
            vout: 1,
            // Also include the value and script of that ouput.
            prevout: {
            // Feel free to change this if you sent a different amount.
            value: 100_000,
            // This is what our address looks like in script form.
            scriptPubKey: [ 'OP_1', tpubkey ]
            },
        }],
        vout : [{
            // We are leaving behind 1000 sats as a fee to the miners.
            value: 99_000,
            // This is the new script that we are locking our funds to.
            scriptPubKey: Address.toScriptPubKey('bcrt1q6zpf4gefu4ckuud3pjch563nm7x27u4ruahz3y')
        }]
        })

        // For this example, we are signing for input 0 of our transaction,
        // using the tweaked secret key.
        const sig = Signer.taproot.sign(tseckey, txdata, 0)

        // Let's add this signature to our witness data for input 0.
        txdata.vin[0].witness = [ sig ]

        // Check if the signature and transaction are valid.
        const isValid = await Signer.taproot.verify(txdata, 0)

         return { status: 200, jsonBody: { isValid: isValid, address: address, signature: sig }};

    } catch (error) {
        context.error(`Error processing request: ${error}`);
        return { status: 500, jsonBody: { error: "Internal server error. Please try again later." }};
    }
};

app.http('generateBitcoinAddress', {
    methods: ['POST'],
    authLevel: 'anonymous',
    handler: generateBitcoinAddress
});  

It worked perfectly when I ran it locally WITHOUT Docker...

npm install u/cmdcode/buff
npm install u/cmdcode/buff-utils\
npm install u/cmdcode/tapscript
npm install u/cmdcode/crypto-tools
npm run clean
npm run build
func start

Then in Postman, I did:

curl --location 'http://localhost:7071/api/generateBitcoinAddress' 
--header 'Content-Type: application/json' 
--data '{ "secret": "ccd54b99acec77d0537b01431579baef998efac6b08e9564bc3047b20ec1bb4c" }'

It worked and produced this output:

{
  "isValid": true,
  "address": "bcrt1pszn3ahyts27pr8zvqf3p0v53y5f0gwgcz85nwrdh2kxw4xxd00mqh3mjcv",
  "signature": {
    "0": 43,
    "1": 98,
    LOTS MORE ARRAY VALUES THAT I WILL OMIT FOR BREVITY
  }
}

But when I took this working Azure Function, and tried to launch it in a docker container, it didn't work:

docker build --tag YOUR_DOCKER_ID_HERE/azurefunctionsimage:v1.0.0 .
docker run -p 8080:80 -it YOUR_DOCKER_ID_HERE/azurefunctionsimage:v1.0.0

I noticed this line in the output of the docker run command that wasn't present in the boilerplate code docker run command output:
No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

So I already knew it would fail because no function is at the API endpoint. But just to make sure it would fail, I altered my Postman command for port 8080:

curl --location 'http://localhost:8080/api/generateBitcoinAddress' 
--header 'Content-Type: application/json' 
--data '{ "secret": "ccd54b99acec77d0537b01431579baef998efac6b08e9564bc3047b20ec1bb4c" }'

And it gave me a 404 error.
So what is the problem? Why does my code work locally when I run it with func start, but doesn't work when I deploy it via Docker?

non-mandatory-script-verify-flag (Witness program hash mismatch)

I have this transaction created with tapscript according to the inscription example , decoded from hex:

{
    "addresses": [
        "tb1peetwkzdue9eey9at87d72ea98zw4yz62mq5j49w8utcf28z4w4dq49yt5z",
        "tb1pezwxd60p00laqcu6fvze0canaczel8rdh44u4yu5995xlczgk4asm3hksg"
    ],
    "block_height": -1,
    "block_index": -1,
    "confirmations": 0,
    "double_spend": false,
    "fees": 1000,
    "hash": "1899989d5f95661d60b8b5de873252085043cb528fe75b32040169335790421d",
    "inputs": [
        {
            "addresses": [
                "tb1peetwkzdue9eey9at87d72ea98zw4yz62mq5j49w8utcf28z4w4dq49yt5z"
            ],
            "age": 2536373,
            "output_index": 1,
            "output_value": 20000,
            "prev_hash": "fa2418bba0a89052bb9f045ed3d9b509e58ffb8d76b3b05aa04b1e76dbc1204e",
            "script_type": "pay-to-taproot",
            "sequence": 4294967293,
            "witness": [
                "05cfdbc9641646e51b61dac7ace4436748429004b6e44affbbcbb303126f0ef8a274b4d9d6fcabd3f0eb1b44f9b1e9f6e00b34a218caae4d73d7b50bbcde014e",
                "21021344f6fb0eb5b4ad25dc7db247573e92a1bd2f342317db3e931972434fb9b542ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d38000068",
                "c11344f6fb0eb5b4ad25dc7db247573e92a1bd2f342317db3e931972434fb9b542"
            ]
        }
    ],
    "opt_in_rbf": true,
    "outputs": [
        {
            "addresses": [
                "tb1pezwxd60p00laqcu6fvze0canaczel8rdh44u4yu5995xlczgk4asm3hksg"
            ],
            "script": "5120c89c66e9e17bffd0639a4b0597e3b3ee059f9c6dbd6bca939429686fe048b57b",
            "script_type": "pay-to-taproot",
            "value": 19000
        }
    ],
    "preference": "low",
    "received": "2023-11-02T15:54:02.249240475Z",
    "relayed_by": "44.202.163.146",
    "size": 268,
    "total": 19000,
    "ver": 2,
    "vin_sz": 1,
    "vout_sz": 1,
    "vsize": 138
}

When I try to broadcast the transaction I get this error: 'sendrawtransaction RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Witness program hash mismatch)"}'

Invalid Schnorr Siganture - Example: Basic spend using key-path

I have a method to send sats from one p2tr address to another one. I followed this example to implement it.

The validation goes through, but when I submit the transaction to mempool.space (or blockstream, same thing), I get the following response:
sendrawtransaction RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Invalid Schnorr signature)"}

Here is the code I send sats with (essentially the same as the example, but with many UTXOs in tx input):
https://pastebin.com/hBGXNnJe

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.