-
-
Save relayking/7a0c73c8a687f5af18d7e0e814be7bdc to your computer and use it in GitHub Desktop.
fastor 21e8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const axios = require('axios'); | |
const bsv = require('bsv'); | |
const chalk = require('chalk'); | |
const secp256k1 = require('secp256k1') | |
const PrivateKey = bsv.PrivateKey; | |
const Opcode = bsv.Opcode; | |
const Transaction = bsv.Transaction; | |
const crypto = require('crypto'); | |
function sha256(data) { | |
return crypto.createHash('sha256').update(data).digest('hex') | |
} | |
const sigtype = bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID; | |
const flags = bsv.Script.Interpreter.SCRIPT_VERIFY_MINIMALDATA | bsv.Script.Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID | bsv.Script.Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES | bsv.Script.Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES; | |
function is21e8Out(script) { | |
return !!( | |
script.chunks.length === 12 && | |
script.chunks[0].buf && | |
script.chunks[0].buf.length === 32 && | |
script.chunks[1].buf && | |
script.chunks[1].buf.length >= 1 && | |
script.chunks[2].opcodenum === Opcode.OP_SIZE && | |
script.chunks[3].opcodenum === Opcode.OP_4 && | |
script.chunks[4].opcodenum === Opcode.OP_PICK && | |
script.chunks[5].opcodenum === Opcode.OP_SHA256 && | |
script.chunks[6].opcodenum === Opcode.OP_SWAP && | |
script.chunks[7].opcodenum === Opcode.OP_SPLIT && | |
script.chunks[8].opcodenum === Opcode.OP_DROP && | |
script.chunks[9].opcodenum === Opcode.OP_EQUALVERIFY && | |
script.chunks[10].opcodenum === Opcode.OP_DROP && | |
script.chunks[11].opcodenum === Opcode.OP_CHECKSIG | |
); | |
} | |
let count = 0; | |
const st = new Date() | |
function sign(hashbuf, target=''){ | |
const privKey = PrivateKey.fromRandom(); | |
const sig = secp256k1.signatureExport(secp256k1.signatureNormalize(secp256k1.ecdsaSign(hashbuf, privKey.toBuffer()).signature)); | |
count ++; | |
if(target!=''){ | |
const sig256 = sha256(Buffer.concat([sig, Buffer.from(sigtype.toString(16), 'hex')])); | |
if(!sig256.startsWith(target)){ | |
if (count % 1000 === 0) { | |
process.stdout.clearLine(); | |
process.stdout.cursorTo(0); | |
process.stdout.write(chalk.gray(count / (+ new Date() - st) * 1000)); | |
} | |
return [false, false]; | |
} else { | |
return [sig, privKey]; | |
} | |
} | |
return [sig, privKey]; | |
} | |
const start = async() => { | |
try { | |
const txid = '7e4479e828eae6f7d465a26a25c769e886e933df3432b55c60b9a31e9e985b45'; | |
if(txid === 'exit') return; //let them exit | |
let tx; | |
try { | |
const {data} = await axios.get(`https://api.whatsonchain.com/v1/bsv/main/tx/hash/${txid}`); | |
tx = data; | |
} catch(e) { | |
throw("TX not found."); | |
} | |
let index = -1; | |
for(let i=0; i<tx.vout.length; i++) { | |
if(is21e8Out(bsv.Script.fromHex(tx.vout[i].scriptPubKey.hex))){ | |
index = i; | |
break; | |
} | |
} | |
if(index<0){ | |
throw("No 21e8 outputs found"); | |
} | |
let {to} = {to: '1KzCAPfsGzmNukukPcZSwyhAAdNFd5MCnG'}; | |
if(txid === 'exit') return; //let them exit | |
if(!to.length){ | |
throw("No address found."); | |
} | |
try { | |
to = bsv.Script.buildPublicKeyHashOut(to); | |
} catch(e){ | |
throw("Invalid address"); | |
} | |
console.log("Automatically publish when mined? Y/N"); | |
let {publish} = {publish: 'y'}; | |
publish = (publish.toLowerCase()[0] == 'y') ? true : false; | |
console.log(chalk.green(`Mining TX ${txid} output ${index}`)); | |
console.log(chalk.green(`Pay to: ${to}`)); | |
mineId(tx, index, to, publish); | |
} catch(e){ | |
console.log(chalk.red(e)); | |
start(); | |
} | |
} | |
const mineId = async(from, index, to, publish) => { | |
const vout = from.vout[index]; | |
const value = Math.floor(vout.value*1e8); | |
const targetScript = bsv.Script.fromHex(vout.scriptPubKey.hex); | |
const target = targetScript.toASM().split(" ")[1].toString('hex'); | |
//Make initial TX | |
let tx = new Transaction(); | |
tx.addInput( | |
new Transaction.Input({ | |
output: new Transaction.Output({ | |
script: targetScript, | |
satoshis: value | |
}), | |
prevTxId: from.txid, | |
outputIndex: index, | |
script: bsv.Script.empty() | |
}) | |
); | |
tx.addOutput( | |
new Transaction.Output({ | |
satoshis: value-218, | |
script: to | |
}) | |
); | |
console.log(chalk.green(`Targeting: ${target}`)); | |
let sig, privKey; | |
if(!is21e8Out(tx.inputs[0].output.script)){ | |
throw("Not a valid 21e8 script"); | |
} | |
const sighash = Transaction.sighash.sighash(tx, sigtype, 0, tx.inputs[0].output.script, new bsv.crypto.BN(tx.inputs[0].output.satoshis), flags).reverse(); | |
while(!sig) { | |
[sig, privKey] = sign(sighash, target) | |
} | |
const unlockingScript = new bsv.Script({}); | |
unlockingScript | |
.add( | |
Buffer.concat([ | |
sig, | |
Buffer.from([sigtype & 0xff]) | |
]) | |
) | |
.add(privKey.toPublicKey().toBuffer()); | |
tx.inputs[0].setScript(unlockingScript); | |
console.log(unlockingScript.toString()) | |
console.log(chalk.green(`Signed ${target} with ${privKey.toString()}`)); | |
if(!!publish){ | |
try { | |
const {data} = await axios.post('https://api.whatsonchain.com/v1/bsv/main/tx/raw', { txhex: tx.uncheckedSerialize() }); | |
console.log(chalk.green('Published ' + Buffer.from(tx._getHash()).reverse().toString('hex'))); | |
} catch(e) { | |
console.log(chalk.red(JSON.stringify({error: e.response.data}))); | |
} | |
} else { | |
return; | |
} | |
} | |
start(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment