eprbell / rp2

Privacy-focused, free, open-source cryptocurrency tax calculator for multiple countries: it handles multiple coins/exchanges and computes long/short-term capital gains, cost bases, in/out lot relationships/fractioning, and account balances. It supports FIFO, LIFO, HIFO and it outputs in form 8949 format. It has a programmable plugin architecture
https://pypi.org/project/rp2/
Apache License 2.0
256 stars 42 forks source link

Staking negative income produces errors #119

Closed advidb closed 3 weeks ago

advidb commented 1 month ago

When staking ETH it is possible to have a negative income. This can happen when your node is offline for a period. This is the error I see when running rp2_us when "Transaction type" is set to "Staking" and "Crypto in" is negative:

ERROR: Fatal exception occurred:
Traceback (most recent call last):
  File "[path to python]/site-packages/rp2/rp2_main.py", line 151, in _rp2_main_internal
    input_data: InputData = parse_ods(configuration=configuration, asset=asset, input_file_handle=input_file_handle)
  File "[path to python]/site-packages/rp2/ods_parser.py", line 127, in parse_ods
    _create_and_process_transaction(
  File "[path to python]/site-packages/rp2/ods_parser.py", line 166, in _create_and_process_transaction
    transaction: AbstractTransaction = _create_transaction(configuration, current_table_type, internal_id, row_values)
  File "[path to python]/site-packages/rp2/ods_parser.py", line 282, in _create_transaction
    transaction = InTransaction(**argument_pack)
  File "[path to python]/site-packages/rp2/in_transaction.py", line 56, in __init__
    self.__crypto_in: RP2Decimal = configuration.type_check_positive_decimal("crypto_in", crypto_in, non_zero=True)
  File "[path to python]/site-packages/rp2/configuration.py", line 471, in type_check_positive_decimal
    raise RP2ValueError(f"Parameter '{name}' has non-positive value {value}")
rp2.rp2_error.RP2ValueError: Parameter 'crypto_in' has non-positive value -0.03

Would it be possible to cater for such negative values?

eprbell commented 1 month ago

Oh, that's interesting (I don't know too much about altcoins, so thanks for educating me): so if you keep your node offline the protocol penalizes you by removing from your stash, rather than adding to it. Is that correct? If so the fix should be fairly easy: this check needs to be changed so that if type is staking then use type_check_decimal, else use type_check_positive_decimal.

eprbell commented 1 month ago

This should be fixed now: see 80b58cb. Let me know if it works.

advidb commented 4 weeks ago

Oh, that's interesting (I don't know too much about altcoins, so thanks for educating me): so if you keep your node offline the protocol penalizes you by removing from your stash, rather than adding to it. Is that correct? If so the fix should be fairly easy: this check needs to be changed so that if type is staking then use type_check_decimal, else use type_check_positive_decimal.

Yes, that's correct. The stake decreases very gradually when offline.

advidb commented 4 weeks ago

This should be fixed now: see 80b58cb. Let me know if it works.

Thanks for the quick response on this. I've tried out the fix but it doesn't work. The error message has changed a bit:

ERROR: Fatal exception occurred:
Traceback (most recent call last):
  File "[path to rp2]/rp2/src/rp2/rp2_main.py", line 154, in _rp2_main_internal
    computed_data: ComputedData = compute_tax(configuration=configuration, accounting_engine=accounting_engine, input_data=input_data)
  File "[path to rp2]/rp2/src/rp2/tax_engine.py", line 44, in compute_tax
    unfiltered_gain_loss_set: GainLossSet = _create_unfiltered_gain_and_loss_set(configuration, accounting_engine, input_data, unfiltered_taxable_event_set)
  File "[path to rp2]/rp2/src/rp2/tax_engine.py", line 127, in _create_unfiltered_gain_and_loss_set
    Configuration.type_check_positive_decimal("taxable_event_amount", taxable_event_amount)
  File "[path to rp2]/rp2/src/rp2/configuration.py", line 471, in type_check_positive_decimal
    raise RP2ValueError(f"Parameter '{name}' has non-positive value {value}")
rp2.rp2_error.RP2ValueError: Parameter 'taxable_event_amount' has non-positive value -0.03
eprbell commented 4 weeks ago

That's an error further downstream. It looks like this isn't as straightforward to fix as I originally thought. I need to find some time to dig into this.

eprbell commented 4 weeks ago

I'm working on a proper fix for this: I should have something ready later today.

eprbell commented 3 weeks ago

OK, this should be fixed for good. The way to capture staking losses is to use STAKING-typed Out Transactions. There is a new unit test that shows this: see test_data4.ods, sheet B4. Let me know if this works for you now.

advidb commented 3 weeks ago

I can now get it running over some staking data containing negative income without producing errors. I wasn't convinced of some of the numbers in the "full_report" ods file so created a simplified input ods file. In case you want to check it out, I've attached it along with the ini config file. The input ods file mocks three days of staking. On each of the first two days 1 ETH is earned (ie two IN rows) and there's one day where 1 ETH is lost (1 OUT row). And the remaining 1 ETH is then sold on Coinbase. In the full report the "Crypto Taxable Total" is equal to 3 ETH. Should it not be 1 ETH? Or perhaps the "IN" staking ETH should be counted separate to the "OUT" staking ETH to give a total for gains and losses respectively.

simple_staking_example.ods simple_staking_example.ini.txt

eprbell commented 3 weeks ago

The "Crypto Taxable Total" for Staking is 3 because there are 3 Staking-related taxable events, each of which amounts to 1 ETH: two Staking/IN and one Staking/OUT (Staking/OUT is treated like a sale, let me know if you have pointers to documentation that says otherwise). That column simply sums all the taxable events denominated in crypto. Note however that the Capital Gains is only $2000, because only the two Staking/IN transactions generated any gains ($1000 each): the Staking/OUT generated $0 gains because the cost basis and the "sale" price are the same ($1000). For your taxes you'll need to use Capital Gains.

advidb commented 3 weeks ago

For tax purposes staking rewards are considered as income in the US as far as I can tell. https://tokentax.co/blog/crypto-staking-taxes https://www.irs.gov/pub/irs-drop/rr-23-14.pdf

So net income over a period would be Staking/IN minus Staking/OUT, to which whatever income tax is relevant would apply. Upon sale of staking rewards, capital gains tax would then apply.

In any case, I think I can get what I need from the reports produced now so I think we're good.

And thanks for clarifying so quickly.