Skip to content

Instantly share code, notes, and snippets.

@baryon
Last active November 9, 2022 22:27
Show Gist options
  • Save baryon/cb673e9c1d68a0f35011720b24b2b16f to your computer and use it in GitHub Desktop.
Save baryon/cb673e9c1d68a0f35011720b24b2b16f to your computer and use it in GitHub Desktop.
Create Bitcoin Script from any unlockTx or lockingTx
const bsv = require( 'bsv' )
const WhatsOnChain = require( 'whatsonchain' )
const _ = require( 'lodash' )
async function createScriptFromTx ( woc, prevTxid, outputIndex, scriptName, unlockParams = '', debugParams = '', txContext = {} ) {
//fetch transaction from prevTxid
const prevTxHex = await woc.getRawTxData( prevTxid )
const prevTx = new bsv.Transaction(prevTxHex)
//analyse locking script
const output = prevTx.outputs[ outputIndex ]
const asm = output.script.toASM()
const fixedAsm = _.map( asm.split( ' ' ), ( item ) => {
switch ( item ) {
case '0':
return 'OP_0'
case '-1':
return 'OP_1NEGATE'
default:
return item
}
} ).join( '\n' )
//create scrypt file
const contract = `
contract ${scriptName} {
public function unlock(${unlockParams}) {
asm {
${fixedAsm}
}
}
}
`
console.log( `${scriptName}.scrypt ` + '>'.repeat( 10 ) )
console.log( contract )
console.log( '<'.repeat( 10 ) + ` ${scriptName}.scrypt `, '\n' )
//debug's setting, paste to .vscode/launch.json
const debugSetting = `
{
"type": "scrypt",
"request": "launch",
"name": "Debug ${scriptName}",
"program": "\${workspaceFolder}/contracts/${scriptName}.scrypt",
"constructorArgs": [
],
"pubFunc": "unlock",
"pubFuncArgs": [
${debugParams}
],
"txContext": {
"hex": "${txContext.hex}",
"inputIndex": ${txContext.inputIndex},
"inputSatoshis": ${prevTx.outputs[ outputIndex ].satoshis}
}
}
`
console.log( `launche.json ` + '>'.repeat( 10 ) )
console.log( debugSetting )
console.log( '<'.repeat( 10 ) + ` launche.json` )
return { contract, debugSetting }
}
async function createScriptFromUnlockTx ( woc, unlockTxId, inputIndex, scriptName ) {
//fetch transaction from unlocking tx
const unlockTxHex = await woc.getRawTxData( unlockTxId )
const unlockTx = new bsv.Transaction(unlockTxHex)
const input = unlockTx.inputs[ inputIndex ]
const prevTxid = input.prevTxId.toString('hex')
const outputIndex = input.outputIndex
let unlockParams, debugParams
const unlockASM = input.script.toASM()
const asms = _.map( unlockASM.split( ' ' ), ( item ) => {
switch ( item ) {
case '0':
return '00'
case '-1', 'OP_1NEGATE':
return '81'
default:
const m = item.match(/^OP_(\d+)$/)
if(m) {
const v = parseInt(m[1]).toString(16)
return v.length < 2 ? '0' + v : v
}
return item
}
} )
unlockParams = 'bytes p0'
debugParams = `"b'${asms[ 0 ]}'"`
for ( let i = 1; i < asms.length; i++ ) {
unlockParams += `, bytes p${i}`
debugParams += `, "b'${asms[ i ]}'"`
}
const txContext = {
hex: unlockTx.uncheckedSerialize(),
inputIndex
}
return createScriptFromTx(woc, prevTxid, outputIndex, scriptName, unlockParams, debugParams, txContext)
}
//network: testnet/livenet
const woc = new WhatsOnChain( 'livenet' )
//unlocking tx
//const unlockTxId = '20adad8bd4cc694cfed4ccadff911433601e55b0f8779e839bc6579cb8d234f9'
const unlockTxId = 'fc5e29ae7aafeb774cc1f94c951381bff358af64e8ad33a8a932c2271c64f2a4'
//const unlockTxId = '83a1d69d99797aee3936ced2908a59428e33db1fdaeee4125f278a3815b64403'
//Index
const inputIndex = 0
//scriptName
const scriptName = 'SimpleP2PKH'
createScriptFromUnlockTx( woc, unlockTxId, inputIndex, scriptName )
@baryon
Copy link
Author

baryon commented Apr 4, 2021

another example on unlockTxId = '20adad8bd4cc694cfed4ccadff911433601e55b0f8779e839bc6579cb8d234f9'

https://whatsonchain.com/tx/20adad8bd4cc694cfed4ccadff911433601e55b0f8779e839bc6579cb8d234f9

% node createScriptFromTx.js
MultiSigBUG.scrypt >>>>>>>>>>

contract MultiSigBUG {
  public function unlock(bytes p0, bytes p1) {
    asm {
      OP_0
OP_TOALTSTACK
OP_IF
OP_DUP
OP_HASH160
dd2d89bb9f64cbdf4139ff0e23c4813124af85e6
OP_EQUALVERIFY
OP_CHECKSIGVERIFY
OP_FROMALTSTACK
OP_1ADD
OP_TOALTSTACK
OP_ENDIF
OP_IF
OP_DUP
OP_HASH160
aef82c0ef3f0c1d867e12b64e9e8d2ebb983dc81
OP_EQUALVERIFY
OP_CHECKSIGVERIFY
OP_FROMALTSTACK
OP_1ADD
OP_TOALTSTACK
OP_ENDIF
OP_2
OP_FROMALTSTACK
OP_GREATERTHANOREQUAL
    }
  }
}
  
<<<<<<<<<< MultiSigBUG.scrypt  

launche.json >>>>>>>>>>

{
  "type": "scrypt",
  "request": "launch",
  "name": "Debug MultiSigBUG",
  "program": "${workspaceFolder}/contracts/MultiSigBUG.scrypt",
  "constructorArgs": [
  ],
  "pubFunc": "unlock",
  "pubFuncArgs": [
    "b'00'", "b'00'"
  ],
  "txContext": {
    "hex": "02000000066ae810f19d8427fd95cbffa2ea01e8adfbc9c9710e9f137c00ce007dd78be3b600000000020000ffffffff45730c9a39f17564c5a267a0b27cd0f20ab13fb2f20b45e5a95584fafeb2f7e501000000020000ffffffffc05321108d3881221bf32d41084ac73af16dde235490d06c52a23c4e10b741e101000000020000ffffffff0b3da4ebb0d52439c24be0ae37bc77d87b820e6aebd8a013a4dc47fc8cace17901000000020000ffffffff50726d09ed427b43083a07fb871efc8999b6e7097b8dd2571958042f8adea1d601000000020000ffffffff40191014b8a0a1c2bbfe9da361ad0dbba3c5e4408dbe360b7dcb677ce9b2597401000000020000ffffffff01685747f80d0000001976a914d7185cd6f589013da9f72efba7193d7536b6175c88ac00000000",
    "inputIndex": 0,
    "inputSatoshis": 10000000000
  }
}
  
<<<<<<<<<< launche.json

@baryon
Copy link
Author

baryon commented Apr 4, 2021

Debug the output asm code using sCrypt vscode extension https://marketplace.visualstudio.com/items?itemName=bsv-scrypt.sCrypt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment