diff --git a/api.go b/api.go index ea326c0..91e71ce 100644 --- a/api.go +++ b/api.go @@ -11,6 +11,8 @@ type Method string const ( GetTransaction Method = "gettransaction" + ZGetTotalBalance = "z_gettotalbalance" + ZListAddresses = "z_listaddresses" ZListReceivedByAddress = "z_listreceivedbyaddress" ZSendMany = "z_sendmany" ZValidateAddress = "z_validateaddress" @@ -46,6 +48,23 @@ func NewZValidateAddress(address string) []byte { return data } +// NewZListAddresses constructs a properly formatted z_listaddresses request +func NewZListAddresses() []byte { + request := setupZcashRequest() + request.Method = ZListAddresses + data, _ := json.Marshal(request) + return data +} + +// NewZGetTotalBalance constructs a properly formatted z_gettotalbalance request +func NewZGetTotalBalance(minConfirmations int) []byte { + request := setupZcashRequest() + request.Method = ZGetTotalBalance + request.Params = append(request.Params, minConfirmations) + data, _ := json.Marshal(request) + return data +} + // NewZListReceivedByAddress constructs a properly formatted z_listreceivedbyaddress request func NewZListReceivedByAddress(fromAddress string) []byte { request := setupZcashRequest() @@ -90,6 +109,9 @@ type ZcashTransaction struct { Memo Hex `json:"memo"` Change bool `json:"change"` OutIndex int `json:"outindex"` + + // The following parameters are not provided by the zcash node + Address string `json:"address"` } // ZcashResult represents the result of a zcash operation. Result can be any one of a number of defined types. @@ -106,3 +128,10 @@ type ZValidateAddressResponse struct { Diversifier Hex `json:"diversifier"` DiversifiedTransmissionKey Hex `json:"diversifiedtransmissionkey"` } + +// ZGetTotalBalanceResponse encapsulates the result returned from a z_gettotalbalance request +type ZGetTotalBalanceResponse struct { + Transparent string `json:"transparent"` + Private string `json:"private"` + Total string `json:"total"` +} diff --git a/testing/zcash_client_integration_test.go b/testing/zcash_client_integration_test.go index 954ee24..9609f29 100644 --- a/testing/zcash_client_integration_test.go +++ b/testing/zcash_client_integration_test.go @@ -1,9 +1,9 @@ package zcash2cwtch import ( - "cwtch.im/zcash2cwtch" "encoding/json" "git.openprivacy.ca/openprivacy/libricochet-go/log" + "git.openprivacy.ca/openprivacy/zcashrpc" "io/ioutil" "testing" ) @@ -13,6 +13,52 @@ type ZcashConfig struct { Password string `json:"password"` } +func TestGetTotalBalance(t *testing.T) { + log.SetLevel(log.LevelDebug) + configFile, _ := ioutil.ReadFile("config.json") + config := ZcashConfig{} + _ = json.Unmarshal(configFile, &config) + + zc := zcashrpc.NewLocalClient(config.Username, config.Password) + result, err := zc.GetTotalBalance(1) + t.Logf("Result: %v %v", result, err) + if err != nil { + t.Errorf("Failed to get total balance: %v %v", result, err) + } +} + +func TestListTransactions(t *testing.T) { + log.SetLevel(log.LevelDebug) + configFile, _ := ioutil.ReadFile("config.json") + config := ZcashConfig{} + _ = json.Unmarshal(configFile, &config) + + zc := zcashrpc.NewLocalClient(config.Username, config.Password) + result, err := zc.ListReceivedTransactionsByAddress("zs1pjv7eneq9jshw0eyywpruv2cetl74sh84ymdnyv4c4vg8vl5k2qmlv0n7ye77g49lhqkg75v52f") + t.Logf("Result: %v %v", result, err) + if len(result) == 0 { + t.Errorf("Failed to list transactions") + } else { + for _, transaction := range result { + t.Logf("Transaction: %v", transaction) + } + } +} + +func TestListAddresses(t *testing.T) { + log.SetLevel(log.LevelDebug) + configFile, _ := ioutil.ReadFile("config.json") + config := ZcashConfig{} + _ = json.Unmarshal(configFile, &config) + + zc := zcashrpc.NewLocalClient(config.Username, config.Password) + result, err := zc.ListAddresses() + t.Logf("Result: %v %v", result, err) + if len(result) == 0 { + t.Errorf("Failed to list zaddresses") + } +} + func TestNewZValidateAddress(t *testing.T) { log.SetLevel(log.LevelDebug) configFile, _ := ioutil.ReadFile("config.json") diff --git a/zcash_client.go b/zcash_client.go index 1300f29..a3054b4 100644 --- a/zcash_client.go +++ b/zcash_client.go @@ -9,12 +9,15 @@ import ( "io/ioutil" "net" "net/http" + "strconv" ) // ZcashClient defines an interface for any zcash client to present. type ZcashClient interface { - ListReceivedTransactionsByAddress(string) ([]ZcashTransaction, error) + GetTotalBalance(minConfirmations int) (float64, error) GetTransaction(string) (Transaction, error) + ListAddresses() ([]string, error) + ListReceivedTransactionsByAddress(string) ([]ZcashTransaction, error) SendOne(string, string, string, float64) ([]byte, error) ValidateAddress(address string) (ZValidateAddressResponse, error) } @@ -57,6 +60,17 @@ func NewOnionClient(onion string, username, password string, acn connectivity.AC return zc } +// Return the total value of funds stored in the node’s wallet. Set the minimum number of confirmations a private or transparent transaction must have in order to be included in the balance. Use 0 to count unconfirmed transactions. +func (zc *zcashClient) GetTotalBalance(minConfirmations int) (float64, error) { + body, err := zc.sendRequest(NewZGetTotalBalance(minConfirmations)) + var totalBalance ZGetTotalBalanceResponse + if err == nil { + result := &ZcashResult{Result: &totalBalance} + err = json.Unmarshal(body, &result) + } + return strconv.ParseFloat(totalBalance.Private, 64) +} + // GetTransaction returns a specific transaction given an id func (zc *zcashClient) GetTransaction(id string) (Transaction, error) { body, err := zc.sendRequest(NewGetTransaction(id)) @@ -68,6 +82,17 @@ func (zc *zcashClient) GetTransaction(id string) (Transaction, error) { return transaction, err } +// Returns a list of all the zaddrs in this node’s wallet for which you have a spending key. +func (zc *zcashClient) ListAddresses() ([]string, error) { + body, err := zc.sendRequest(NewZListAddresses()) + var addresses []string + if err == nil { + result := &ZcashResult{Result: &addresses} + err = json.Unmarshal(body, &result) + } + return addresses, err +} + // ListReceivedTransactionsByAddress returns all the transactions received by a given zcash address func (zc *zcashClient) ListReceivedTransactionsByAddress(address string) ([]ZcashTransaction, error) { body, err := zc.sendRequest(NewZListReceivedByAddress(address)) @@ -76,6 +101,9 @@ func (zc *zcashClient) ListReceivedTransactionsByAddress(address string) ([]Zcas result := &ZcashResult{Result: &transactions} err = json.Unmarshal(body, &result) } + for i := range transactions { + transactions[i].Address = address + } return transactions, err }