Skip to content

Instantly share code, notes, and snippets.

@ryandotsmith
Created January 15, 2015 01:10
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryandotsmith/e9b82473994c8b7bc0fc to your computer and use it in GitHub Desktop.
Save ryandotsmith/e9b82473994c8b7bc0fc to your computer and use it in GitHub Desktop.
Sending an OP_RETURN Bitcoin Transaction with Go using Chain's Bitcoin API
package main
import (
"bytes"
"encoding/hex"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"github.com/ryandotsmith/x/Godeps/_workspace/src/github.com/conformal/btcec"
"github.com/ryandotsmith/x/Godeps/_workspace/src/github.com/conformal/btcnet"
"github.com/ryandotsmith/x/Godeps/_workspace/src/github.com/conformal/btcscript"
"github.com/ryandotsmith/x/Godeps/_workspace/src/github.com/conformal/btcutil"
"github.com/ryandotsmith/x/Godeps/_workspace/src/github.com/conformal/btcwire"
)
const sendURL = "https://api.chain.com/v2/testnet3/transactions/send"
var (
pkWIF = "cMcv2Y3vDY2STEkFqsDrVryZ7dZHkL9gNExMg1jmk2BSVMizinHu"
prevOutPkScriptStr = "76a9147af1bab2645028cd20a491b7929dec96f94d5efc88ac"
prevOutHashStr = "4ca3ab297341bec8603f16a747068975531339bf72469b40bc89cfd54eeb56fa"
prevOutIndex = uint32(0)
changeAddressStr = "mrj2K6txjo2QBcSmuAzHj4nD1oXSEJE1Qo"
change = 100000
)
func init() {
log.SetFlags(log.Lshortfile)
}
func main() {
wif, err := btcutil.DecodeWIF(pkWIF)
if err != nil {
log.Fatal(err)
}
prevOutHash, err := btcwire.NewShaHashFromStr(prevOutHashStr)
if err != nil {
log.Fatal(err)
}
prevOutPkScript, err := hex.DecodeString(prevOutPkScriptStr)
if err != nil {
log.Fatal(err)
}
changeAddress, err := btcutil.DecodeAddress(changeAddressStr, &btcnet.TestNet3Params)
if err != nil {
log.Fatal(err)
}
sendTx(buildTxOPRETURN(wif.PrivKey, changeAddress, prevOutHash, prevOutPkScript, "Hello from Chain."))
}
func buildTxOPRETURN(key *btcec.PrivateKey, changeAddress btcutil.Address, hash *btcwire.ShaHash, script []byte, data string) []byte {
tx := btcwire.NewMsgTx()
txin := btcwire.NewTxIn(btcwire.NewOutPoint(hash, prevOutIndex), []byte{})
tx.AddTxIn(txin)
b := btcscript.NewScriptBuilder()
b.AddOp(btcscript.OP_RETURN)
b.AddData([]byte(data))
pkScript, err := btcscript.PayToAddrScript(changeAddress)
if err != nil {
log.Fatal(err)
}
tx.AddTxOut(btcwire.NewTxOut(int64(change), pkScript))
tx.AddTxOut(btcwire.NewTxOut(0, b.Script()))
sig, err := btcscript.SignatureScript(tx,
0, script, btcscript.SigHashAll, key.ToECDSA(), true)
if err != nil {
log.Fatal(err)
}
txin.SignatureScript = sig
var signedTxHex bytes.Buffer
if err := tx.Serialize(&signedTxHex); err != nil {
log.Fatal(err)
}
return signedTxHex.Bytes()
}
func sendTx(signedHex []byte) {
var sendTxReq = struct {
Hex string `json:"signed_hex"`
}{hex.EncodeToString(signedHex)}
log.Printf("reqBody=%s\n", sendTxReq.Hex)
var reqBuf bytes.Buffer
if err := json.NewEncoder(&reqBuf).Encode(sendTxReq); err != nil {
log.Fatal(err)
}
req, err := http.NewRequest("POST", sendURL, &reqBuf)
if err != nil {
log.Fatal(err)
}
req.SetBasicAuth("GUEST-TOKEN", "")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Printf("respBody=%s\n", string(respBody))
}
@ryandotsmith
Copy link
Author

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