func (c *Client) Memo(txid types.TransactionID) (memo []byte, err error) {
	resp, err := http.Get(fmt.Sprintf("http://%v/memos/%v", c.addr, txid.String()))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	data, _ := ioutil.ReadAll(resp.Body)
	if resp.StatusCode != 200 {
		return nil, errors.New(string(data))
	}
	return data, nil
}
Memo retrieves the memo for a transaction.
package walrus
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"sync"
	"go.sia.tech/siad/crypto"
	"go.sia.tech/siad/types"
	"lukechampine.com/frand"
	"lukechampine.com/us/ed25519hash"
	"lukechampine.com/us/renter/proto"
	"lukechampine.com/us/wallet"
)
type Client struct {
	addr string
}
func (c *Client) req(method string, route string, data, resp interface{}) error {
	var body io.Reader
	if data != nil {
		js, _ := json.Marshal(data)
		body = bytes.NewReader(js)
	}
	req, err := http.NewRequest(method, fmt.Sprintf("%v%v", c.addr, route), body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", "application/json")
	r, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer io.Copy(ioutil.Discard, r.Body)
	defer r.Body.Close()
	if r.StatusCode != 200 {
		err, _ := ioutil.ReadAll(r.Body)
		return errors.New(string(err))
	}
	if resp == nil {
		return nil
	}
	return json.NewDecoder(r.Body).Decode(resp)
}
func (c *Client) get(route string, r interface{}) error     { return c.req("GET", route, nil, r) }
func (c *Client) post(route string, d, r interface{}) error { return c.req("POST", route, d, r) }
func (c *Client) put(route string, d interface{}) error     { return c.req("PUT", route, d, nil) }
func (c *Client) delete(route string) error                 { return c.req("DELETE", route, nil, nil) }
func (c *Client) Addresses() (addrs []types.UnlockHash, err error) {
	err = c.get("/addresses", &addrs)
	return
}
func (c *Client) AddressInfo(addr types.UnlockHash) (info wallet.SeedAddressInfo, err error) {
	err = c.get("/addresses/"+addr.String(), &info)
	return
}
func (c *Client) Balance(limbo bool) (bal types.Currency, err error) {
	err = c.get("/balance?limbo="+strconv.FormatBool(limbo), &bal)
	return
}
func (c *Client) BatchAddresses(addrs []types.UnlockHash) (infos map[types.UnlockHash]wallet.SeedAddressInfo, err error) {
	var m responseBatchqueryAddresses
	err = c.post("/batchquery/addresses", addrs, &m)
	return m, err
}
func (c *Client) BatchTransactions(ids []types.TransactionID) (txns map[types.TransactionID]ResponseTransactionsID, err error) {
	var m responseBatchqueryTransactions
	err = c.post("/batchquery/transactions", ids, &m)
	return m, err
}
func (c *Client) Broadcast(txnSet []types.Transaction) error {
	return c.post("/broadcast", txnSet, nil)
}
func (c *Client) BlockRewards(max int) (rewards []wallet.BlockReward, err error) {
	err = c.get("/blockrewards?max="+strconv.Itoa(max), &rewards)
	return
}
func (c *Client) ConsensusInfo() (info ResponseConsensus, err error) {
	err = c.get("/consensus", &info)
	return
}
func (c *Client) RecommendedFee() (fee types.Currency, err error) {
	err = c.get("/fee", &fee)
	return
}
func (c *Client) FileContracts(max int) (contracts []wallet.FileContract, err error) {
	err = c.get("/filecontracts?max="+strconv.Itoa(max), &contracts)
	return
}
func (c *Client) FileContractHistory(id types.FileContractID) (history []wallet.FileContract, err error) {
	err = c.get("/filecontracts/"+id.String(), &history)
	return
}
func (c *Client) LimboTransactions() (txns []wallet.LimboTransaction, err error) {
	err = c.get("/limbo", &txns)
	return
}
func (c *Client) AddToLimbo(txn types.Transaction) (err error) {
	return c.put("/limbo/"+txn.ID().String(), txn)
}
func (c *Client) RemoveFromLimbo(txid types.TransactionID) (err error) {
	return c.delete("/limbo/" + txid.String())
}