# docker-finance | modern accounting for the power-user
#
# Copyright (C) 2021-2025 Aaron Fiore (Founder, Evergreen Crypto LLC)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

fields date,blockchain,account_name,subaccount_name,subaccount_address,type,direction,tx_index,tx_hash,token_name,token_id,contract_address,symbol,block_hash,block_number,method_id,from_address,to_address,amount_,fees

date-format %Y-%m-%d %H:%M:%S

description %date +0000

account1 assets:%account_name:%subaccount_name:%blockchain:%symbol
amount %amount_ "%symbol"

comment blockchain:%blockchain, type:%type, block:%block_number, blockid:%block_hash, index:%tx_index, method:%method_id, subaccount_address:%subaccount_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction

# Txs marked as 'internal'
if %type ^internal$
  comment blockchain:%blockchain, type:%type, block:%block_number, subaccount_address:%subaccount_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction

# Txs with contract addresses
if %contract_address [a-z]
  comment blockchain:%blockchain, type:%type, block:%block_number, blockid:%block_hash, index:%tx_index, subaccount_address:%subaccount_address, contract_address:%contract_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction

if %token_id [0-9]
  comment blockchain:%blockchain, type:%type, block:%block_number, blockid:%block_hash, index:%tx_index, subaccount_address:%subaccount_address, contract_address:%contract_address, from_address:%from_address, to_address:%to_address, tokenid:%token_id, txid:%tx_hash, direction:%direction

# Subtract when sending OUT
if %direction ^OUT$
  amount -%amount_ "%symbol"

# Default transfers as equity accounts
if %direction ^IN$
  account2 equity:%account_name:%subaccount_name:%blockchain:withdrawal:%symbol

if %direction ^OUT$
  account2 equity:%account_name:%subaccount_name:%blockchain:deposit:%symbol

# Network fees
#   - To get accurate balance, take all fees from "normal" because fees are also
#     included in ERC-20's.
#   - For certain sends, polygonscan *will* include the ERC-20 tx amount in a
#     'normal' tx along with the fees. For whatever reason, "sending matic" can,
#     at times, send to the contract address for certain end-user addresses. So,
#     reports will produce a double-spend unless this is corrected here.
if %direction ^OUT$
& %blockchain (^ethereum$|^polygon$|^arbitrum$|^base$|^optimism$)
& %type ^normal$
& %fees [1-9]
  account3 assets:%account_name:%subaccount_name:%blockchain:%symbol
  amount3 -%fees %symbol
  account4 expenses:%account_name:%subaccount_name:%blockchain:fees:%symbol
  amount4 %fees %symbol
  comment blockchain:%blockchain, type:%type, block:%block_number, blockid:%block_hash, index:%tx_index, method:%method_id, subaccount_address:%subaccount_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction, taxed_as:SPEND
  comment3 %date +0000,SPEND,%account_name:%subaccount_name:%blockchain,%symbol,%fees,USD,,FEE
# NOTE: docker-finance *WANTS* a MATCH trade to overwrite comment3 because that will *include* this fee in the tx

# Remove 0 value txs (or else journal is cluttered). These should appear for FEE spends only
if %direction ^OUT$
& %blockchain (^ethereum$|^polygon$|^arbitrum$|^base$|^optimism$)
& %amount_ ^[^1-9]*$
  account1
  account2

# ---------------------------------------------------------------------------- #
#                                   Polygon                                    #
# ---------------------------------------------------------------------------- #

# Polygon/MATIC remove dups (only fees in journal entry instead of fees + assets)
if %to_address ^0x0000000000000000000000000000000000001010$
& %direction ^OUT$
& %blockchain ^polygon$
& %type ^normal$
  account1
  account2

# MATIC Plasma bridge contract

if %to_address ^0x401f6c983ea34274ec46f84d70b31c151321188b$
& %blockchain (^ethereum$|^polygon$)
& %amount_ [1-9]
  account2 assets:%account_name:%subaccount_name:polygon:MATIC

# ---------------------------------------------------------------------------- #
#                      Wrapped Ethereum (WETH) contract                        #
# ---------------------------------------------------------------------------- #

# NOTE: No ERC-20 txs here for WETH... all "normal" or "internal"

# TODO: on all supported chains

# BUY
if %to_address ^0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2$
& %blockchain ^ethereum$
& %type (^normal$|^internal$)
& %amount_ [1-9]
  account1 assets:%account_name:%subaccount_name:%blockchain:WETH
  amount %amount_ WETH @@ %amount_ %symbol
  account2 assets:%account_name:%subaccount_name:%blockchain:%symbol
  comment blockchain:%blockchain, type:%type, block:%block_number, blockid:%block_hash, index:%tx_index, method:%method_id, subaccount_address:%subaccount_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction, taxed_as:RAW_TRADE
  comment3 %date +0000,BUY,%account_name:%subaccount_name:%blockchain,WETH,%amount_,%symbol,%amount_,%symbol,%fees
# NOTE: must use comment3 to overwrite FEE SPEND

# BUY (remove unused tags)
if %to_address ^0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2$
& %blockchain ^ethereum$
& %type ^internal$
& %amount_ [1-9]
  comment blockchain:%blockchain, type:%type, block:%block_number, subaccount_address:%subaccount_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction, taxed_as:RAW_TRADE

# SELL
if %from_address ^0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2$
& %blockchain ^ethereum$
& %type (^normal$|^internal$)
& %amount_ [1-9]
  account1 assets:%account_name:%subaccount_name:%blockchain:%symbol
  amount %amount_ %symbol @@ %amount_ WETH
  account2 assets:%account_name:%subaccount_name:%blockchain:WETH
  comment blockchain:%blockchain, type:%type, block:%block_number, blockid:%block_hash, index:%tx_index, method:%method_id, subaccount_address:%subaccount_address, contract_address:%contract_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction, taxed_as:PARTIAL_TRADE
  comment2 %tx_hash,%date +0000,SELL,%account_name:%subaccount_name:%blockchain,WETH,%amount_,%symbol,%amount_
# NOTE: trailing FeeCurrency and Fee columns left empty for PARTIAL_TRADE (see FEE below)

# SELL (remove unused tags)
if %from_address ^0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2$
& %blockchain ^ethereum$
& %type ^internal$
& %amount_ [1-9]
  comment blockchain:%blockchain, type:%type, block:%block_number, subaccount_address:%subaccount_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction, taxed_as:PARTIAL_TRADE

# FEE
if %to_address ^0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2$
& %blockchain ^ethereum$
& %type ^normal$
& %amount_ ^[^1-9]*$
& %fees [1-9]
  comment blockchain:%blockchain, type:%type, block:%block_number, blockid:%block_hash, index:%tx_index, method:%method_id, subaccount_address:%subaccount_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction, taxed_as:PARTIAL_TRADE
  comment2
  comment3 %tx_hash,%date +0000,SPEND,%account_name:%subaccount_name:%blockchain,%symbol,%fees,USD,,FEE
# NOTE:
#  - lib_taxes *MUST* extract only the %symbol and %fees column and append to
#    the previous SELL PARTIAL_TRADE. Rationale for keeping a full comment 3:
#    all functions might not be caught below, so at least the tx will be caught
#    as a SPEND (which it should be)
#  - In custom rules, use comment2 for SPENDs that aren't FEE

# Non-wrap/unwrap functions will not have corresponding wrap, so no PARTIAL_TRADE
# TODO: expand functions as needed
if %to_address ^0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2$
& %method_id (^0x095ea7b3$|^0xa9059cbb$)
& %blockchain ^ethereum$
& %type ^normal$
& %amount_ ^[^1-9]*$
& %fees [1-9]
  comment blockchain:%blockchain, type:%type, block:%block_number, blockid:%block_hash, index:%tx_index, method:%method_id, subaccount_address:%subaccount_address, from_address:%from_address, to_address:%to_address, txid:%tx_hash, direction:%direction, taxed_as:SPEND
  comment2
  comment3 %date +0000,SPEND,%account_name:%subaccount_name:%blockchain,%symbol,%fees,USD,,FEE

# ---------------------------------------------------------------------------- #
#                                   Swapping                                   #
# ---------------------------------------------------------------------------- #

# TODO: on all supported chains

include ./rules.d/swap.d/1inch.rules
include ./rules.d/swap.d/airswap.rules
include ./rules.d/swap.d/metamask.rules
include ./rules.d/swap.d/uniswap.rules

# ---------------------------------------------------------------------------- #
#                                   Lending                                    #
# ---------------------------------------------------------------------------- #

# TODO: on all supported chains

include ./rules.d/lending.d/aave.rules
include ./rules.d/lending.d/compound.rules

# ---------------------------------------------------------------------------- #
#                                   Staking                                    #
# ---------------------------------------------------------------------------- #

# TODO: on all supported chains

include ./rules.d/staking.d/lido.rules
include ./rules.d/staking.d/rocket-pool.rules

# ---------------------------------------------------------------------------- #
#                               Spam / Scamdrops                               #
# ---------------------------------------------------------------------------- #

include ./rules.d/spam.d/arbitrum.rules
include ./rules.d/spam.d/base.rules
include ./rules.d/spam.d/ethereum.rules
include ./rules.d/spam.d/optimism.rules
include ./rules.d/spam.d/polygon.rules

# If an ERC-{721,1155} token has no name and ID of 0, assume it's spam
if %type (^erc-721$|^erc-1155$)
& %token_name ^[^a-z1-9]*$
& %token_id 0
  skip

# vim: sw=2 sts=2 si ai et
