From 918e49cba94fe5637d9a777d465ad7cde7b010f4 Mon Sep 17 00:00:00 2001 From: pharr117 Date: Sat, 20 Jan 2024 02:07:29 -0500 Subject: [PATCH 1/5] Fix fee DB statement to preload Tx.Block --- db/search.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/search.go b/db/search.go index 450a56a..352b4bd 100644 --- a/db/search.go +++ b/db/search.go @@ -23,7 +23,7 @@ func GetTaxableTransactions(address string, db *gorm.DB) ([]TaxableTransaction, func GetTaxableFees(address string, db *gorm.DB) ([]Fee, error) { var fees []Fee result := db.Joins("JOIN addresses ON addresses.id = fees.payer_address_id"). - Where("addresses.address = ?", address).Preload("PayerAddress").Preload("Denomination").Preload("Tx").Find(&fees) + Where("addresses.address = ?", address).Preload("PayerAddress").Preload("Denomination").Preload("Tx").Preload("Tx.Block").Find(&fees) return fees, result.Error } From 1183fabcb8b5a96157d654d263fec413a692935b Mon Sep 17 00:00:00 2001 From: pharr117 Date: Sat, 20 Jan 2024 22:21:02 -0500 Subject: [PATCH 2/5] Add fee additions for cointracker to add fees to all TXs instead of separate row sends --- csv/parsers/cointracker/cointracker.go | 111 ++++++++++++------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/csv/parsers/cointracker/cointracker.go b/csv/parsers/cointracker/cointracker.go index b18fb94..6ac5237 100644 --- a/csv/parsers/cointracker/cointracker.go +++ b/csv/parsers/cointracker/cointracker.go @@ -14,6 +14,7 @@ import ( "github.com/DefiantLabs/cosmos-tax-cli/db" "github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/gamm" "github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/poolmanager" + "github.com/DefiantLabs/cosmos-tax-cli/util" ) func (p *Parser) TimeLayout() string { @@ -24,6 +25,13 @@ func (p *Parser) ProcessTaxableTx(address string, taxableTxs []db.TaxableTransac // Build a map, so we know which TX go with which messages txMap := parsers.MakeTXMap(taxableTxs) + feesWithoutTx := []db.Fee{} + for _, fee := range taxableFees { + if _, ok := txMap[fee.Tx.ID]; !ok { + feesWithoutTx = append(feesWithoutTx, fee) + } + } + // Pull messages out of txMap that must be grouped together parsers.SeparateParsingGroups(txMap, p.ParsingGroups) @@ -31,9 +39,14 @@ func (p *Parser) ProcessTaxableTx(address string, taxableTxs []db.TaxableTransac for _, txGroup := range txMap { // All messages have been removed into a parsing group if len(txGroup) != 0 { + var fees []db.Fee + + if len(txGroup) > 0 { + fees = txGroup[0].Message.Tx.Fees + } // For the current transaction group, generate the rows for the CSV. // Usually (but not always) a transaction will only have a single row in the CSV. - txRows, err := ParseTx(address, txGroup) + txRows, err := ParseTx(address, txGroup, fees) if err != nil { return err } @@ -51,15 +64,15 @@ func (p *Parser) ProcessTaxableTx(address string, taxableTxs []db.TaxableTransac } } - // Handle fees on all taxableTxs at once, we don't do this in the regular parser or in the parsing groups - // This requires HandleFees to process the fees into unique mappings of tx -> fees (since we gather Taxable Messages in the taxableTxs) - // If we move it into the ParseTx function or into the ParseGroup function, we may be able to reduce the logic in the HandleFees func - feeRows, err := HandleFees(address, taxableTxs, taxableFees) - if err != nil { - return err - } + for _, fee := range feesWithoutTx { + row := Row{} + err := row.ParseFee(fee.Tx, fee) + if err != nil { + return err + } - p.Rows = append(p.Rows, feeRows...) + p.Rows = append(p.Rows, row) + } return nil } @@ -157,52 +170,6 @@ func (p Parser) GetHeaders() []string { return []string{"Date", "Received Quantity", "Received Currency", "Sent Quantity", "Sent Currency", "Fee Amount", "Fee Currency", "Tag"} } -// HandleFees: -// If the transaction lists the same amount of fees as there are rows in the CSV, -// then we spread the fees out one per row. Otherwise we add a line for the fees, -// where each fee has a separate line. -func HandleFees(address string, events []db.TaxableTransaction, allFees []db.Fee) (rows []Row, err error) { - // No events -- This address didn't pay any fees - if len(events) == 0 && len(allFees) == 0 { - return rows, nil - } - - // We need to gather all unique fees, but we are receiving Messages not Txes - // Make a map from TX hash to fees array to keep unique - txToFeesMap := make(map[uint][]db.Fee) - txIdsToTx := make(map[uint]db.Tx) - for _, event := range events { - txID := event.Message.Tx.ID - feeStore := event.Message.Tx.Fees - txToFeesMap[txID] = feeStore - txIdsToTx[txID] = event.Message.Tx - } - - // Due to the way we are parsing, we may have fees for TX that we don't have events for - for _, fee := range allFees { - txID := fee.Tx.ID - if _, ok := txToFeesMap[txID]; !ok { - txToFeesMap[txID] = []db.Fee{fee} - txIdsToTx[txID] = fee.Tx - } - } - - for id, txFees := range txToFeesMap { - for _, fee := range txFees { - if fee.PayerAddress.Address == address { - newRow := Row{} - err = newRow.ParseFee(txIdsToTx[id], fee) - if err != nil { - return nil, err - } - rows = append(rows, newRow) - } - } - } - - return rows, nil -} - // ParseEvent: Parse the potentially taxable event func ParseEvent(event db.TaxableEvent) (rows []Row, err error) { if event.Source == db.OsmosisRewardDistribution { @@ -220,7 +187,8 @@ func ParseEvent(event db.TaxableEvent) (rows []Row, err error) { // ParseTx: Parse the potentially taxable TX and Messages // This function is used for parsing a single TX that will not need to relate to any others // Use TX Parsing Groups to parse txes as a group -func ParseTx(address string, events []db.TaxableTransaction) (rows []parsers.CsvRow, err error) { +func ParseTx(address string, events []db.TaxableTransaction, fees []db.Fee) (rows []parsers.CsvRow, err error) { + currFeeIndex := 0 for _, event := range events { var newRow Row var err error @@ -273,8 +241,39 @@ func ParseTx(address string, events []db.TaxableTransaction) (rows []parsers.Csv continue } + // Attach fees to the transaction events + if currFeeIndex < len(fees) { + if fees[currFeeIndex].PayerAddress.Address == address { + conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(fees[currFeeIndex].Amount), fees[currFeeIndex].Denomination) + if err != nil { + config.Log.Errorf("error parsing fee: %v", err) + } else { + newRow.FeeAmount = conversionAmount.String() + newRow.FeeCurrency = conversionSymbol + } + } + currFeeIndex++ + } + rows = append(rows, newRow) } + + // Check if fees have all been processed based on last processed index + if currFeeIndex < len(fees) { + // Create empty row for the fees that weren't processed + for i := currFeeIndex; i < len(fees); i++ { + if fees[i].PayerAddress.Address == address { + newRow := Row{} + err = newRow.ParseFee(fees[i].Tx, fees[i]) + if err != nil { + config.Log.Errorf("error parsing fee: %v", err) + continue + } + rows = append(rows, newRow) + } + } + } + return rows, nil } From cc94ce5bc1328b9fd74dd88dd9656bc7cc4305a8 Mon Sep 17 00:00:00 2001 From: pharr117 Date: Sat, 20 Jan 2024 22:47:40 -0500 Subject: [PATCH 3/5] Add personal parsers for IBC Ack and Recv message types to handle missing denoms --- csv/parsers/accointing/accointing.go | 62 ++++++++++++++++- csv/parsers/cointracker/cointracker.go | 55 +++++++++++++++- .../cryptotaxcalculator.go | 66 ++++++++++++++++++- csv/parsers/koinly/koinly.go | 63 +++++++++++++++++- 4 files changed, 238 insertions(+), 8 deletions(-) diff --git a/csv/parsers/accointing/accointing.go b/csv/parsers/accointing/accointing.go index 42870aa..7f2b712 100644 --- a/csv/parsers/accointing/accointing.go +++ b/csv/parsers/accointing/accointing.go @@ -15,6 +15,7 @@ import ( "github.com/DefiantLabs/cosmos-tax-cli/db" "github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/gamm" "github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/poolmanager" + "github.com/DefiantLabs/cosmos-tax-cli/util" ) func (p *Parser) TimeLayout() string { @@ -265,9 +266,9 @@ func ParseTx(address string, events []db.TaxableTransaction) (rows []parsers.Csv case ibc.MsgTransfer: newRow, err = ParseMsgTransfer(address, event) case ibc.MsgAcknowledgement: - newRow, err = ParseMsgTransfer(address, event) + newRow, err = ParseMsgAcknowledgement(address, event) case ibc.MsgRecvPacket: - newRow, err = ParseMsgTransfer(address, event) + newRow, err = ParseMsgRecvPacket(address, event) case poolmanager.MsgSplitRouteSwapExactAmountIn, poolmanager.MsgSwapExactAmountIn, poolmanager.MsgSwapExactAmountOut: newRow, err = ParsePoolManagerSwap(event) default: @@ -384,6 +385,63 @@ func ParseMsgTransfer(address string, event db.TaxableTransaction) (Row, error) return *row, err } +func ParseMsgAcknowledgement(address string, event db.TaxableTransaction) (Row, error) { + row := &Row{} + + denomToUse := event.DenominationSent + amountToUse := event.AmountSent + + conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) + + if err != nil { + config.Log.Error("Error with ParseMsgAcknowledgement.", err) + return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: deposit)", row.OperationID) + } + + if event.ReceiverAddress.Address == address { + row.InBuyAmount = conversionAmount.Text('f', -1) + row.InBuyAsset = conversionSymbol + row.TransactionType = Deposit + } else if event.SenderAddress.Address == address { // withdrawal + row.OutSellAmount = conversionAmount.Text('f', -1) + row.OutSellAsset = conversionSymbol + row.TransactionType = Withdraw + } + + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) + row.OperationID = event.Message.Tx.Hash + + return *row, err +} + +func ParseMsgRecvPacket(address string, event db.TaxableTransaction) (Row, error) { + row := &Row{} + + denomToUse := event.DenominationReceived + amountToUse := event.AmountReceived + + conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) + + if err != nil { + config.Log.Error("Error with ParseMsgRecvPacket.", err) + return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: deposit)", row.OperationID) + } + + if event.ReceiverAddress.Address == address { + row.InBuyAmount = conversionAmount.Text('f', -1) + row.InBuyAsset = conversionSymbol + row.TransactionType = Deposit + } else if event.SenderAddress.Address == address { // withdrawal + row.OutSellAmount = conversionAmount.Text('f', -1) + row.OutSellAsset = conversionSymbol + row.TransactionType = Withdraw + } + + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) + row.OperationID = event.Message.Tx.Hash + return *row, err +} + func ParseOsmosisReward(event db.TaxableEvent) (Row, error) { row := &Row{} err := row.EventParseBasic(event) diff --git a/csv/parsers/cointracker/cointracker.go b/csv/parsers/cointracker/cointracker.go index 6ac5237..e71218f 100644 --- a/csv/parsers/cointracker/cointracker.go +++ b/csv/parsers/cointracker/cointracker.go @@ -1,6 +1,7 @@ package cointracker import ( + "fmt" "sort" "time" @@ -226,9 +227,9 @@ func ParseTx(address string, events []db.TaxableTransaction, fees []db.Fee) (row case ibc.MsgTransfer: newRow, err = ParseMsgTransfer(address, event) case ibc.MsgAcknowledgement: - newRow, err = ParseMsgTransfer(address, event) + newRow, err = ParseMsgAcknowledgement(address, event) case ibc.MsgRecvPacket: - newRow, err = ParseMsgTransfer(address, event) + newRow, err = ParseMsgRecvPacket(address, event) case poolmanager.MsgSplitRouteSwapExactAmountIn, poolmanager.MsgSwapExactAmountIn, poolmanager.MsgSwapExactAmountOut: newRow, err = ParsePoolManagerSwap(event) default: @@ -358,6 +359,56 @@ func ParseMsgTransfer(address string, event db.TaxableTransaction) (Row, error) return *row, err } +func ParseMsgAcknowledgement(address string, event db.TaxableTransaction) (Row, error) { + row := &Row{} + + denomToUse := event.DenominationSent + amountToUse := event.AmountSent + + conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) + + if err != nil { + config.Log.Error("Error with ParseMsgAcknowledgement.", err) + return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: withdrawal)", event.Message.Tx.Hash) + } + + if event.ReceiverAddress.Address == address { + row.ReceivedAmount = conversionAmount.Text('f', -1) + row.ReceivedCurrency = conversionSymbol + } else if event.SenderAddress.Address == address { // withdrawal + row.SentAmount = conversionAmount.Text('f', -1) + row.SentCurrency = conversionSymbol + } + + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) + return *row, err +} + +func ParseMsgRecvPacket(address string, event db.TaxableTransaction) (Row, error) { + row := &Row{} + + denomToUse := event.DenominationReceived + amountToUse := event.AmountReceived + + conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) + + if err != nil { + config.Log.Error("Error with ParseMsgAcknowledgement.", err) + return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: withdrawal)", event.Message.Tx.Hash) + } + + if event.ReceiverAddress.Address == address { + row.ReceivedAmount = conversionAmount.Text('f', -1) + row.ReceivedCurrency = conversionSymbol + } else if event.SenderAddress.Address == address { // withdrawal + row.SentAmount = conversionAmount.Text('f', -1) + row.SentCurrency = conversionSymbol + } + + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) + return *row, err +} + func ParseMsgSubmitProposal(address string, event db.TaxableTransaction) (Row, error) { row := &Row{} err := row.ParseBasic(address, event) diff --git a/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go b/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go index 792b8d6..f2e7a4c 100644 --- a/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go +++ b/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go @@ -1,6 +1,7 @@ package cryptotaxcalculator import ( + "fmt" "sort" "time" @@ -14,6 +15,7 @@ import ( "github.com/DefiantLabs/cosmos-tax-cli/db" "github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/gamm" "github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/poolmanager" + "github.com/DefiantLabs/cosmos-tax-cli/util" ) func (p *Parser) TimeLayout() string { @@ -208,9 +210,9 @@ func ParseTx(address string, events []db.TaxableTransaction) (rows []parsers.Csv case ibc.MsgTransfer: newRow, err = ParseMsgTransfer(address, event) case ibc.MsgAcknowledgement: - newRow, err = ParseMsgTransfer(address, event) + newRow, err = ParseMsgAcknowledgement(address, event) case ibc.MsgRecvPacket: - newRow, err = ParseMsgTransfer(address, event) + newRow, err = ParseMsgRecvPacket(address, event) case poolmanager.MsgSplitRouteSwapExactAmountIn, poolmanager.MsgSwapExactAmountIn, poolmanager.MsgSwapExactAmountOut: newRow, err = ParsePoolManagerSwap(address, event) default: @@ -307,6 +309,66 @@ func ParseMsgTransfer(address string, event db.TaxableTransaction) (Row, error) return *row, err } +func ParseMsgAcknowledgement(address string, event db.TaxableTransaction) (Row, error) { + row := &Row{} + + denomToUse := event.DenominationSent + amountToUse := event.AmountSent + + conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) + + if err != nil { + config.Log.Error("Error with ParseMsgAcknowledgement.", err) + return *row, fmt.Errorf("cannot parse denom units for TX %s", event.Message.Tx.Hash) + } + + row.BaseAmount = conversionAmount.Text('f', -1) + row.BaseCurrency = conversionSymbol + + if event.ReceiverAddress.Address == address { + row.Type = Buy + } else if event.SenderAddress.Address == address { // withdrawal + row.Type = Sell + } + + row.From = event.SenderAddress.Address + row.To = event.ReceiverAddress.Address + + row.Date = event.Message.Tx.Block.TimeStamp + row.ID = event.Message.Tx.Hash + return *row, err +} + +func ParseMsgRecvPacket(address string, event db.TaxableTransaction) (Row, error) { + row := &Row{} + + denomToUse := event.DenominationReceived + amountToUse := event.AmountReceived + + conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) + + if err != nil { + config.Log.Error("Error with ParseMsgAcknowledgement.", err) + return *row, fmt.Errorf("cannot parse denom units for TX %s", event.Message.Tx.Hash) + } + + row.BaseAmount = conversionAmount.Text('f', -1) + row.BaseCurrency = conversionSymbol + + if event.ReceiverAddress.Address == address { + row.Type = Buy + } else if event.SenderAddress.Address == address { // withdrawal + row.Type = Sell + } + + row.From = event.SenderAddress.Address + row.To = event.ReceiverAddress.Address + + row.Date = event.Message.Tx.Block.TimeStamp + row.ID = event.Message.Tx.Hash + return *row, err +} + func (p *Parser) InitializeParsingGroups() { p.ParsingGroups = append(p.ParsingGroups, parsers.GetOsmosisTxParsingGroups()...) } diff --git a/csv/parsers/koinly/koinly.go b/csv/parsers/koinly/koinly.go index c02f22d..3a73fc4 100644 --- a/csv/parsers/koinly/koinly.go +++ b/csv/parsers/koinly/koinly.go @@ -17,6 +17,7 @@ import ( "github.com/DefiantLabs/cosmos-tax-cli/db" "github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/gamm" "github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/poolmanager" + "github.com/DefiantLabs/cosmos-tax-cli/util" ) var unsupportedCoins = []string{ @@ -332,9 +333,9 @@ func ParseTx(address string, events []db.TaxableTransaction) (rows []parsers.Csv case gov.MsgDeposit, gov.MsgDepositV1: newRow, err = ParseMsgDeposit(address, event) case ibc.MsgAcknowledgement: - newRow, err = ParseMsgTransfer(address, event) + newRow, err = ParseMsgAcknowledgement(address, event) case ibc.MsgRecvPacket: - newRow, err = ParseMsgTransfer(address, event) + newRow, err = ParseMsgRecvPacket(address, event) case poolmanager.MsgSplitRouteSwapExactAmountIn, poolmanager.MsgSwapExactAmountIn, poolmanager.MsgSwapExactAmountOut: newRow, err = ParsePoolManagerSwap(event) default: @@ -433,6 +434,64 @@ func ParseMsgTransfer(address string, event db.TaxableTransaction) (Row, error) return *row, err } +func ParseMsgAcknowledgement(address string, event db.TaxableTransaction) (Row, error) { + row := &Row{} + + denomToUse := event.DenominationSent + amountToUse := event.AmountSent + + conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) + + if err != nil { + config.Log.Error("Error with ParseMsgRecvPacket.", err) + return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: deposit)", event.Message.Tx.Hash) + } + + if event.ReceiverAddress.Address == address { + row.ReceivedAmount = conversionAmount.Text('f', -1) + row.ReceivedCurrency = conversionSymbol + row.Label = Income + } else if event.SenderAddress.Address == address { // withdrawal + row.SentAmount = conversionAmount.Text('f', -1) + row.SentCurrency = conversionSymbol + row.Label = Cost + } + + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) + row.TxHash = event.Message.Tx.Hash + + return *row, err +} + +func ParseMsgRecvPacket(address string, event db.TaxableTransaction) (Row, error) { + row := &Row{} + + denomToUse := event.DenominationReceived + amountToUse := event.AmountReceived + + conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) + + if err != nil { + config.Log.Error("Error with ParseMsgRecvPacket.", err) + return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: deposit)", event.Message.Tx.Hash) + } + + if event.ReceiverAddress.Address == address { + row.ReceivedAmount = conversionAmount.Text('f', -1) + row.ReceivedCurrency = conversionSymbol + row.Label = Income + } else if event.SenderAddress.Address == address { // withdrawal + row.SentAmount = conversionAmount.Text('f', -1) + row.SentCurrency = conversionSymbol + row.Label = Cost + } + + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) + row.TxHash = event.Message.Tx.Hash + + return *row, err +} + func ParseMsgSubmitProposal(address string, event db.TaxableTransaction) (Row, error) { row := &Row{} err := row.ParseBasic(address, event) From d4ee7b98f0ee1bb6549795518c6be3d3c34c10db Mon Sep 17 00:00:00 2001 From: pharr117 Date: Sun, 21 Jan 2024 12:32:43 -0500 Subject: [PATCH 4/5] Rework start date and end date processing to fix index bugs --- csv/parsers/accointing/accointing.go | 49 +++++----------- csv/parsers/cointracker/cointracker.go | 50 +++++------------ .../cryptotaxcalculator.go | 56 +++++++++---------- csv/parsers/cryptotaxcalculator/osmosis.go | 2 +- csv/parsers/cryptotaxcalculator/rows.go | 12 ++-- csv/parsers/cryptotaxcalculator/types.go | 4 +- csv/parsers/koinly/koinly.go | 52 +++++------------ csv/parsers/taxbit/taxbit.go | 49 +++++----------- 8 files changed, 93 insertions(+), 181 deletions(-) diff --git a/csv/parsers/accointing/accointing.go b/csv/parsers/accointing/accointing.go index 7f2b712..03b495b 100644 --- a/csv/parsers/accointing/accointing.go +++ b/csv/parsers/accointing/accointing.go @@ -109,46 +109,25 @@ func (p *Parser) GetRows(address string, startDate, endDate *time.Time) ([]parse }) // Now that we are sorted, if we have a start date, drop everything from before it, if end date is set, drop everything after it - var firstToKeep *int - var lastToKeep *int + var rowsToKeep []*Row for i := range accointingRows { - if startDate != nil && firstToKeep == nil { - rowDate, err := time.Parse(TimeLayout, accointingRows[i].Date) - if err != nil { - config.Log.Error("Error parsing row date.", err) - return nil, err - } - if rowDate.Before(*startDate) { - continue - } - startIdx := i - firstToKeep = &startIdx - } else if endDate != nil && lastToKeep == nil { - rowDate, err := time.Parse(TimeLayout, accointingRows[i].Date) - if err != nil { - config.Log.Error("Error parsing row date.", err) - return nil, err - } - if rowDate.Before(*endDate) { - continue - } else if i > 0 { - endIdx := i - 1 - lastToKeep = &endIdx - break - } + rowDate, err := time.Parse(TimeLayout, accointingRows[i].Date) + if err != nil { + config.Log.Error("Error parsing row date.", err) + return nil, err } - } - if firstToKeep != nil && lastToKeep != nil { // nolint:gocritic - accointingRows = accointingRows[*firstToKeep:*lastToKeep] - } else if firstToKeep != nil { - accointingRows = accointingRows[*firstToKeep:] - } else if lastToKeep != nil { - accointingRows = accointingRows[:*lastToKeep] + if startDate != nil && rowDate.Before(*startDate) { + continue + } + if endDate != nil && rowDate.After(*endDate) { + break + } + rowsToKeep = append(rowsToKeep, &accointingRows[i]) } // Copy AccointingRows into csvRows for return val - csvRows := make([]parsers.CsvRow, len(accointingRows)) - for i, v := range accointingRows { + csvRows := make([]parsers.CsvRow, len(rowsToKeep)) + for i, v := range rowsToKeep { v.Comments = fmt.Sprintf("Address: %s %s", address, v.Comments) csvRows[i] = v } diff --git a/csv/parsers/cointracker/cointracker.go b/csv/parsers/cointracker/cointracker.go index e71218f..4c16a6c 100644 --- a/csv/parsers/cointracker/cointracker.go +++ b/csv/parsers/cointracker/cointracker.go @@ -121,46 +121,26 @@ func (p *Parser) GetRows(address string, startDate, endDate *time.Time) ([]parse }) // Now that we are sorted, if we have a start date, drop everything from before it, if end date is set, drop everything after it - var firstToKeep *int - var lastToKeep *int + // Now that we are sorted, if we have a start date, drop everything from before it, if end date is set, drop everything after it + var rowsToKeep []*Row for i := range cointrackerRows { - if startDate != nil && firstToKeep == nil { - rowDate, err := time.Parse(TimeLayout, cointrackerRows[i].Date) - if err != nil { - config.Log.Error("Error parsing row date.", err) - return nil, err - } - if rowDate.Before(*startDate) { - continue - } - startIdx := i - firstToKeep = &startIdx - } else if endDate != nil && lastToKeep == nil { - rowDate, err := time.Parse(TimeLayout, cointrackerRows[i].Date) - if err != nil { - config.Log.Error("Error parsing row date.", err) - return nil, err - } - if rowDate.Before(*endDate) { - continue - } else if i > 0 { - endIdx := i - 1 - lastToKeep = &endIdx - break - } + rowDate, err := time.Parse(TimeLayout, cointrackerRows[i].Date) + if err != nil { + config.Log.Error("Error parsing row date.", err) + return nil, err } - } - if firstToKeep != nil && lastToKeep != nil { // nolint:gocritic - cointrackerRows = cointrackerRows[*firstToKeep:*lastToKeep] - } else if firstToKeep != nil { - cointrackerRows = cointrackerRows[*firstToKeep:] - } else if lastToKeep != nil { - cointrackerRows = cointrackerRows[:*lastToKeep] + if startDate != nil && rowDate.Before(*startDate) { + continue + } + if endDate != nil && rowDate.After(*endDate) { + break + } + rowsToKeep = append(rowsToKeep, &cointrackerRows[i]) } // Copy cointrackerRows into csvRows for return val - csvRows := make([]parsers.CsvRow, len(cointrackerRows)) - for i, v := range cointrackerRows { + csvRows := make([]parsers.CsvRow, len(rowsToKeep)) + for i, v := range rowsToKeep { csvRows[i] = v } diff --git a/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go b/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go index f2e7a4c..5c10e68 100644 --- a/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go +++ b/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go @@ -98,40 +98,38 @@ func (p *Parser) GetRows(address string, startDate, endDate *time.Time) ([]parse // Sort by date sort.Slice(cryptoRows, func(i int, j int) bool { - return cryptoRows[i].Date.Before(cryptoRows[j].Date) + leftDate, err := time.Parse(TimeLayout, cryptoRows[i].Date) + if err != nil { + config.Log.Error("Error sorting left date.", err) + return false + } + rightDate, err := time.Parse(TimeLayout, cryptoRows[j].Date) + if err != nil { + config.Log.Error("Error sorting right date.", err) + return false + } + return leftDate.Before(rightDate) }) - // Now that we are sorted, if we have a start date, drop everything from before it, if end date is set, drop everything after it - var firstToKeep *int - var lastToKeep *int + var rowsToKeep []*Row for i := range cryptoRows { - if startDate != nil && firstToKeep == nil { - if cryptoRows[i].Date.Before(*startDate) { - continue - } - startIdx := i - firstToKeep = &startIdx - } else if endDate != nil && lastToKeep == nil { - if cryptoRows[i].Date.Before(*endDate) { - continue - } else if i > 0 { - endIdx := i - 1 - lastToKeep = &endIdx - break - } + rowDate, err := time.Parse(TimeLayout, cryptoRows[i].Date) + if err != nil { + config.Log.Error("Error parsing row date.", err) + return nil, err } - } - if firstToKeep != nil && lastToKeep != nil { // nolint:gocritic - cryptoRows = cryptoRows[*firstToKeep:*lastToKeep] - } else if firstToKeep != nil { - cryptoRows = cryptoRows[*firstToKeep:] - } else if lastToKeep != nil { - cryptoRows = cryptoRows[:*lastToKeep] + if startDate != nil && rowDate.Before(*startDate) { + continue + } + if endDate != nil && rowDate.After(*endDate) { + break + } + rowsToKeep = append(rowsToKeep, &cryptoRows[i]) } // Copy AccointingRows into csvRows for return val - csvRows := make([]parsers.CsvRow, len(cryptoRows)) - for i, v := range cryptoRows { + csvRows := make([]parsers.CsvRow, len(rowsToKeep)) + for i, v := range rowsToKeep { csvRows[i] = v } @@ -334,7 +332,7 @@ func ParseMsgAcknowledgement(address string, event db.TaxableTransaction) (Row, row.From = event.SenderAddress.Address row.To = event.ReceiverAddress.Address - row.Date = event.Message.Tx.Block.TimeStamp + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) row.ID = event.Message.Tx.Hash return *row, err } @@ -364,7 +362,7 @@ func ParseMsgRecvPacket(address string, event db.TaxableTransaction) (Row, error row.From = event.SenderAddress.Address row.To = event.ReceiverAddress.Address - row.Date = event.Message.Tx.Block.TimeStamp + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) row.ID = event.Message.Tx.Hash return *row, err } diff --git a/csv/parsers/cryptotaxcalculator/osmosis.go b/csv/parsers/cryptotaxcalculator/osmosis.go index 59b2eba..b72649e 100644 --- a/csv/parsers/cryptotaxcalculator/osmosis.go +++ b/csv/parsers/cryptotaxcalculator/osmosis.go @@ -12,7 +12,7 @@ func ParseGroup(sf *parsers.WrapperLpTxGroup) error { for _, message := range txMessages { row := Row{} row.ID = message.Message.Tx.Hash - row.Date = message.Message.Tx.Block.TimeStamp + row.Date = message.Message.Tx.Block.TimeStamp.Format(TimeLayout) if message.Message.MessageType.MessageType == gamm.MsgJoinSwapExternAmountIn || message.Message.MessageType.MessageType == gamm.MsgExitSwapShareAmountIn || diff --git a/csv/parsers/cryptotaxcalculator/rows.go b/csv/parsers/cryptotaxcalculator/rows.go index 487eddd..4b4705c 100644 --- a/csv/parsers/cryptotaxcalculator/rows.go +++ b/csv/parsers/cryptotaxcalculator/rows.go @@ -9,7 +9,7 @@ import ( func (row Row) GetRowForCsv() []string { return []string{ - row.Date.Format(TimeLayout), + row.Date, row.Type, row.BaseCurrency, row.BaseAmount, @@ -28,11 +28,11 @@ func (row Row) GetRowForCsv() []string { } func (row Row) GetDate() string { - return row.Date.Format(TimeLayout) + return row.Date } func (row *Row) EventParseBasic(event db.TaxableEvent) error { - row.Date = event.Block.TimeStamp + row.Date = event.Block.TimeStamp.Format(TimeLayout) conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(event.Amount), event.Denomination) if err == nil { @@ -48,7 +48,7 @@ func (row *Row) EventParseBasic(event db.TaxableEvent) error { // ParseBasic: Handles the fields that are shared between most types. func (row *Row) ParseBasic(address string, event db.TaxableTransaction) error { - row.Date = event.Message.Tx.Block.TimeStamp + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) row.ID = event.Message.Tx.Hash // deposit @@ -88,7 +88,7 @@ func (row *Row) ParseBasic(address string, event db.TaxableTransaction) error { } func (row *Row) ParseFee(address string, fee db.Fee) error { - row.Date = fee.Tx.Block.TimeStamp + row.Date = fee.Tx.Block.TimeStamp.Format(TimeLayout) row.ID = fee.Tx.Hash row.Type = Fee @@ -104,7 +104,7 @@ func (row *Row) ParseFee(address string, fee db.Fee) error { } func (row *Row) ParseSwap(event db.TaxableTransaction, address, eventType string) error { - row.Date = event.Message.Tx.Block.TimeStamp + row.Date = event.Message.Tx.Block.TimeStamp.Format(TimeLayout) row.ID = event.Message.Tx.Hash row.Type = eventType diff --git a/csv/parsers/cryptotaxcalculator/types.go b/csv/parsers/cryptotaxcalculator/types.go index c365ba4..400c136 100644 --- a/csv/parsers/cryptotaxcalculator/types.go +++ b/csv/parsers/cryptotaxcalculator/types.go @@ -1,8 +1,6 @@ package cryptotaxcalculator import ( - "time" - "github.com/DefiantLabs/cosmos-tax-cli/csv/parsers" ) @@ -20,7 +18,7 @@ type Parser struct { } type Row struct { - Date time.Time + Date string Type string BaseCurrency string BaseAmount string diff --git a/csv/parsers/koinly/koinly.go b/csv/parsers/koinly/koinly.go index 3a73fc4..49e2180 100644 --- a/csv/parsers/koinly/koinly.go +++ b/csv/parsers/koinly/koinly.go @@ -151,50 +151,28 @@ func (p *Parser) GetRows(address string, startDate, endDate *time.Time) ([]parse } return leftDate.Before(rightDate) }) + mapUnsupportedCoints(koinlyRows) // Now that we are sorted, if we have a start date, drop everything from before it, if end date is set, drop everything after it - var firstToKeep *int - var lastToKeep *int + var rowsToKeep []*Row for i := range koinlyRows { - if startDate != nil && firstToKeep == nil { - rowDate, err := time.Parse(TimeLayout, koinlyRows[i].Date) - if err != nil { - config.Log.Error("Error parsing row date.", err) - return nil, err - } - if rowDate.Before(*startDate) { - continue - } - startIdx := i - firstToKeep = &startIdx - } else if endDate != nil && lastToKeep == nil { - rowDate, err := time.Parse(TimeLayout, koinlyRows[i].Date) - if err != nil { - config.Log.Error("Error parsing row date.", err) - return nil, err - } - if rowDate.Before(*endDate) { - continue - } else if i > 0 { - endIdx := i - 1 - lastToKeep = &endIdx - break - } + rowDate, err := time.Parse(TimeLayout, koinlyRows[i].Date) + if err != nil { + config.Log.Error("Error parsing row date.", err) + return nil, err } + if startDate != nil && rowDate.Before(*startDate) { + continue + } + if endDate != nil && rowDate.After(*endDate) { + break + } + rowsToKeep = append(rowsToKeep, &koinlyRows[i]) } - if firstToKeep != nil && lastToKeep != nil { // nolint:gocritic - koinlyRows = koinlyRows[*firstToKeep:*lastToKeep] - } else if firstToKeep != nil { - koinlyRows = koinlyRows[*firstToKeep:] - } else if lastToKeep != nil { - koinlyRows = koinlyRows[:*lastToKeep] - } - - mapUnsupportedCoints(koinlyRows) // Copy AccointingRows into csvRows for return val - csvRows := make([]parsers.CsvRow, len(koinlyRows)) - for i, v := range koinlyRows { + csvRows := make([]parsers.CsvRow, len(rowsToKeep)) + for i, v := range rowsToKeep { if _, isUnsuppored := coinReplacementMap[v.ReceivedCurrency]; isUnsuppored { v.ReceivedCurrency = coinReplacementMap[v.ReceivedCurrency] } diff --git a/csv/parsers/taxbit/taxbit.go b/csv/parsers/taxbit/taxbit.go index b4864a5..d460dc7 100644 --- a/csv/parsers/taxbit/taxbit.go +++ b/csv/parsers/taxbit/taxbit.go @@ -107,46 +107,25 @@ func (p *Parser) GetRows(address string, startDate, endDate *time.Time) ([]parse }) // Now that we are sorted, if we have a start date, drop everything from before it, if end date is set, drop everything after it - var firstToKeep *int - var lastToKeep *int + var rowsToKeep []*Row for i := range taxbitRows { - if startDate != nil && firstToKeep == nil { - rowDate, err := time.Parse(TimeLayout, taxbitRows[i].Date) - if err != nil { - config.Log.Error("Error parsing row date.", err) - return nil, err - } - if rowDate.Before(*startDate) { - continue - } - startIdx := i - firstToKeep = &startIdx - } else if endDate != nil && lastToKeep == nil { - rowDate, err := time.Parse(TimeLayout, taxbitRows[i].Date) - if err != nil { - config.Log.Error("Error parsing row date.", err) - return nil, err - } - if rowDate.Before(*endDate) { - continue - } else if i > 0 { - endIdx := i - 1 - lastToKeep = &endIdx - break - } + rowDate, err := time.Parse(TimeLayout, taxbitRows[i].Date) + if err != nil { + config.Log.Error("Error parsing row date.", err) + return nil, err } - } - if firstToKeep != nil && lastToKeep != nil { // nolint:gocritic - taxbitRows = taxbitRows[*firstToKeep:*lastToKeep] - } else if firstToKeep != nil { - taxbitRows = taxbitRows[*firstToKeep:] - } else if lastToKeep != nil { - taxbitRows = taxbitRows[:*lastToKeep] + if startDate != nil && rowDate.Before(*startDate) { + continue + } + if endDate != nil && rowDate.After(*endDate) { + break + } + rowsToKeep = append(rowsToKeep, &taxbitRows[i]) } // Copy cointrackerRows into csvRows for return val - csvRows := make([]parsers.CsvRow, len(taxbitRows)) - for i, v := range taxbitRows { + csvRows := make([]parsers.CsvRow, len(rowsToKeep)) + for i, v := range rowsToKeep { csvRows[i] = v } From ed0dc96e0c40642f44bcf9891b176bdd25476c66 Mon Sep 17 00:00:00 2001 From: pharr117 Date: Sun, 21 Jan 2024 12:34:46 -0500 Subject: [PATCH 5/5] gofumpt --- csv/parsers/accointing/accointing.go | 2 -- csv/parsers/cointracker/cointracker.go | 2 -- csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go | 2 -- csv/parsers/koinly/koinly.go | 2 -- 4 files changed, 8 deletions(-) diff --git a/csv/parsers/accointing/accointing.go b/csv/parsers/accointing/accointing.go index 03b495b..1ac8325 100644 --- a/csv/parsers/accointing/accointing.go +++ b/csv/parsers/accointing/accointing.go @@ -371,7 +371,6 @@ func ParseMsgAcknowledgement(address string, event db.TaxableTransaction) (Row, amountToUse := event.AmountSent conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) - if err != nil { config.Log.Error("Error with ParseMsgAcknowledgement.", err) return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: deposit)", row.OperationID) @@ -400,7 +399,6 @@ func ParseMsgRecvPacket(address string, event db.TaxableTransaction) (Row, error amountToUse := event.AmountReceived conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) - if err != nil { config.Log.Error("Error with ParseMsgRecvPacket.", err) return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: deposit)", row.OperationID) diff --git a/csv/parsers/cointracker/cointracker.go b/csv/parsers/cointracker/cointracker.go index 4c16a6c..025d1d5 100644 --- a/csv/parsers/cointracker/cointracker.go +++ b/csv/parsers/cointracker/cointracker.go @@ -346,7 +346,6 @@ func ParseMsgAcknowledgement(address string, event db.TaxableTransaction) (Row, amountToUse := event.AmountSent conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) - if err != nil { config.Log.Error("Error with ParseMsgAcknowledgement.", err) return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: withdrawal)", event.Message.Tx.Hash) @@ -371,7 +370,6 @@ func ParseMsgRecvPacket(address string, event db.TaxableTransaction) (Row, error amountToUse := event.AmountReceived conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) - if err != nil { config.Log.Error("Error with ParseMsgAcknowledgement.", err) return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: withdrawal)", event.Message.Tx.Hash) diff --git a/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go b/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go index 5c10e68..3a0e66f 100644 --- a/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go +++ b/csv/parsers/cryptotaxcalculator/cryptotaxcalculator.go @@ -314,7 +314,6 @@ func ParseMsgAcknowledgement(address string, event db.TaxableTransaction) (Row, amountToUse := event.AmountSent conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) - if err != nil { config.Log.Error("Error with ParseMsgAcknowledgement.", err) return *row, fmt.Errorf("cannot parse denom units for TX %s", event.Message.Tx.Hash) @@ -344,7 +343,6 @@ func ParseMsgRecvPacket(address string, event db.TaxableTransaction) (Row, error amountToUse := event.AmountReceived conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) - if err != nil { config.Log.Error("Error with ParseMsgAcknowledgement.", err) return *row, fmt.Errorf("cannot parse denom units for TX %s", event.Message.Tx.Hash) diff --git a/csv/parsers/koinly/koinly.go b/csv/parsers/koinly/koinly.go index 49e2180..1877892 100644 --- a/csv/parsers/koinly/koinly.go +++ b/csv/parsers/koinly/koinly.go @@ -419,7 +419,6 @@ func ParseMsgAcknowledgement(address string, event db.TaxableTransaction) (Row, amountToUse := event.AmountSent conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) - if err != nil { config.Log.Error("Error with ParseMsgRecvPacket.", err) return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: deposit)", event.Message.Tx.Hash) @@ -448,7 +447,6 @@ func ParseMsgRecvPacket(address string, event db.TaxableTransaction) (Row, error amountToUse := event.AmountReceived conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(amountToUse), denomToUse) - if err != nil { config.Log.Error("Error with ParseMsgRecvPacket.", err) return *row, fmt.Errorf("cannot parse denom units for TX %s (classification: deposit)", event.Message.Tx.Hash)