package main import ( "flag" "fmt" "log" "os" "strconv" "strings" "time" "git.nils.zone/nils/prettify" ) type lineEntry struct { BlockHeight int BlockHash string Type string PoolID int Time time.Time Amounts map[string]float64 } func main() { // define flags csvFile := flag.String("csvFile", "", "specifies the path the csv file containing the transaction log") flag.Parse() if *csvFile == "" { log.Fatal("please specify a csvFile using the flag -csvFile") } // start of program b, err := readCSV(*csvFile) if err != nil { log.Fatalf("error occurred when reading csv, error is: %s", err) } entries, err := unmarshalCSV(b) if err != nil { panic(err) } var rewards []lineEntry for i := range entries { if entries[i].Type == "Rewards" { rewards = append(rewards, entries[i]) } } // daily listRewards("2006-01-02", rewards) // monthly listRewards("2006-01", rewards) // yearly listRewards("2006", rewards) } func listRewards(format string, entries []lineEntry) { var str string switch format { case "2006-01-02": str = "daily" case "2006-01": str = "monthly" case "2006": str = "yearly" } rewards := make(map[string]float64) log.Printf("listing %s Rewards", str) for i := range entries { rewardsString := entries[i].Time.Format(format) rewards[rewardsString] += entries[i].Amounts["DFI"] } prettify.Print(rewards) } func readCSV(filename string) ([]byte, error) { b, err := os.ReadFile(filename) if err != nil { return nil, err } return b, nil } func unmarshalCSV(b []byte) ([]lineEntry, error) { // output variable var e []lineEntry // read all lines and do magic on each line lines := strings.Split(string(b), "\n") // for i := range lines { for i := 1; i < len(lines); i++ { // create variable for current line var l lineEntry l.Amounts = make(map[string]float64) // Remove " from lines line := strings.ReplaceAll(lines[i], `"`, ``) // split line by comma entries := strings.Split(line, ",") // convert blockHeight to int height, err := strconv.Atoi(entries[0]) if err != nil { return nil, fmt.Errorf("can't convert blockHeight in line %d to int, error is: %s", i+1, err) } // get time from CSV dateTime, err := time.Parse("02/01/2006 / 03:04 pm", entries[2]) if err != nil { return nil, fmt.Errorf("can't convert time in line %d to time.time, error is: %s", i+1, err) } // convert poolID to int if entries[5] == "" { // empty row entries[5] = "0" } poolID, err := strconv.Atoi(entries[5]) if err != nil { return nil, fmt.Errorf("can't convert poolID in line %d to int, error is: %s", i+1, err) } // Split for amount and currency amounts := strings.Split(strings.Join(entries[6:], " "), " ") for i := range amounts { // Split amounts and currency ac := strings.Split(amounts[i], "@") amountString := ac[0] currency := ac[1] // Parse string to float amount, err := strconv.ParseFloat(amountString, 64) if err != nil { return nil, err } // put rewards into map l.Amounts[currency] = amount } // fill l with values l.BlockHeight = height // entries[0] l.BlockHash = entries[1] // entries[1] l.Type = entries[4] // entries[2] l.PoolID = poolID // entries[3] l.Time = dateTime e = append(e, l) } return e, nil }