// return the change addrress or nil if there will be no change func get_change_addr() (chng *btc.BtcAddr) { if *change != "" { var e error chng, e = btc.NewAddrFromString(*change) if e != nil { println("Change address:", e.Error()) cleanExit(1) } assert_address_version(chng) return } // If change address not specified, send it back to the first input for idx := range unspentOuts { if unspentOuts[idx].stealth { continue // cannot send change to a stelath address since we don't know the scankey } uo := getUO(&unspentOuts[idx].TxPrevOut) if k := pkscr_to_key(uo.Pk_script); k != nil { chng = k.BtcAddr return } } fmt.Println("ERROR: Could not determine address where to send change. Add -change switch") cleanExit(1) return }
// parse the "-send ..." parameter func parse_spend() { outs := strings.Split(*send, ",") for i := range outs { tmp := strings.Split(strings.Trim(outs[i], " "), "=") if len(tmp) != 2 { println("The outputs must be in a format address1=amount1[,addressN=amountN]") cleanExit(1) } a, e := btc.NewAddrFromString(tmp[0]) if e != nil { println("NewAddrFromString:", e.Error()) cleanExit(1) } assert_address_version(a) am, er := btc.StringToSatoshis(tmp[1]) if er != nil { println("Incorrect amount: ", tmp[1], er.Error()) cleanExit(1) } if *subfee { am -= curFee } sendTo = append(sendTo, oneSendTo{addr: a, amount: am}) spendBtc += am } }
func load_wallet(fn string) (addrs []*btc.BtcAddr) { f, e := os.Open(fn) if e != nil { println(e.Error()) return } defer f.Close() rd := bufio.NewReader(f) linenr := 0 for { var l string l, e = rd.ReadString('\n') l = strings.Trim(l, " \t\r\n") linenr++ if len(l) > 0 { if l[0] == '@' { fmt.Println("netsted wallet in line", linenr, "- ignore it") } else if l[0] != '#' { ls := strings.SplitN(l, " ", 2) if len(ls) > 0 { a, e := btc.NewAddrFromString(ls[0]) if e != nil { println(fmt.Sprint(fn, ":", linenr), e.Error()) } else { addrs = append(addrs, a) } } } } if e != nil { break } } return }
func ReloadMiners() { d, _ := ioutil.ReadFile("miners.json") if d != nil { var MinerIdFile [][3]string e := json.Unmarshal(d, &MinerIdFile) if e != nil { println("miners.json", e.Error()) return } MinerIds = nil for _, r := range MinerIdFile { var rec oneMinerId rec.Name = r[0] if r[1] != "" { rec.Tag = []byte(r[1]) } else { if a, _ := btc.NewAddrFromString(r[2]); a != nil { rec.Tag = a.OutScript() } else { println("Error in miners.json for", r[0]) continue } } MinerIds = append(MinerIds, rec) } } }
func address_to_key(addr string) *btc.PrivateAddr { a, e := btc.NewAddrFromString(addr) if e != nil { println("Cannot Decode address", addr) println(e.Error()) cleanExit(1) } return hash_to_key(a.Hash160) }
// parse the "-batch ..." parameter func parse_batch() { f, e := os.Open(*batch) if e == nil { defer f.Close() td := bufio.NewReader(f) var lcnt int for { li, _, _ := td.ReadLine() if li == nil { break } lcnt++ tmp := strings.SplitN(strings.Trim(string(li), " "), "=", 2) if len(tmp) < 2 { println("Error in the batch file line", lcnt) cleanExit(1) } if tmp[0][0] == '#' { continue // Just a comment-line } a, e := btc.NewAddrFromString(tmp[0]) if e != nil { println("NewAddrFromString:", e.Error()) cleanExit(1) } assert_address_version(a) am, e := btc.StringToSatoshis(tmp[1]) if e != nil { println("StringToSatoshis:", e.Error()) cleanExit(1) } sendTo = append(sendTo, oneSendTo{addr: a, amount: am}) spendBtc += am } } else { println(e.Error()) cleanExit(1) } }
func main() { fmt.Println("Gocoin FetchBal version", lib.Version) fmt.Println("NOTE: This tool is deprecated. Use balio instead.") proxy = os.Getenv("TOR") if proxy != "" { fmt.Println("Using Tor at", proxy) http.DefaultClient.Transport = &http.Transport{Dial: dials5} } else { fmt.Println("WARNING: not using Tor (setup TOR variable, if you want)") } if len(os.Args) < 2 { print_help() return } var addrs []*btc.BtcAddr if len(os.Args) == 2 { fi, er := os.Stat(os.Args[1]) if er == nil && fi.Size() > 10 && !fi.IsDir() { wal := wallet.NewWallet(os.Args[1]) if wal != nil { fmt.Println("Found", len(wal.Addrs), "address(es) in", wal.FileName) addrs = wal.Addrs } } } if len(addrs) == 0 { for i := 1; i < len(os.Args); i++ { a, e := btc.NewAddrFromString(os.Args[i]) if e != nil { println(os.Args[i], ": ", e.Error()) return } else { addrs = append(addrs, a) } } } if len(addrs) == 0 { print_help() return } url := "http://blockchain.info/unspent?active=" for i := range addrs { if i > 0 { url += "|" } url += addrs[i].String() } var sum, outcnt uint64 r, er := http.Get(url) //println(url) if er == nil && r.StatusCode == 200 { defer r.Body.Close() c, _ := ioutil.ReadAll(r.Body) var r restype er = json.Unmarshal(c[:], &r) if er == nil { os.RemoveAll("balance/") os.Mkdir("balance/", 0700) unsp, _ := os.Create("balance/unspent.txt") for i := 0; i < len(r.Unspent_outputs); i++ { pkscr, _ := hex.DecodeString(r.Unspent_outputs[i].Script) b58adr := "???" if pkscr != nil { ba := btc.NewAddrFromPkScript(pkscr, false) if ba != nil { b58adr = ba.String() } } txidlsb, _ := hex.DecodeString(r.Unspent_outputs[i].Tx_hash) if txidlsb != nil { txid := btc.NewUint256(txidlsb) rawtx := utils.GetTxFromWeb(txid) if rawtx != nil { ioutil.WriteFile("balance/"+txid.String()+".tx", rawtx, 0666) fmt.Fprintf(unsp, "%s-%03d # %.8f @ %s, %d confs\n", txid.String(), r.Unspent_outputs[i].Tx_output_n, float64(r.Unspent_outputs[i].Value)/1e8, b58adr, r.Unspent_outputs[i].Confirmations) sum += r.Unspent_outputs[i].Value outcnt++ } else { fmt.Printf(" - cannot fetch %s-%03d\n", txid.String(), r.Unspent_outputs[i].Tx_output_n) } } } unsp.Close() if outcnt > 0 { fmt.Printf("Total %.8f BTC in %d unspent outputs.\n", float64(sum)/1e8, outcnt) fmt.Println("The data has been stored in 'balance' folder.") fmt.Println("Use it with the wallet app to spend any of it.") } else { fmt.Println("The fateched balance is empty.") } } else { fmt.Println("Unspent json.Unmarshal", er.Error()) } } else { if er != nil { fmt.Println("Unspent ", er.Error()) } else { fmt.Println("Unspent HTTP StatusCode", r.StatusCode) } } }
func list_unspent(addr string) { fmt.Println("Checking unspent coins for addr", addr) defer func() { // in case if ad.OutScript() would panic if r := recover(); r != nil { err := r.(error) fmt.Println("main panic recovered:", err.Error()) } }() var ad *btc.BtcAddr var e error ad, e = btc.NewAddrFromString(addr) if e != nil { println(e.Error()) return } sa := ad.StealthAddr var walk chain.FunctionWalkUnspent var unsp chain.AllUnspentTx if sa == nil { exp_scr := ad.OutScript() walk = func(tx *chain.QdbRec) { for idx, rec := range tx.Outs { if rec != nil && bytes.Equal(rec.PKScr, exp_scr) { unsp = append(unsp, tx.ToUnspent(uint32(idx), ad)) } } } } else { var c, spen_exp []byte var rec, out *chain.QdbTxOut var h160 [20]byte wallet.FetchStealthKeys() d := wallet.FindStealthSecret(sa) if d == nil { fmt.Println("No matching secret found in your wallet/stealth folder") return } walk = func(tx *chain.QdbRec) { for i := 0; i < len(tx.Outs)-1; i++ { if rec = tx.Outs[i]; rec == nil { continue } if out = tx.Outs[i+1]; out == nil { continue } if !rec.IsStealthIdx() || !out.IsP2KH() || !ad.StealthAddr.CheckNonce(rec.PKScr[3:40]) { continue } c = btc.StealthDH(rec.PKScr[7:40], d) spen_exp = btc.DeriveNextPublic(sa.SpendKeys[0][:], c) btc.RimpHash(spen_exp, h160[:]) if bytes.Equal(out.PKScr[3:23], h160[:]) { uo := new(chain.OneUnspentTx) uo.TxPrevOut.Hash = tx.TxID uo.TxPrevOut.Vout = uint32(i + 1) uo.Value = out.Value uo.MinedAt = tx.InBlock uo.BtcAddr = btc.NewAddrFromHash160(h160[:], btc.AddrVerPubkey(common.CFG.Testnet)) uo.FixDestString() uo.BtcAddr.StealthAddr = sa uo.BtcAddr.Extra = ad.Extra uo.StealthC = c unsp = append(unsp, uo) } } } } common.BlockChain.Unspent.BrowseUTXO(false, walk) sort.Sort(unsp) var sum uint64 for i := range unsp { if len(unsp) < 200 { fmt.Println(unsp[i].String()) } sum += unsp[i].Value } fmt.Printf("Total %.8f unspent BTC in %d outputs at address %s\n", float64(sum)/1e8, len(unsp), ad.String()) }
func do_scan_stealth(p string, ignore_prefix bool) { ad, _ := btc.NewAddrFromString(p) if ad == nil { fmt.Println("Specify base58 encoded bitcoin address") return } sa := ad.StealthAddr if sa == nil { fmt.Println("Specify base58 encoded stealth address") return } if sa.Version != btc.StealthAddressVersion(common.Testnet) { fmt.Println("Incorrect version of the stealth address") return } if len(sa.SpendKeys) != 1 { fmt.Println("Currently only single spend keys are supported. This address has", len(sa.SpendKeys)) return } //fmt.Println("scankey", hex.EncodeToString(sa.ScanKey[:])) if ignore_prefix { sa.Prefix = []byte{0} fmt.Println("Ignoring Prefix inside the address") } else if len(sa.Prefix) == 0 { fmt.Println("Prefix not present in the address") } else { fmt.Println("Prefix", sa.Prefix[0], hex.EncodeToString(sa.Prefix[1:])) } wallet.FetchStealthKeys() d := wallet.FindStealthSecret(sa) if d == nil { fmt.Println("No matching secret found in your wallet/stealth folder") return } var unsp chain.AllUnspentTx var c, spen_exp []byte var rec, out *chain.QdbTxOut var h160 [20]byte common.BlockChain.Unspent.BrowseUTXO(true, func(tx *chain.QdbRec) { for i := 0; i < len(tx.Outs)-1; i++ { if rec = tx.Outs[i]; rec == nil { continue } if out = tx.Outs[i+1]; out == nil { continue } if !rec.IsStealthIdx() || !out.IsP2KH() || !ad.StealthAddr.CheckNonce(rec.PKScr[3:40]) { continue } c = btc.StealthDH(rec.PKScr[7:40], d) spen_exp = btc.DeriveNextPublic(sa.SpendKeys[0][:], c) btc.RimpHash(spen_exp, h160[:]) if bytes.Equal(out.PKScr[3:23], h160[:]) { uo := new(chain.OneUnspentTx) uo.TxPrevOut.Hash = tx.TxID uo.TxPrevOut.Vout = uint32(i + 1) uo.Value = out.Value uo.MinedAt = tx.InBlock uo.BtcAddr = btc.NewAddrFromHash160(h160[:], btc.AddrVerPubkey(common.CFG.Testnet)) uo.FixDestString() uo.BtcAddr.StealthAddr = sa uo.BtcAddr.Extra = ad.Extra uo.StealthC = c unsp = append(unsp, uo) } } }) sort.Sort(unsp) os.RemoveAll("balance") os.MkdirAll("balance/", 0770) utxt, _ := os.Create("balance/unspent.txt") fmt.Print(wallet.DumpBalance(unsp, utxt, true, false)) }
func main() { fmt.Println("Gocoin BalIO version", lib.Version) if len(os.Args) < 2 { print_help() return } proxy = os.Getenv("TOR") if proxy != "" { fmt.Println("Using Tor at", proxy) http.DefaultClient.Transport = &http.Transport{Dial: dials5} } else { fmt.Println("WARNING: not using Tor (setup TOR variable, if you want)") } var addrs []*btc.BtcAddr var argz []string for i := 1; i < len(os.Args); i++ { if os.Args[i] == "-ltc" { ltc = true } else if os.Args[i] == "-t" { tbtc = true } else { argz = append(argz, os.Args[i]) } } if len(argz) == 1 { fi, er := os.Stat(argz[0]) if er == nil && fi.Size() > 10 && !fi.IsDir() { addrs = load_wallet(argz[0]) if addrs != nil { fmt.Println("Found", len(addrs), "address(es) in", argz[0]) } } } if len(addrs) == 0 { for i := range argz { a, e := btc.NewAddrFromString(argz[i]) if e != nil { println(argz[i], ": ", e.Error()) return } else { addrs = append(addrs, a) } } } if len(addrs) == 0 { print_help() return } for i := range addrs { switch addrs[i].Version { case 48: ltc = true case 111: tbtc = true } } if tbtc && ltc { println("Litecoin's testnet is not suppported") return } url := base_url() + "address/unspent/" for i := range addrs { if i > 0 { url += "," } url += addrs[i].String() } if len(addrs) == 0 { println("No addresses to fetch balance for") return } var sum, outcnt uint64 os.RemoveAll("balance/") os.Mkdir("balance/", 0700) unsp, _ := os.Create("balance/unspent.txt") for off := 0; off < len(addrs); off += MAX_UNSPENT_AT_ONCE { var r []prvout if off+MAX_UNSPENT_AT_ONCE < len(addrs) { r = get_unspent(addrs[off : off+MAX_UNSPENT_AT_ONCE]) } else { r = get_unspent(addrs[off:]) } if r == nil { return } for i := range r { for j := range r[i].Unspent { txraw := get_raw_tx(r[i].Unspent[j].Tx) if len(txraw) > 0 { ioutil.WriteFile("balance/"+r[i].Unspent[j].Tx+".tx", txraw, 0666) } else { println("ERROR: cannot fetch raw tx data for", r[i].Unspent[j].Tx) os.Exit(1) } val, _ := btc.StringToSatoshis(r[i].Unspent[j].Amount) sum += val outcnt++ fmt.Fprintf(unsp, "%s-%03d # %s @ %s, %d confs", r[i].Unspent[j].Tx, r[i].Unspent[j].N, r[i].Unspent[j].Amount, r[i].Address, r[i].Unspent[j].Confirmations) fmt.Fprintln(unsp) } } } unsp.Close() if outcnt > 0 { fmt.Printf("Total %.8f %s in %d unspent outputs.\n", float64(sum)/1e8, curr_unit(), outcnt) fmt.Println("The data has been stored in 'balance' folder.") fmt.Println("Use it with the wallet app to spend any of it.") } else { fmt.Println("The fateched balance is empty.") } }
func LoadWalfile(fn string, included int) (addrs []*btc.BtcAddr) { waldir, walname := filepath.Split(fn) f, e := os.Open(fn) if e != nil { println(e.Error()) return } defer f.Close() rd := bufio.NewReader(f) linenr := 0 for { var l string l, e = rd.ReadString('\n') space_first := len(l) > 0 && l[0] == ' ' l = strings.Trim(l, " \t\r\n") linenr++ if len(l) > 0 { if l[0] == '@' { if included > 3 { println(fmt.Sprint(fn, ":", linenr), "Too many nested wallets") } else { ifn := strings.Trim(l[1:], " \n\t\t") addrs = append(addrs, LoadWalfile(waldir+ifn, included+1)...) } } else { var s string if l[0] != '#' { s = l } else if !PrecachingComplete && len(l) > 10 && l[1] == '1' { s = l[1:] // While pre-caching addresses, include ones that are commented out } if s != "" { ls := strings.SplitN(s, " ", 2) if len(ls) > 0 { a, e := btc.NewAddrFromString(ls[0]) if e != nil { println(fmt.Sprint(fn, ":", linenr), e.Error()) } else { a.Extra.Wallet = walname if len(ls) > 1 { a.Extra.Label = ls[1] } a.Extra.Virgin = space_first addrs = append(addrs, a) } } } } } if e != nil { break } } // remove duplicated addresses for i := 0; i < len(addrs)-1; i++ { for j := i + 1; j < len(addrs); { if addrs[i].Hash160 == addrs[j].Hash160 { if addrs[i].StealthAddr != nil && !bytes.Equal(addrs[i].Prefix, addrs[j].Prefix) { fmt.Println("WARNING: duplicate stealth addresses with different prefixes. Merging them into one with null-prefix") fmt.Println(" -", addrs[i].PrefixLen(), addrs[i].String()) fmt.Println(" -", addrs[j].PrefixLen(), addrs[j].String()) addrs[i].Prefix = []byte{0} addrs[i].Enc58str = addrs[i].StealthAddr.String() fmt.Println(" +", addrs[i].PrefixLen(), addrs[i].String()) } if addrs[i].Extra.Wallet == AddrBookFileName { // Overwrite wallet name if is was ADDRESS (book) addrs[i].Extra.Wallet = addrs[j].Extra.Wallet } addrs[i].Extra.Label += "*" + addrs[j].Extra.Label addrs = append(addrs[:j], addrs[j+1:]...) } else { j++ } } } return }
func main() { var msg []byte flag.Parse() if *help || *addr == "" || *sign == "" { flag.PrintDefaults() return } ad, er := btc.NewAddrFromString(*addr) if !*litecoin && ad != nil && ad.Version == ltc.AddrVerPubkey(false) { *litecoin = true } if er != nil { println("Address:", er.Error()) flag.PrintDefaults() return } nv, btcsig, er := btc.ParseMessageSignature(*sign) if er != nil { println("ParseMessageSignature:", er.Error()) return } if *mess != "" { msg = []byte(*mess) } else if *mfil != "" { msg, er = ioutil.ReadFile(*mfil) if er != nil { println(er.Error()) return } } else { if *verb { fmt.Println("Enter the message:") } msg, _ = ioutil.ReadAll(os.Stdin) } if *unix { if *verb { fmt.Println("Enforcing Unix text format") } msg = bytes.Replace(msg, []byte{'\r'}, nil, -1) } hash := make([]byte, 32) if *litecoin { ltc.HashFromMessage(msg, hash) } else { btc.HashFromMessage(msg, hash) } compressed := false if nv >= 31 { if *verb { fmt.Println("compressed key") } nv -= 4 compressed = true } pub := btcsig.RecoverPublicKey(hash[:], int(nv-27)) if pub != nil { pk := pub.Bytes(compressed) ok := btc.EcdsaVerify(pk, btcsig.Bytes(), hash) if ok { sa := btc.NewAddrFromPubkey(pk, ad.Version) if ad.Hash160 != sa.Hash160 { fmt.Println("BAD signature for", ad.String()) if bytes.IndexByte(msg, '\r') != -1 { fmt.Println("You have CR chars in the message. Try to verify with -u switch.") } os.Exit(1) } else { fmt.Println("Signature OK") } } else { println("BAD signature") os.Exit(1) } } else { println("BAD, BAD, BAD signature") os.Exit(1) } }
func dl_payment(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } var err string if len(r.Form["outcnt"]) == 1 { var thisbal chain.AllUnspentTx var pay_cmd string var totalinput, spentsofar uint64 var change_addr *btc.BtcAddr var multisig_input []*wallet.MultisigAddr addrs_to_msign := make(map[string]bool) tx := new(btc.Tx) tx.Version = 1 tx.Lock_time = 0 outcnt, _ := strconv.ParseUint(r.Form["outcnt"][0], 10, 32) wallet.BalanceMutex.Lock() for i := 1; i <= int(outcnt); i++ { is := fmt.Sprint(i) if len(r.Form["txout"+is]) == 1 && r.Form["txout"+is][0] == "on" { hash := btc.NewUint256FromString(r.Form["txid"+is][0]) if hash != nil { vout, er := strconv.ParseUint(r.Form["txvout"+is][0], 10, 32) if er == nil { var po = btc.TxPrevOut{Hash: hash.Hash, Vout: uint32(vout)} for j := range wallet.MyBalance { if wallet.MyBalance[j].TxPrevOut == po { thisbal = append(thisbal, wallet.MyBalance[j]) // Add the input to our tx tin := new(btc.TxIn) tin.Input = wallet.MyBalance[j].TxPrevOut tin.Sequence = 0xffffffff tx.TxIn = append(tx.TxIn, tin) // Add new multisig address description _, msi := wallet.IsMultisig(wallet.MyBalance[j].BtcAddr) multisig_input = append(multisig_input, msi) if msi != nil { for ai := range msi.ListOfAddres { addrs_to_msign[msi.ListOfAddres[ai]] = true } } // Add the value to total input value totalinput += wallet.MyBalance[j].Value // If no change specified, use the first input addr as it if change_addr == nil { change_addr = wallet.MyBalance[j].BtcAddr } } } } } } } wallet.BalanceMutex.Unlock() for i := 1; ; i++ { adridx := fmt.Sprint("adr", i) btcidx := fmt.Sprint("btc", i) if len(r.Form[adridx]) != 1 || len(r.Form[btcidx]) != 1 { break } if len(r.Form[adridx][0]) > 1 { addr, er := btc.NewAddrFromString(r.Form[adridx][0]) if er == nil { am, er := btc.StringToSatoshis(r.Form[btcidx][0]) if er == nil && am > 0 { if pay_cmd == "" { pay_cmd = "wallet -useallinputs -send " } else { pay_cmd += "," } pay_cmd += addr.Enc58str + "=" + btc.UintToBtc(am) outs, er := btc.NewSpendOutputs(addr, am, common.CFG.Testnet) if er != nil { err = er.Error() goto error } tx.TxOut = append(tx.TxOut, outs...) spentsofar += am } else { err = "Incorrect amount (" + r.Form[btcidx][0] + ") for Output #" + fmt.Sprint(i) goto error } } else { err = "Incorrect address (" + r.Form[adridx][0] + ") for Output #" + fmt.Sprint(i) goto error } } } if pay_cmd == "" { err = "No inputs selected" goto error } am, er := btc.StringToSatoshis(r.Form["txfee"][0]) if er != nil { err = "Incorrect fee value: " + r.Form["txfee"][0] goto error } pay_cmd += " -fee " + r.Form["txfee"][0] spentsofar += am if len(r.Form["change"][0]) > 1 { addr, er := btc.NewAddrFromString(r.Form["change"][0]) if er != nil { err = "Incorrect change address: " + r.Form["change"][0] goto error } change_addr = addr } pay_cmd += " -change " + change_addr.String() if totalinput > spentsofar { // Add change output outs, er := btc.NewSpendOutputs(change_addr, totalinput-spentsofar, common.CFG.Testnet) if er != nil { err = er.Error() goto error } tx.TxOut = append(tx.TxOut, outs...) } buf := new(bytes.Buffer) zi := zip.NewWriter(buf) was_tx := make(map[[32]byte]bool, len(thisbal)) for i := range thisbal { if was_tx[thisbal[i].TxPrevOut.Hash] { continue } was_tx[thisbal[i].TxPrevOut.Hash] = true txid := btc.NewUint256(thisbal[i].TxPrevOut.Hash[:]) fz, _ := zi.Create("balance/" + txid.String() + ".tx") wallet.GetRawTransaction(thisbal[i].MinedAt, txid, fz) } fz, _ := zi.Create("balance/unspent.txt") for i := range thisbal { fmt.Fprintln(fz, thisbal[i].UnspentTextLine()) } if len(addrs_to_msign) > 0 { // Multisig (or mixed) transaction ... for i := range multisig_input { if multisig_input[i] == nil { continue } d, er := hex.DecodeString(multisig_input[i].RedeemScript) if er != nil { println("ERROR parsing hex RedeemScript:", er.Error()) continue } ms, er := btc.NewMultiSigFromP2SH(d) if er != nil { println("ERROR parsing bin RedeemScript:", er.Error()) continue } tx.TxIn[i].ScriptSig = ms.Bytes() } fz, _ = zi.Create("multi_" + common.CFG.PayCommandName) fmt.Fprintln(fz, "wallet -raw tx2sign.txt") for k, _ := range addrs_to_msign { fmt.Fprintln(fz, "wallet -msign", k, "-raw ...") } } else { if pay_cmd != "" { fz, _ = zi.Create(common.CFG.PayCommandName) fz.Write([]byte(pay_cmd)) } } // Non-multisig transaction ... fz, _ = zi.Create("tx2sign.txt") fz.Write([]byte(hex.EncodeToString(tx.Serialize()))) zi.Close() w.Header()["Content-Type"] = []string{"application/zip"} w.Write(buf.Bytes()) return } else { err = "Bad request" } error: s := load_template("send_error.html") write_html_head(w, r) s = strings.Replace(s, "<!--ERROR_MSG-->", err, 1) w.Write([]byte(s)) write_html_tail(w) }