github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/usif/webui/sendtx.go (about)

     1  package webui
     2  
     3  import (
     4  	"fmt"
     5  	"bytes"
     6  	"strings"
     7  	"strconv"
     8  	"net/http"
     9  	"archive/zip"
    10  	"encoding/hex"
    11  	"github.com/piotrnar/gocoin/lib/btc"
    12  	"github.com/piotrnar/gocoin/lib/utxo"
    13  	"github.com/piotrnar/gocoin/client/usif"
    14  	"github.com/piotrnar/gocoin/client/common"
    15  )
    16  
    17  
    18  const (
    19  	AvgSignatureSize = 73
    20  	AvgPublicKeySize = 34 /*Assumine compressed key*/
    21  )
    22  
    23  
    24  type MultisigAddr struct {
    25  	MultiAddress string
    26  	ScriptPubKey string
    27  	KeysRequired, KeysProvided uint
    28  	RedeemScript string
    29  	ListOfAddres []string
    30  }
    31  
    32  func dl_payment(w http.ResponseWriter, r *http.Request) {
    33  	if !ipchecker(r) || !common.GetBool(&common.WalletON)  {
    34  		return
    35  	}
    36  
    37  	var err string
    38  
    39  	if len(r.Form["outcnt"])==1 {
    40  		var thisbal utxo.AllUnspentTx
    41  		var pay_cmd string
    42  		var totalinput, spentsofar uint64
    43  		var change_addr *btc.BtcAddr
    44  
    45  		tx := new(btc.Tx)
    46  		tx.Version = 1
    47  		tx.Lock_time = 0
    48  
    49  		seq, er := strconv.ParseInt(r.Form["tx_seq"][0], 10, 64)
    50  		if er != nil || seq < -2 || seq > 0xffffffff {
    51  			err = "Incorrect Sequence value: " + r.Form["tx_seq"][0]
    52  			goto error
    53  		}
    54  
    55  		outcnt, _ := strconv.ParseUint(r.Form["outcnt"][0], 10, 32)
    56  
    57  		lck := new(usif.OneLock)
    58  		lck.In.Add(1)
    59  		lck.Out.Add(1)
    60  		usif.LocksChan <- lck
    61  		lck.In.Wait()
    62  		defer lck.Out.Done()
    63  
    64  		for i:=1; i<=int(outcnt); i++ {
    65  			is := fmt.Sprint(i)
    66  			if len(r.Form["txout"+is])==1 && r.Form["txout"+is][0]=="on" {
    67  				hash := btc.NewUint256FromString(r.Form["txid"+is][0])
    68  				if hash!=nil {
    69  					vout, er := strconv.ParseUint(r.Form["txvout"+is][0], 10, 32)
    70  					if er==nil {
    71  						var po = btc.TxPrevOut{Hash:hash.Hash, Vout:uint32(vout)}
    72  						if res := common.BlockChain.Unspent.UnspentGet(&po); res != nil {
    73  							addr := btc.NewAddrFromPkScript(res.Pk_script, common.Testnet)
    74  
    75  							unsp := &utxo.OneUnspentTx{TxPrevOut:po, Value:res.Value,
    76  								MinedAt:res.BlockHeight, Coinbase:res.WasCoinbase, BtcAddr:addr}
    77  
    78  							thisbal = append(thisbal, unsp)
    79  
    80  							// Add the input to our tx
    81  							tin := new(btc.TxIn)
    82  							tin.Input = po
    83  							tin.Sequence = uint32(seq)
    84  							tx.TxIn = append(tx.TxIn, tin)
    85  
    86  							// Add the value to total input value
    87  							totalinput += res.Value
    88  
    89  							// If no change specified, use the first input addr as it
    90  							if change_addr == nil {
    91  								change_addr = addr
    92  							}
    93  						}
    94  					}
    95  				}
    96  			}
    97  		}
    98  
    99  		if change_addr == nil {
   100  			// There werte no inputs
   101  			return
   102  		}
   103  
   104  		for i:=1; ; i++ {
   105  			adridx := fmt.Sprint("adr", i)
   106  			btcidx := fmt.Sprint("btc", i)
   107  
   108  			if len(r.Form[adridx])!=1 || len(r.Form[btcidx])!=1 {
   109  				break
   110  			}
   111  
   112  			if len(r.Form[adridx][0])>1 {
   113  				addr, er := btc.NewAddrFromString(r.Form[adridx][0])
   114  				if er == nil {
   115  					am, er := btc.StringToSatoshis(r.Form[btcidx][0])
   116  					if er==nil && am>0 {
   117  						if pay_cmd=="" {
   118  							pay_cmd = "wallet -a=false -useallinputs -send "
   119  						} else {
   120  							pay_cmd += ","
   121  						}
   122  						pay_cmd += addr.String() + "=" + btc.UintToBtc(am)
   123  
   124  						outs, er := btc.NewSpendOutputs(addr, am, common.CFG.Testnet)
   125  						if er != nil {
   126  							err = er.Error()
   127  							goto error
   128  						}
   129  						tx.TxOut = append(tx.TxOut, outs...)
   130  
   131  						spentsofar += am
   132  					} else {
   133  						err = "Incorrect amount (" + r.Form[btcidx][0] + ") for Output #" + fmt.Sprint(i)
   134  						goto error
   135  					}
   136  				} else {
   137  					err = "Incorrect address (" + r.Form[adridx][0] + ") for Output #" + fmt.Sprint(i)
   138  					goto error
   139  				}
   140  			}
   141  		}
   142  
   143  		if pay_cmd=="" {
   144  			err = "No inputs selected"
   145  			goto error
   146  		}
   147  
   148  		pay_cmd += fmt.Sprint(" -seq ", seq)
   149  
   150  		am, er := btc.StringToSatoshis(r.Form["txfee"][0])
   151  		if er != nil {
   152  			err = "Incorrect fee value: " + r.Form["txfee"][0]
   153  			goto error
   154  		}
   155  
   156  		pay_cmd += " -fee " + r.Form["txfee"][0]
   157  		spentsofar += am
   158  
   159  		if len(r.Form["change"][0])>1 {
   160  			addr, er := btc.NewAddrFromString(r.Form["change"][0])
   161  			if er != nil {
   162  				err = "Incorrect change address: " + r.Form["change"][0]
   163  				goto error
   164  			}
   165  			change_addr = addr
   166  		}
   167  		pay_cmd += " -change " + change_addr.String()
   168  
   169  		if totalinput > spentsofar {
   170  			// Add change output
   171  			outs, er := btc.NewSpendOutputs(change_addr, totalinput - spentsofar, common.CFG.Testnet)
   172  			if er != nil {
   173  				err = er.Error()
   174  				goto error
   175  			}
   176  			tx.TxOut = append(tx.TxOut, outs...)
   177  		}
   178  
   179  		buf := new(bytes.Buffer)
   180  		zi := zip.NewWriter(buf)
   181  
   182  		was_tx := make(map [[32]byte] bool, len(thisbal))
   183  		for i := range thisbal {
   184  			if was_tx[thisbal[i].TxPrevOut.Hash] {
   185  				continue
   186  			}
   187  			was_tx[thisbal[i].TxPrevOut.Hash] = true
   188  			txid := btc.NewUint256(thisbal[i].TxPrevOut.Hash[:])
   189  			fz, _ := zi.Create("balance/" + txid.String() + ".tx")
   190  			if dat, er := common.GetRawTx(thisbal[i].MinedAt, txid); er == nil {
   191  				fz.Write(dat)
   192  			} else {
   193  				println(er.Error())
   194  			}
   195  		}
   196  
   197  		fz, _ := zi.Create("balance/unspent.txt")
   198  		for i := range thisbal {
   199  			fmt.Fprintln(fz, thisbal[i].UnspentTextLine())
   200  		}
   201  
   202  		if pay_cmd!="" {
   203  			fz, _ = zi.Create(common.CFG.WebUI.PayCmdName)
   204  			fz.Write([]byte(pay_cmd))
   205  		}
   206  
   207  		// Non-multisig transaction ...
   208  		fz, _ = zi.Create("tx2sign.txt")
   209  		fz.Write([]byte(hex.EncodeToString(tx.Serialize())))
   210  
   211  
   212  		zi.Close()
   213  		w.Header()["Content-Type"] = []string{"application/zip"}
   214  		w.Write(buf.Bytes())
   215  		return
   216  	} else {
   217  		err = "Bad request"
   218  	}
   219  error:
   220  	s := load_template("send_error.html")
   221  	write_html_head(w, r)
   222  	s = strings.Replace(s, "<!--ERROR_MSG-->", err, 1)
   223  	w.Write([]byte(s))
   224  	write_html_tail(w)
   225  }
   226  
   227  
   228  func p_snd(w http.ResponseWriter, r *http.Request) {
   229  	if !ipchecker(r) {
   230  		return
   231  	}
   232  
   233  	if !common.GetBool(&common.WalletON) {
   234  		p_wallet_is_off(w, r)
   235  		return
   236  	}
   237  
   238  	s := load_template("send.html")
   239  
   240  	write_html_head(w, r)
   241  	w.Write([]byte(s))
   242  	write_html_tail(w)
   243  }