diff --git a/accounting/main.go b/accounting/main.go new file mode 100644 index 0000000..72d9624 --- /dev/null +++ b/accounting/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "cwtch.im/zcash2cwtch" + "encoding/hex" + "encoding/json" + "fmt" + "git.openprivacy.ca/openprivacy/libricochet-go/connectivity" + "git.openprivacy.ca/openprivacy/libricochet-go/log" + "io/ioutil" + "sort" + "strings" + "time" +) + +type ZcashConfig struct { + Username string `json: "username"` + Password string `json: "password"` + Onion string `json: "onion"` + ZAddress string `json: "zaddress"` +} + +type Transaction struct { + time time.Time + transaction zcash2cwtch.ZcashTransaction +} + +type timeSlice []Transaction + +func (p timeSlice) Len() int { + return len(p) +} + +func (p timeSlice) Less(i, j int) bool { + return p[i].time.Before(p[j].time) +} + +func (p timeSlice) Swap(i, j int) { + p[i], p[j] = p[j], p[i] +} + +func main() { + log.SetLevel(log.LevelDebug) + configFile, _ := ioutil.ReadFile("accounting.json") + config := ZcashConfig{} + _ = json.Unmarshal([]byte(configFile), &config) + var acn connectivity.ACN + acn, _ = connectivity.StartTor("./", "") + acn.WaitTillBootstrapped() + zc := zcash2cwtch.NewClient(config.Onion, config.Username, config.Password, acn) + transactions, err := zc.ListReceivedTransactionsByAddress(config.ZAddress) + if err != nil { + log.Errorf("Error fetching zcash transactions: %v", err) + } + + sortedTransactions := make(timeSlice, 0) + + for _, transaction := range transactions { + t, err := zc.GetTransaction(transaction.TransactionID) + log.Infof("Transaction: %v, Err %v", transaction, err) + ttime := time.Unix(int64(t.Time), 0) + sortedTransactions = append(sortedTransactions, Transaction{ttime, transaction}) + } + sort.Sort(sortedTransactions) + + // Output a CSV of all transactions + for _, transaction := range sortedTransactions { + memoBytes, _ := hex.DecodeString(transaction.transaction.Memo) + memo := strings.ReplaceAll(string(memoBytes), "\"", "\"\"") + memo = strings.ReplaceAll(string(memoBytes), string([]byte{0x00}), "") + fmt.Printf("%s,%s,%f,%v,\"%s\"\n", transaction.time, transaction.transaction.TransactionID, transaction.transaction.Amount, transaction.transaction.Change, memo) + } + +} diff --git a/transaction.go b/transaction.go index 6634223..e046f74 100644 --- a/transaction.go +++ b/transaction.go @@ -1,5 +1,9 @@ package zcash2cwtch +type Transaction struct { + Time int `json:"time"` +} + type ZcashTransaction struct { TransactionID string `json:"txid"` Amount float64 `json:"amount"` diff --git a/zcash_client.go b/zcash_client.go index bfc6077..ea06b52 100644 --- a/zcash_client.go +++ b/zcash_client.go @@ -17,6 +17,7 @@ type ZcashResult struct { type ZcashClient interface { ListReceivedTransactionsByAddress(string) ([]ZcashTransaction, error) + GetTransaction(string) (Transaction, error) } type zcashOnionClient struct { @@ -41,6 +42,30 @@ func NewClient(onion string, username, password string, acn connectivity.ACN) Zc return zc } +func (zc *zcashOnionClient) GetTransaction(id string) (Transaction, error) { + var jsonStr = []byte(`{"jsonrpc": "1.0", "id":"zcash2cwtch", "method": "gettransaction", "params": ["` + id + `"]}`) + req, err := http.NewRequest("POST", "http://"+zc.onion+".onion:9878", bytes.NewBuffer(jsonStr)) + if err != nil { + return Transaction{}, err + } + req.Header.Add("Authorization", "Basic "+zc.auth) + log.Debugf("Sending request to zcash server %v", req) + resp, err := zc.client.Do(req) + if err != nil { + return Transaction{}, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return Transaction{}, err + } + log.Debugf("Got response from zcash server %s", body) + var transaction Transaction + result := &ZcashResult{Result: &transaction} + err = json.Unmarshal(body, &result) + return transaction, err +} + func (zc *zcashOnionClient) ListReceivedTransactionsByAddress(address string) ([]ZcashTransaction, error) { var jsonStr = []byte(`{"jsonrpc": "1.0", "id":"zcash2cwtch", "method": "z_listreceivedbyaddress", "params": ["` + address + `"]}`) req, err := http.NewRequest("POST", "http://"+zc.onion+".onion:9878", bytes.NewBuffer(jsonStr))