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  `