TokenTax supports Balancer, but the automation of DSProxy contracts is technically challenging due to the nature of their internal transactions. This article describes how to manually fix unsupported BPT transactions.
While it's common for these problems to manifest in missing cost basis errors for subsequent transactions, it's possible for them to completely "fly under the radar" if the entire series of taxable events is interpreted as nontaxable deposits/withdrawals by our system. For that reason, you should proactively look for them in the All Transactions page.
First, filter deposits of BPT on the All Transactions page.
Note that these transactions are in the location of "ETH Transaction" — this most likely indicates that we're looking at unsupported DeFi since that's the default location we'll use as a stand-in.
Next, examine the individual transactions by filtering by their hashes. Here is one of the entries:
At a glance it looks like this should really be a MANA -> BPT trade transaction, but we should confirm on etherscan.io by searching by the txn hash just to be sure. Here's the link: https://etherscan.io/tx/0xe7150b29d454784ad98d9d9c196be5586930cd3b3bec0463a82cce529483c570
Here's the view:
Sure enough, the problem is DSProxy. Fortunately, the fix here is pretty easy though. I like to CTRL + F the wallet address so I can clearly see what's going on — this helps me further understand that we are in fact looking at a MANA -> BPT trade transaction. Here I have done this for the shortened version (0x_b1) next to the full wallet address.
There's one additional complication here though: "BPT" isn't really a valid token ticker because there are a few different types of BPTs and we don't want to confuse the tickers. You can figure out the full ticker by clicking the "Balancer Pool Token (BPT)" link on the etherscan page:
From here you can view the contract address. You'll want to copy that contract into a case converting website such as https://caseconvert.net/ and then convert the contract hash to all uppercase. After that, you'll want to put "BPT-" before the hash to get your full ticker name. In this example it's BPT-0XCA54C398195FCE98856888B0FD97A9470A140F71
Now we have all of the information we need. You can copy that ticker back into TokenTax and edit the deposit/withdrawal pair into a single "trade" transaction like so:
This fix was straightforward because it was just a MANA -> BPT trade, but Balancer LP transactions can get complicated since Balancer does not require 50/50 value ratios like Uniswap. What do you do if the issue is an LP transaction and not just a straightforward trade?
Let's look at another transaction — https://etherscan.io/tx/0xbecb1ed02d5bc3b2417bcc81cd22c71b458ff8193402b97717a6de995a235729
If this were a Uniswap transaction, we could correct it by dividing the LP token quantity in half to determine the SellAmount and then adding two "trade" transactions in TokenTax. But this is an 80/20 UMA/ETH (WETH) pool so we need to apply the correct coefficients.
Determine the SellCurrency using the method outlined above. In this example, it's BPT-0XB1F9EC02480DD9E16053B010DFC6E6C4B72ECAD5
Determine your two BuyCurrencies and their coefficients. In this example they are UMA, 0.8 and ETH (WETH), 0.2 since it's an 80/20 UMA/ETH (WETH) pool.
Determine your BuyAmounts by reading the etherscan information. The amounts are 12,482.025284518618327021 for UMA and 42.826604213360436153 for ETH (WETH) in this example.
Apply the coefficients to the total SellAmount to determine what the values should be for your two transactions. In this case they are 0.8 * 8,694.51771495564269955 and 0.2 * 8,694.51771495564269955, or 6,955.61417196451415964 and 1,738.90354299112853991.
Put the information together in TokenTax! The software will round the numbers as they appear on the All Transactions page but the full numbers (up to 16 digits) will remain in the Edit Transactions window.
Alternatively, you can tackle this problem by splitting the transaction into two events: one for the buy side and one for the sell side. Recall that a crypto-to-crypto trade is a taxable event in which you realize a gain or a loss on the token(s) you are disposing based on the difference in cost basis and the fair market value at the moment of sale. We combine trade transactions into a single event for clarity/readability, but you can unpack the transaction like this into two events:
A spend of the tokens that are being sent into the liquidity pool
A fiat to crypto trade transaction for the LP token(s)
A spend of the LP token(s)
Fiat to crypto trade transactions for the tokens being withdrawn from the liquidity pool
In (2) the fiat currency on the sell side of the trade would be the fair market value of the token(s) on the buy side of the trade.
So, what does this have to do with LP transactions? Instead of calculating the pool coefficients for UMA and WETH like we did in the previous example, we can simply change the deposit transactions into income transactions. This will pull in the fiat price for that timestamp, but we also want to make this part of the trade nontaxable so we should edit the income transactions into trade transactions.
Now that we have the buy side covered, we just need to fix the sell side. To do this, simply edit the withdrawal of BPT-0XB1F9EC024... into a spend. The pricing data will most likely be incorrect, but we can derive the LP token price using the information from the buy side of the transaction — just sum the UMA and WETH and divide that sum by the amount of LP tokens.
This method might be overkill for an LP that only has two sides, but it can come in handy for situations where you have three or more constituent tokens.