Skip to content

Instantly share code, notes, and snippets.

@mahdiidarabi
Created December 4, 2020 14:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mahdiidarabi/5a97e29626cca5fbf67f882e0eb1f9e4 to your computer and use it in GitHub Desktop.
Save mahdiidarabi/5a97e29626cca5fbf67f882e0eb1f9e4 to your computer and use it in GitHub Desktop.
sign a multi sig transaction in the format of P2SH in go
package main
import (
"bytes"
"encoding/hex"
"fmt"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
func SpendMultiSig() (string, error) {
// you can use your wif
wifStr1 := "cQpHXfs91s5eR9PWXui6qo2xjoJb2X3VdUspwKXe4A8Dybvut2rL"
wif1, err := btcutil.DecodeWIF(wifStr1)
if err != nil {
return "", err
}
// public key extracted from wif.PrivKey
pk1 := wif1.PrivKey.PubKey().SerializeCompressed()
wifStr2 := "cVgxEkRBtnfvd41ssd4PCsiemahAHidFrLWYoDBMNojUeME8dojZ"
wif2, err := btcutil.DecodeWIF(wifStr2)
if err != nil {
return "", err
}
pk2 := wif2.PrivKey.PubKey().SerializeCompressed()
wifStr3 := "cPXZBMz5pKytwCyUNAdq94R9VafU8L2QmAW8uw3gKrzjuCWCd3TM"
wif3, err := btcutil.DecodeWIF(wifStr3)
if err != nil {
return "", nil
}
pk3 := wif3.PrivKey.PubKey().SerializeCompressed()
// create redeem script for 2 of 3 multi-sig
builder := txscript.NewScriptBuilder()
// add the minimum number of needed signatures
builder.AddOp(txscript.OP_2)
// add the 3 public key
builder.AddData(pk1).AddData(pk2).AddData(pk3)
// add the total number of public keys in the multi-sig screipt
builder.AddOp(txscript.OP_3)
// add the check-multi-sig op-code
builder.AddOp(txscript.OP_CHECKMULTISIG)
// redeem script is the script program in the format of []byte
redeemScript, err := builder.Script()
if err != nil {
return "", err
}
redeemTx := wire.NewMsgTx(wire.TxVersion)
// you should provide your UTXO hash
utxoHash, err := chainhash.NewHashFromStr( "b14e1fda5f3f74cfceb43bce9b35b0bbe3d5666d21cc802b30dc2fb738a475fe")
if err != nil {
return "", nil
}
// and add the index of the UTXO
outPoint := wire.NewOutPoint(utxoHash, 1)
txIn := wire.NewTxIn(outPoint, nil, nil)
redeemTx.AddTxIn(txIn)
// adding the output to tx
decodedAddr, err := btcutil.DecodeAddress("mxnMVvGkEsC8YQeUXoos9MXJSne9UVnbCS", &chaincfg.TestNet3Params)
if err != nil {
return "", err
}
destinationAddrByte, err := txscript.PayToAddrScript(decodedAddr)
if err != nil {
return "", err
}
// adding the destination address and the amount to the transaction
redeemTxOut := wire.NewTxOut(43000, destinationAddrByte)
redeemTx.AddTxOut(redeemTxOut)
// signing the tx
sig1, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wif1.PrivKey)
if err != nil {
return "", err
}
//sig2, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wif2.PrivKey)
//if err != nil {
// return "", err
//}
sig3, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wif3.PrivKey)
if err != nil {
fmt.Println("got error in constructing sig3")
return "", err
}
signature := txscript.NewScriptBuilder()
signature.AddOp(txscript.OP_FALSE).AddData(sig1)
signature.AddData(sig3).AddData(redeemScript)
signatureScript, err := signature.Script()
if err != nil {
// Handle the error.
return "", err
}
redeemTx.TxIn[0].SignatureScript = signatureScript
var signedTx bytes.Buffer
redeemTx.Serialize(&signedTx)
hexSignedTx := hex.EncodeToString(signedTx.Bytes())
return hexSignedTx, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment