Skip to content

Commit

Permalink
Patch/csv parsers various message types (#527)
Browse files Browse the repository at this point in the history
* Fix csv parsing group interface definition:
1. Remove hack for parserfunc that was using specific subwrapper parsing func signature
2. Redefine parsing group struct definitions in each csv parser subtype
3. Add parsing group in accointing for concentrated liquidity position messages

* Add cl position group handling for cointracker

* Finish implementation of all parsing groups for cl position handling messages
  • Loading branch information
pharr117 authored Jan 28, 2024
1 parent b936e86 commit 94645eb
Show file tree
Hide file tree
Showing 19 changed files with 863 additions and 91 deletions.
4 changes: 2 additions & 2 deletions csv/parsers/accointing/accointing.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (p *Parser) ProcessTaxableTx(address string, taxableTxs []db.TaxableTransac

// Parse all the TXs found in the Parsing Groups
for _, txParsingGroup := range p.ParsingGroups {
err := txParsingGroup.ParseGroup(ParseGroup)
err := txParsingGroup.ParseGroup()
if err != nil {
return err
}
Expand Down Expand Up @@ -82,7 +82,7 @@ func (p *Parser) ProcessTaxableEvent(taxableEvents []db.TaxableEvent) error {
}

func (p *Parser) InitializeParsingGroups() {
p.ParsingGroups = append(p.ParsingGroups, parsers.GetOsmosisTxParsingGroups()...)
p.ParsingGroups = append(p.ParsingGroups, &OsmosisLpTxGroup{}, &OsmosisConcentratedLiquidityTxGroup{})
}

func (p *Parser) GetRows(address string, startDate, endDate *time.Time) ([]parsers.CsvRow, error) {
Expand Down
113 changes: 90 additions & 23 deletions csv/parsers/accointing/osmosis.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,42 @@ import (
"github.com/DefiantLabs/cosmos-tax-cli/config"
"github.com/DefiantLabs/cosmos-tax-cli/csv/parsers"
"github.com/DefiantLabs/cosmos-tax-cli/db"
"github.com/DefiantLabs/cosmos-tax-cli/util"

"github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/concentratedliquidity"
"github.com/preichenberger/go-coinbasepro/v2"
)

func ParseGroup(sf *parsers.WrapperLpTxGroup) error {
type OsmosisLpTxGroup struct {
GroupedTxes map[uint][]db.TaxableTransaction // TX db ID to its messages
Rows []parsers.CsvRow
}

func (sf *OsmosisLpTxGroup) GetRowsForParsingGroup() []parsers.CsvRow {
return sf.Rows
}

func (sf *OsmosisLpTxGroup) BelongsToGroup(message db.TaxableTransaction) bool {
_, isInGroup := parsers.IsOsmosisLpTxGroup[message.Message.MessageType.MessageType]
return isInGroup
}

func (sf *OsmosisLpTxGroup) GetGroupedTxes() map[uint][]db.TaxableTransaction {
return sf.GroupedTxes
}

func (sf *OsmosisLpTxGroup) String() string {
return "OsmosisLpTxGroup"
}

func (sf *OsmosisLpTxGroup) AddTxToGroup(tx db.TaxableTransaction) {
// Add tx to group using the TX ID as key and appending to array
if sf.GroupedTxes == nil {
sf.GroupedTxes = make(map[uint][]db.TaxableTransaction)
}
sf.GroupedTxes = parsers.AddTxToGroupMap(sf.GroupedTxes, tx)
}

func (sf *OsmosisLpTxGroup) ParseGroup() error {
cbClient := coinbasepro.NewClient()
for _, txMessages := range sf.GroupedTxes {
for _, message := range txMessages {
Expand All @@ -21,27 +51,8 @@ func ParseGroup(sf *parsers.WrapperLpTxGroup) error {
row.OperationID = message.Message.Tx.Hash
row.Date = message.Message.Tx.Block.TimeStamp.Format(TimeLayout)

denomRecieved := message.DenominationReceived
valueRecieved := message.AmountReceived
conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(valueRecieved), denomRecieved)
if err != nil {
row.InBuyAmount = util.NumericToString(valueRecieved)
row.InBuyAsset = denomRecieved.Base
} else {
row.InBuyAmount = conversionAmount.Text('f', -1)
row.InBuyAsset = conversionSymbol
}

denomSent := message.DenominationSent
valueSent := message.AmountSent
conversionAmount, conversionSymbol, err = db.ConvertUnits(util.FromNumeric(valueSent), denomSent)
if err != nil {
row.OutSellAmount = util.NumericToString(valueSent)
row.OutSellAsset = denomSent.Base
} else {
row.OutSellAmount = conversionAmount.Text('f', -1)
row.OutSellAsset = conversionSymbol
}
parseAndAddReceivedAmountWithDefault(&row, message)
parseAndAddSentAmountWithDefault(&row, message)

// We deliberately exclude the GAMM tokens from OutSell/InBuy for Exits/Joins respectively
// Accointing has no way of using the GAMM token to determine LP cost basis etc...
Expand Down Expand Up @@ -77,3 +88,59 @@ func ParseGroup(sf *parsers.WrapperLpTxGroup) error {
}
return nil
}

type OsmosisConcentratedLiquidityTxGroup struct {
GroupedTxes map[uint][]db.TaxableTransaction // TX db ID to its messages
Rows []parsers.CsvRow
}

func (sf *OsmosisConcentratedLiquidityTxGroup) GetRowsForParsingGroup() []parsers.CsvRow {
return sf.Rows
}

func (sf *OsmosisConcentratedLiquidityTxGroup) BelongsToGroup(message db.TaxableTransaction) bool {
_, isInGroup := parsers.IsOsmosisConcentratedLiquidity[message.Message.MessageType.MessageType]
return isInGroup
}

func (sf *OsmosisConcentratedLiquidityTxGroup) GetGroupedTxes() map[uint][]db.TaxableTransaction {
return sf.GroupedTxes
}

func (sf *OsmosisConcentratedLiquidityTxGroup) String() string {
return "OsmosisLpTxGroup"
}

func (sf *OsmosisConcentratedLiquidityTxGroup) AddTxToGroup(tx db.TaxableTransaction) {
// Add tx to group using the TX ID as key and appending to array
if sf.GroupedTxes == nil {
sf.GroupedTxes = make(map[uint][]db.TaxableTransaction)
}
sf.GroupedTxes = parsers.AddTxToGroupMap(sf.GroupedTxes, tx)
}

// Concentrated liquidit txs are grouped to be parsed together. Complex analysis may be require later, so group them now for later extension.
func (sf *OsmosisConcentratedLiquidityTxGroup) ParseGroup() error {
for _, txMessages := range sf.GroupedTxes {
for _, message := range txMessages {
row := Row{}
row.OperationID = message.Message.Tx.Hash
row.Date = message.Message.Tx.Block.TimeStamp.Format(TimeLayout)

switch message.Message.MessageType.MessageType {
case concentratedliquidity.MsgCreatePosition:
parseAndAddSentAmountWithDefault(&row, message)
case concentratedliquidity.MsgWithdrawPosition, concentratedliquidity.MsgTransferPositions:
parseAndAddReceivedAmountWithDefault(&row, message)
case concentratedliquidity.MsgAddToPosition:
if message.DenominationReceivedID != nil {
parseAndAddReceivedAmountWithDefault(&row, message)
} else {
parseAndAddSentAmountWithDefault(&row, message)
}
}
sf.Rows = append(sf.Rows, row)
}
}
return nil
}
38 changes: 38 additions & 0 deletions csv/parsers/accointing/rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,41 @@ func (row *Row) ParseFee(tx db.Tx, fee db.Fee) error {

return nil
}

func parseAndAddSentAmount(row *Row, event db.TaxableTransaction) error {
conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(event.AmountSent), event.DenominationSent)
if err != nil {
return fmt.Errorf("cannot parse denom units for TX %s (classification: withdrawal)", row.OperationID)
}
row.OutSellAmount = conversionAmount.Text('f', -1)
row.OutSellAsset = conversionSymbol

return nil
}

func parseAndAddSentAmountWithDefault(row *Row, event db.TaxableTransaction) {
err := parseAndAddSentAmount(row, event)
if err != nil {
row.OutSellAmount = util.NumericToString(event.AmountSent)
row.OutSellAsset = event.DenominationSent.Base
}
}

func parseAndAddReceivedAmount(row *Row, event db.TaxableTransaction) error {
conversionAmount, conversionSymbol, err := db.ConvertUnits(util.FromNumeric(event.AmountReceived), event.DenominationReceived)
if err != nil {
return fmt.Errorf("cannot parse denom units for TX %s (classification: deposit)", row.OperationID)
}
row.InBuyAmount = conversionAmount.Text('f', -1)
row.InBuyAsset = conversionSymbol

return nil
}

func parseAndAddReceivedAmountWithDefault(row *Row, event db.TaxableTransaction) {
err := parseAndAddReceivedAmount(row, event)
if err != nil {
row.InBuyAmount = util.NumericToString(event.AmountReceived)
row.InBuyAsset = event.DenominationReceived.Base
}
}
4 changes: 2 additions & 2 deletions csv/parsers/cointracker/cointracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (p *Parser) ProcessTaxableTx(address string, taxableTxs []db.TaxableTransac

// Parse all the TXs found in the Parsing Groups
for _, txParsingGroup := range p.ParsingGroups {
err := txParsingGroup.ParseGroup(ParseGroup)
err := txParsingGroup.ParseGroup()
if err != nil {
return err
}
Expand Down Expand Up @@ -94,7 +94,7 @@ func (p *Parser) ProcessTaxableEvent(taxableEvents []db.TaxableEvent) error {
}

func (p *Parser) InitializeParsingGroups() {
p.ParsingGroups = append(p.ParsingGroups, parsers.GetOsmosisTxParsingGroups()...)
p.ParsingGroups = append(p.ParsingGroups, &OsmosisLpTxGroup{}, &OsmosisConcentratedLiquidityTxGroup{})
}

func (p *Parser) GetRows(address string, startDate, endDate *time.Time) ([]parsers.CsvRow, error) {
Expand Down
111 changes: 110 additions & 1 deletion csv/parsers/cointracker/osmosis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,40 @@ package cointracker
import (
"github.com/DefiantLabs/cosmos-tax-cli/csv/parsers"
"github.com/DefiantLabs/cosmos-tax-cli/db"
"github.com/DefiantLabs/cosmos-tax-cli/osmosis/modules/concentratedliquidity"
"github.com/DefiantLabs/cosmos-tax-cli/util"
)

func ParseGroup(sf *parsers.WrapperLpTxGroup) error {
type OsmosisLpTxGroup struct {
GroupedTxes map[uint][]db.TaxableTransaction // TX db ID to its messages
Rows []parsers.CsvRow
}

func (sf *OsmosisLpTxGroup) GetRowsForParsingGroup() []parsers.CsvRow {
return sf.Rows
}

func (sf *OsmosisLpTxGroup) BelongsToGroup(message db.TaxableTransaction) bool {
_, isInGroup := parsers.IsOsmosisLpTxGroup[message.Message.MessageType.MessageType]
return isInGroup
}

func (sf *OsmosisLpTxGroup) GetGroupedTxes() map[uint][]db.TaxableTransaction {
return sf.GroupedTxes
}

func (sf *OsmosisLpTxGroup) String() string {
return "OsmosisLpTxGroup"
}

func (sf *OsmosisLpTxGroup) AddTxToGroup(tx db.TaxableTransaction) {
if sf.GroupedTxes == nil {
sf.GroupedTxes = make(map[uint][]db.TaxableTransaction)
}
sf.GroupedTxes = parsers.AddTxToGroupMap(sf.GroupedTxes, tx)
}

func (sf *OsmosisLpTxGroup) ParseGroup() error {
// cbClient := coinbasepro.NewClient()
for _, txMessages := range sf.GroupedTxes {
for _, message := range txMessages {
Expand Down Expand Up @@ -74,3 +104,82 @@ func ParseGroup(sf *parsers.WrapperLpTxGroup) error {
}
return nil
}

type OsmosisConcentratedLiquidityTxGroup struct {
GroupedTxes map[uint][]db.TaxableTransaction // TX db ID to its messages
Rows []parsers.CsvRow
}

func (sf *OsmosisConcentratedLiquidityTxGroup) GetRowsForParsingGroup() []parsers.CsvRow {
return sf.Rows
}

func (sf *OsmosisConcentratedLiquidityTxGroup) BelongsToGroup(message db.TaxableTransaction) bool {
_, isInGroup := parsers.IsOsmosisConcentratedLiquidity[message.Message.MessageType.MessageType]
return isInGroup
}

func (sf *OsmosisConcentratedLiquidityTxGroup) GetGroupedTxes() map[uint][]db.TaxableTransaction {
return sf.GroupedTxes
}

func (sf *OsmosisConcentratedLiquidityTxGroup) String() string {
return "OsmosisLpTxGroup"
}

func (sf *OsmosisConcentratedLiquidityTxGroup) AddTxToGroup(tx db.TaxableTransaction) {
// Add tx to group using the TX ID as key and appending to array
if sf.GroupedTxes == nil {
sf.GroupedTxes = make(map[uint][]db.TaxableTransaction)
}
sf.GroupedTxes = parsers.AddTxToGroupMap(sf.GroupedTxes, tx)
}

// Concentrated liquidit txs are grouped to be parsed together. Complex analysis may be require later, so group them now for later extension.
func (sf *OsmosisConcentratedLiquidityTxGroup) ParseGroup() error {
txsToFees := parsers.GetTxToFeesMap(sf.GroupedTxes)
for _, txMessages := range sf.GroupedTxes {
for _, message := range txMessages {

row := Row{}
row.Date = message.Message.Tx.Block.TimeStamp.Format(TimeLayout)

switch message.Message.MessageType.MessageType {
case concentratedliquidity.MsgCreatePosition:
parseAndAddSentAmountWithDefault(&row, message)
case concentratedliquidity.MsgWithdrawPosition, concentratedliquidity.MsgTransferPositions:
parseAndAddReceivedAmountWithDefault(&row, message)
case concentratedliquidity.MsgAddToPosition:
if message.DenominationReceivedID != nil {
parseAndAddReceivedAmountWithDefault(&row, message)
} else {
parseAndAddSentAmountWithDefault(&row, message)
}
}

messageFee := txsToFees[message.Message.Tx.ID]
if len(messageFee) > 0 {
fee := messageFee[0]
parseAndAddFeeWithDefault(&row, fee)

// This fee has been processed, pop it off the stack
txsToFees[message.Message.Tx.ID] = txsToFees[message.Message.Tx.ID][1:]

}
sf.Rows = append(sf.Rows, row)
}
}

// If there are any fees left over, add them to the CSV
for _, fees := range txsToFees {
for _, fee := range fees {
row := Row{}
err := row.ParseFee(fee.Tx, fee)
if err != nil {
return err
}
sf.Rows = append(sf.Rows, row)
}
}
return nil
}
Loading

0 comments on commit 94645eb

Please sign in to comment.