func WaitForOperation(opid string) (string, error) {
	i := 0
	for range time.Tick(time.Second) {
		status, err := checkOperationStatus(opid)
		if err != nil {
			return "", err
		}
		switch status.Status {
		case "failed":
			fmt.Println("operation failed!")
			fmt.Println("reason: ", status.Error.Message)
			return "", fmt.Errorf(status.Error.Message)
		case "executing":
			fmt.Printf("\r                      \r")
			fmt.Print("sending message")
			for j := 0; j <= (i % 4); j++ {
				fmt.Print(".")
			}
		case "success":
			fmt.Println("\nMessage sent successfuly!")
			return status.Result.Txid, nil
		default:
			fmt.Printf("%#v\n", status)
		}
		i++
	}
	return "", nil
}
WaitForOperation polls the operations status until it either fails or
succeeds.
package main
import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"os"
	"strings"
	"time"
	cli "github.com/urfave/cli"
	rpc "github.com/whyrusleeping/zmsg/rpc"
)
var Verbose = false
type Message struct {
	To        string
	Timestamp time.Time
	Content   string
	Val       float64
}
func getMyAddresses() ([]string, error) {
	req := &rpc.Request{
		Method: "z_listaddresses",
	}
	var out struct {
		Result []string
	}
	err := rpc.Do(req, &out)
	if err != nil {
		return nil, err
	}
	return out.Result, nil
}
type TxDesc struct {
	Txid   string
	Amount float64
	Memo   string
}
func parseTypedData(d []byte) (uint64, []byte, error) {
	mtyp, n1 := binary.Uvarint(d)
	mlen, n2 := binary.Uvarint(d[n1:])
	if 1+n1+n2+int(mlen) > 512 {
		return 0, nil, fmt.Errorf("specified message length exceeded limit")
	}
	return mtyp, d[n1+n2 : n1+n2+int(mlen)], nil
}
func getReceivedForAddr(addr string, noconf bool) ([]*Message, error) {
	req := &rpc.Request{
		Method: "z_listreceivedbyaddress",
	}
	params := []interface{}{addr}
	if noconf {
		params = append(params, 0)
	}
	req.Params = params
	var out struct {
		Result []*TxDesc
	}
	err := rpc.Do(req, &out)
	if err != nil {
		return nil, err
	}
	var msgs []*Message
	for _, txd := range out.Result {
		decmemo, err := hex.DecodeString(txd.Memo)
		if err != nil {
			return nil, err
		}
		var content string
		switch {
		case decmemo[0] == 0xff:
			if Verbose {
				fmt.Println(" == warning: memo contained unformatted data")
			}
			continue
		default:
			if Verbose {
				fmt.Printf(" == warning: memo contained data marked with future protocol extension codes (%d)\n", decmemo[0])
			}
			continue
		case decmemo[0] == 0xf5:
			mtyp, buf, err := parseTypedData(decmemo[1:])
			if err != nil {
				return nil, err
			}
			if mtyp != 0xa0 {
				if Verbose {
					fmt.Println(" == warning: can only handle type of 'ascii' (0xa0)")
				}
				continue
			}
			content = string(buf)
		case decmemo[0] <= 0xf4:
			content = string(bytes.TrimRight(decmemo, "\x00"))
		}
		tx, err := getTransaction(txd.Txid)
		if err != nil {
			return nil, err
		}
		msg := &Message{
			Timestamp: time.Unix(tx.Time, 0),
			Val:       txd.Amount,
			Content:   content,
			To:        addr,
		}
		msgs = append(msgs, msg)
	}
	return msgs, nil
}
func CheckMessages(noconf bool) ([]*Message, error) {
	addrs, err := getMyAddresses()
	if err != nil {
		return nil, err
	}
	var allmsgs []*Message
	for _, myaddr := range addrs {
		msgs, err := getReceivedForAddr(myaddr, noconf)
		if err != nil {
			return nil, err
		}
		allmsgs = append(allmsgs, msgs...)
	}
	return allmsgs, nil
}
var ErrNoAddresses = fmt.Errorf("no addresses to send message from! (create one with the zcash-cli)")
func SendMessage(from, to, msg string, msgval float64) (string, error) {
	if from == "" {
		myaddrs, err := getMyAddresses()
		if err != nil {
			return "", err
		}
		if len(myaddrs) == 0 {
			return "", ErrNoAddresses
		}
		from = myaddrs[0]
		fmt.Printf("sending message from %s\n", from)
	}
	req := &rpc.Request{
		Method: "z_sendmany",
		Params: []interface{}{
			from,  
			[]interface{}{
				map[string]interface{}{
					"amount":  msgval,
					"address": to,
					"memo":    hex.EncodeToString([]byte(msg)),
				},
			},
		},
	}
	var out struct {
		Result string
	}
	err := rpc.Do(req, &out)
	if err != nil {
		return "", err
	}
	opid := out.Result
	txid, err := WaitForOperation(opid)
	if err != nil {
		return "", err
	}
	return txid, nil
}
type opStatus struct {
	Id           string
	Status       string
	CreationTime uint64 `json:"creation_time"`
	Error        rpc.Error
	Result       struct {
		Txid string
	}
}
func checkOperationStatus(opid string) (*opStatus, error) {
	req := &rpc.Request{
		Method: "z_getoperationstatus",
		Params: []interface{}{[]string{opid}},
	}
	var out struct {
		Result []*opStatus
	}
	err := rpc.Do(req, &out)
	if err != nil {
		return nil, err
	}
	return out.Result[0], nil
}
type Transaction struct {
	Time          int64
	Confirmations int
}
func getTransaction(txid string) (*Transaction, error) {
	req := &rpc.Request{
		Method: "gettransaction",
		Params: []string{txid},
	}
	var out struct {
		Result Transaction
	}
	err := rpc.Do(req, &out)
	if err != nil {
		return nil, err
	}
	return &out.Result, nil
}