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 }