github.com/decred/politeia@v1.4.0/politeiawww/cmd/pictl/cmdsendfaucettx.go (about) 1 // Copyright (c) 2017-2021 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "context" 9 "encoding/json" 10 "errors" 11 "fmt" 12 "io" 13 "net/http" 14 "net/url" 15 "strings" 16 17 "github.com/decred/dcrd/chaincfg/v3" 18 "github.com/decred/dcrd/dcrutil/v3" 19 "github.com/decred/politeia/util" 20 ) 21 22 // cmdSendFaucetTx uses the Decred testnet faucet to send the specified amount 23 // of DCR (in atoms) to the specified address. 24 type cmdSendFaucetTx struct { 25 Args struct { 26 Address string `positional-arg-name:"address" required:"true"` 27 Amount string `positional-arg-name:"amount" required:"true"` 28 OverrideToken string `positional-arg-name:"overridetoken"` 29 } `positional-args:"true"` 30 } 31 32 // Execute executes the cmdSendFaucetTx command. 33 // 34 // This function satisfies the go-flags Commander interface. 35 func (c *cmdSendFaucetTx) Execute(args []string) error { 36 address := c.Args.Address 37 amount := c.Args.Amount 38 39 txID, err := sendFaucetTx(cfg.FaucetHost, address, 40 amount, c.Args.OverrideToken) 41 if err != nil { 42 return err 43 } 44 45 printf("Paid %v DCR to %v with tx %v\n", amount, address, txID) 46 47 return nil 48 } 49 50 // faucetReply contains the reply from the DCR testnet faucet. The reply will 51 // be included in the "x-json-reply" header. 52 type faucetReply struct { 53 TxID string `json:"txid"` 54 Error string `json:"error"` 55 } 56 57 // sendFaucetTx sends a request to the DCR testnet faucet that asks it to send 58 // DCR from the faucet to the provided address. 59 func sendFaucetTx(faucetURL string, address, amountInDCR, overridetoken string) (string, error) { 60 // Verify address is valid 61 _, err := dcrutil.DecodeAddress(address, chaincfg.TestNet3Params()) 62 if err != nil { 63 return "", err 64 } 65 66 // Setup request 67 form := url.Values{} 68 form.Add("address", address) 69 form.Add("amount", amountInDCR) 70 form.Add("overridetoken", overridetoken) 71 72 req, err := http.NewRequestWithContext(context.Background(), 73 http.MethodPost, faucetURL, strings.NewReader(form.Encode())) 74 if err != nil { 75 return "", err 76 } 77 req.PostForm = form 78 req.Header.Add("Content-Type", "application/x-www-form-urlencoded") 79 80 // Send request 81 client, err := util.NewHTTPClient(false, "") 82 if err != nil { 83 return "", err 84 } 85 resp, err := client.Do(req) 86 if err != nil { 87 return "", err 88 } 89 defer resp.Body.Close() 90 91 // Handle reply 92 if resp.StatusCode != http.StatusOK { 93 body, err := io.ReadAll(resp.Body) 94 if err != nil { 95 return "", fmt.Errorf("testnet faucet error: %v %v %v", 96 resp.StatusCode, faucetURL, err) 97 } 98 return "", fmt.Errorf("testnet faucet error: %v %v %s", 99 resp.StatusCode, faucetURL, body) 100 } 101 102 // The reply will be in the JSON header 103 reply := resp.Header.Get("X-Json-Reply") 104 if reply == "" { 105 return "", fmt.Errorf("empty JSON reply header") 106 } 107 108 var fr faucetReply 109 err = json.Unmarshal([]byte(reply), &fr) 110 if err != nil { 111 return "", err 112 } 113 if fr.Error != "" { 114 return "", errors.New(fr.Error) 115 } 116 117 return fr.TxID, nil 118 } 119 120 // sendFaucetTxHelpMsg is the printed to stdout by the help command. 121 const sendFaucetTxHelpMsg = `sendfaucettx "address" amount "overridetoken" 122 123 Use the Decred testnet faucet to send DCR to an address. 124 125 Arguments: 126 1. address (string, required) Receiving address 127 2. amount (string, required) Amount to send in DCR. Supported input 128 variations: "1", ".1", "0.1". 129 3. overridetoken (string, optional) Override token for testnet faucet 130 `