Created
December 4, 2020 14:17
-
-
Save mahdiidarabi/5a97e29626cca5fbf67f882e0eb1f9e4 to your computer and use it in GitHub Desktop.
sign a multi sig transaction in the format of P2SH in go
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
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