diff --git a/README.md b/README.md index ce806cc..7c13585 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,15 @@ This solution provides a simple starting point for a tool to export on-chain Alg * [CoinTracker](https://www.cointracker.io/) * [Koinly](https://koinly.io/) +* [TokenTax](https://tokentax.co/) CoinTracker has an excellent tax guide if you'd lke more details on the subject: https://www.cointracker.io/blog/crypto-tax-guide Koinly is an excellent choice as well. There are pros/cons to all of these sites and with varying fees & features. They're worth a look. +TokenTax is another simple and easy to use option, but comes at a cost. The report generated from this tool tracks "Deposits", "Withdrawals" and "Staking" income. Combined with +data one's other wallets/exchanges, TokenTax can show captial gains as well as income received from Algorand staking. + [TOC] # Requirements @@ -535,4 +539,4 @@ Index server to connect to (default "localhost:8980") Refer back to [Example use](#example-use) for examples of how the program is used. -Enjoy! \ No newline at end of file +Enjoy! diff --git a/exporter/tokentax.go b/exporter/tokentax.go new file mode 100644 index 0000000..6c7c500 --- /dev/null +++ b/exporter/tokentax.go @@ -0,0 +1,74 @@ +package exporter + +import ( + "fmt" + "io" + "os" +) + +/* + NOTHING HERE IS TAX ADVICE NOR SHOULD BE INTERPRETED AS SUCH. + + This TokenTax exporter makes a key classification / assumption: + + All transactions are either a Withdrawal, Deposit or Staking reward. + Since we can only see Algo-in / Algo-out, we classify "Algo-in" as a deposit, "Algo-out" + as a withdrawal. Staking rewards are "Staking". If an "Algo-out" transaction is to + a wallet that isn't yours, it'll likely show up in your Tax reporting software + and will likely need to be reclassified from "Withdrawal" -> "Spend". (AGAIN THIS IS NOT + TAX ADVICE NOT SHOULD BE INTERPRETED AS SUCH.) +*/ + +type TokenTaxExporter struct { +} + +func (t TokenTaxExporter) Name() string { + return "tokentax" +} + +func (t *TokenTaxExporter) WriteHeader(writer io.Writer) { + header := "Type,BuyAmount,BuyCurrency,SellAmount,SellCurrency,FeeAmount,FeeCurrency,Exchange,Group,Comment,Date" + fmt.Fprintln(writer, header) +} + +func (t *TokenTaxExporter) WriteRecord(writer io.Writer, record ExportRecord) { + + var transactionType, buyAmt, sellAmt string + if record.reward { + transactionType = "Staking" + buyAmt = algoFmt(record.recvQty) + } else { + // If we have a Buy and Sell Amt, this is a "Trade". + // This program isn't meant to track trades. Since we're just + // tracking down transactions between wallets for tax purposes. + // If you're buying and selling, you're likely using an exchange, + // these exchanges can wire into TokenTax (in this case). + if record.recvQty != 0 && record.sentQty != 0 { + msg := "Detected Buy and Sell qtys, this is likely a trade. This program doesn't support trades right now" + fmt.Println(msg) + os.Exit(1) + } else if record.recvQty != 0 { + transactionType = "Deposit" + buyAmt = algoFmt(record.recvQty) + } else if record.sentQty != 0 { + transactionType = "Withdrawal" + sellAmt = algoFmt(record.sentQty) + } + } + fmt.Fprintf(writer, "%s,", transactionType) + if transactionType == "Deposit" || transactionType == "Staking" { + fmt.Fprintf(writer, "%s,ALGO,,,,,,,,", buyAmt) + } else if transactionType == "Withdrawal" { + fmt.Fprintf(writer, ",,%s,ALGO,,,,,,", sellAmt) + } + // Finally, the date + fmt.Fprintf(writer, "%s UTC\n", record.blockTime.UTC().Format("01/02/2006 15:04")) +} + +func NewTokenTaxExporter() Interface { + return &TokenTaxExporter{} +} + +func init() { + registerFormat("tokentax", NewTokenTaxExporter) +} diff --git a/go.sum b/go.sum index f108b74..3f49671 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/algorand/go-algorand-sdk v1.4.2 h1:xF+Q1ZjuFrRVwzGZ0MQJT22S4CWN65tWYNLef3A9Og4= github.com/algorand/go-algorand-sdk v1.4.2/go.mod h1:atJEKcxcwxgK7E0N1NfKCUyRUWTpt13vpBry+V+uP1Q= +github.com/algorand/go-algorand-sdk v1.5.1 h1:5THZvMOlfAc+HHRhbV/V89LJC4k0EzhK1mn3oizSt+c= +github.com/algorand/go-algorand-sdk v1.5.1/go.mod h1:U12d8fTN/CyKPR1HObrt51ITxb6OgXxpGCH743Ds2GQ= github.com/algorand/go-codec v1.1.7 h1:6nvCh2nfgnfkaoVHKQyk2wxyl2GQBAlI7IkbqbB/e4s= github.com/algorand/go-codec v1.1.7/go.mod h1:pVLQYhIVCsx9D3iy4W4Qqi0SKhx6IVhMwOvj/agFL4g= github.com/algorand/go-codec/codec v1.1.7 h1:EFOyWf5duxbh2ru+AW1YDgmZ+MRVgqklELSqTArgp3M= @@ -10,6 +12,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=