Skip to main content
glnc

REFERENCE

Crypto tax CSVs: cost basis, Form 8949, FIFO

glnc history --cost-basis fifo annotates each disposal row with FIFO cost basis, USD proceeds, realized gain, and holding period — five new columns at the end of the standard history CSV that map cleanly to IRS Form 8949 and Schedule D. glnc is MIT-licensed AS-IS software and does not constitute tax, legal, or accounting advice. Verify all output with a qualified tax professional before filing.

Important — read this first

glnc does NOT compute ordinary income from staking rewards, airdrops, hard forks, mining, or lending interest. These are taxable as ordinary income at fair market value on receipt (Rev. Rul. 2019-24, Rev. Rul. 2023-14). glnc records each potential inbound as a zero-cost-basis lot and surfaces the USD value in the income_usd column for you or your CPA to classify and report on Schedule 1.

glnc is MIT-licensed AS-IS software. It does not constitute tax, legal, or accounting advice. Verify all output with a qualified tax professional before filing.

Quickstart

Single chain (Ethereum is the default), FIFO cost basis, write to 2025.csv:

glnc history 0xd8dA... --chain ethereum --cost-basis fifo --out 2025.csv
fetching pages 1..7 from etherscan V2
classifying 1,243 transactions
backfilling historical USD prices
computing FIFO cost basis (1 chain: ethereum)
wrote ./2025.csv (1,243 rows, 87 disposals)

Treat transfers between your own wallets as non-taxable — basis travels with the asset instead of being realized:

glnc history 0xd8dA... --chain ethereum --cost-basis fifo --own-wallets 0xA1b2...,0xC3d4... --out 2025.csv
registered 2 own-wallet addresses
computing FIFO cost basis
wrote ./2025.csv (1,243 rows, 41 disposals, 12 own-wallet transfers)

The CSV imports directly into TurboTax (Documents → Import → CSV), Koinly, CoinTracker, and TaxBit. The column order is stable across glnc versions within a major release — see the table below.

CSV columns

Columns are stable so spreadsheets and tax tools can map them once. The last five rows (marked new in v1.1.0) are populated only when --cost-basis fifo is set.

Full CSV column reference for glnc history (23 columns).
FlagDescription
timestampUnix-second timestamp of the block.
iso_timestampUTC ISO-8601 timestamp of the block.
chainChain slug (ethereum, polygon, arbitrum, base, optimism).
tx_hashTransaction hash.
typeClassifier output: transfer-in/out, native-transfer-in/out, swap, wrap, unwrap, approve, contract-call, other.
token_inSymbol of the asset SENT for transfer-out / disposals. (For swap rows: the token paid.)
amount_inQuantity of token_in.
token_outSymbol of the asset RECEIVED for transfer-in / acquisitions. (For swap rows: the token received.)
amount_outQuantity of token_out.
usd_valueUSD value of the row at block time. Drives proceeds_usd for disposals and cost basis for acquisitions.
counterpartyThe non-wallet side of the transaction (matched against --own-wallets).
counterparty_nameHuman-readable label for counterparty when known (e.g. ENS reverse).
fee_nativeGas paid by the sender in native units (ETH, POL, ...). null for receivers.
fee_symbolNative gas symbol (ETH, POL, ...).
fee_usdUSD value of fee_native at block time. NOT capitalized into cost basis — tracked separately.
block_numberBlock height the tx was included in.
contractContract address called by the transaction (the to field on the normal tx).
methodDecoded method name where the classifier resolved one.
cost_basis_usd (new v1.1.0)For disposals only. FIFO basis of the lots consumed, in USD.
proceeds_usd (new v1.1.0)For disposals only. USD value received for the disposed asset at block time.
realized_gain_usd (new v1.1.0)proceeds_usd − cost_basis_usd. Positive = gain, negative = loss. Maps to Form 8949 column (h).
holding_period (new v1.1.0)"short" (≤365 days), "long" (>365 days), or "mixed" if one disposal pops lots spanning both. Drives Form 8949 Part I vs Part II.
income_usd (new v1.1.0)For inbound transfers from non-own wallets. USD value at receipt — a potential ordinary-income event (staking, airdrop, fork, mining, interest). YOU classify; glnc does not.

realized_gain_usd and holding_period together give you exactly what Form 8949 needs to populate Part I (short-term) and Part II (long-term) rows. income_usd is a separate Schedule 1 input — see the next section.

Income vs capital gain — what gets classified how

US tax treats crypto activity along two tracks. glnc emits the data for both, but it does not decide which is which — that decision depends on your facts.

Capital gains (Form 8949 → Schedule D). Disposals of crypto held as property: selling for fiat, swapping one token for another (yes, every swap is a disposal — Notice 2014-21), spending crypto on goods. glnc populates cost_basis_usd, proceeds_usd, realized_gain_usd, and holding_period on every swap, transfer-out, and native-transfer-out row that is not an own-wallet transfer.

Ordinary income (Schedule 1). Crypto received in exchange for services or as a reward — staking rewards, airdrops, hard forks, mining income, lending interest, referral rewards. Per Rev. Rul. 2019-24 and Rev. Rul. 2023-14, this is taxable at fair market value on the date of receipt, and the FMV becomes the cost basis of the resulting lot. glnc surfaces the candidate USD value in income_usd on every inbound row from a non-own-wallet counterparty — but glnc cannot tell a staking reward from a gift from a relative from a returned loan. You or your CPA make that call. See IRS Publication 525 (Schedule 1 income categories) and Publication 544 (sales and dispositions).

The minimal workflow: filter the CSV to rows where income_usd is non-empty, classify each one as income or non-income, sum the income rows by category for Schedule 1. The zero-cost-basis lots that glnc created from those receipts will then produce the correct realized gain when you eventually dispose of them.

The FIFO algorithm

FIFO (First In, First Out) is the default IRS assumption for digital-asset disposals when no specific-identification election applies. glnc walks rows chronologically and maintains a per-asset queue of lots; each acquisition pushes a lot (quantity, cost basis per unit, acquired_at), and each disposal pops lots from the front of the queue until the disposed quantity is consumed.

Worked example. Assume a single asset, ETH:

# chronological events for one wallet, one asset (ETH)
2024-01-10 buy 1.0 ETH @ $2,300 → lot A: 1.0 ETH basis $2,300
2024-06-15 buy 2.0 ETH @ $3,500 → lot B: 2.0 ETH basis $7,000
2025-02-01 sell 0.5 ETH @ $3,200 → proceeds $1,600
pop 0.5 from lot A
basis = 0.5 × $2,300 = $1,150
gain = $1,600 − $1,150 = $450
held = 387 days → long-term
2025-08-01 sell 1.5 ETH @ $4,000 → proceeds $6,000
pop 0.5 remaining from lot A (held 568d → long)
pop 1.0 from lot B (held 412d → long)
basis = (0.5 × $2,300) + (1.0 × $3,500) = $4,650
gain = $6,000 − $4,650 = $1,350
holding = long (both lots > 365d)

If a single disposal had popped one short-term lot and one long-term lot, glnc would label holding_period as mixed. For Form 8949 you would then split that disposal into two rows manually (short-term portion on Part I, long-term portion on Part II) using the basis breakdown in the CSV — the algorithm preserves enough detail for that, but glnc does not auto-split the output row.

Holding period

The IRS rule is "more than one year" for long-term capital gain treatment. glnc implements this as disposed_at − acquired_at > 365 × 86400 seconds.

Holding-period values emitted by glnc.
FlagDescription
shortAll popped lots were held 365 days or less. Maps to Form 8949 Part I; taxed at ordinary income rates.
longAll popped lots were held more than 365 days. Maps to Form 8949 Part II; preferential capital-gain rates.
mixedOne disposal popped lots from both buckets. Split the row manually for Form 8949 using the per-lot basis preserved by FIFO.

Caveat. glnc compares unix-second timestamps, not calendar dates. For more than 99% of dispositions this matches the IRS rule exactly, but the second-precision comparison can disagree with calendar-date arithmetic by one day across a leap year for a disposal almost exactly 366 days after acquisition. If you are within ten days of the boundary on a material disposal, verify by hand.

Multi-wallet tracking with --own-wallets

Send 1 ETH from your hardware wallet to your exchange and back, and a naive cost-basis engine will record two disposals and two acquisitions — fabricating a taxable event out of thin air. --own-wallets tells glnc which addresses you also control so transfers between them are not treated as disposals.

glnc history 0xHARDWARE... --chain ethereum --cost-basis fifo \\ --own-wallets 0xEXCHANGE,0xMETAMASK,0xLEDGER \\ --out 2025.csv
registered 3 own-wallet addresses
computing FIFO cost basis
warn: own-wallet receive of 1.0 ETH from 0xMETAMASK… has no tracked basis from origin wallet (recorded as 0; pass --own-wallets to track basis across your wallets)
wrote ./2025.csv (1,243 rows)

How it works. When glnc sees an outbound transfer to an own-wallet counterparty, it consumes lots from the queue silently — no realization, no row in Form 8949. When it sees an inbound transfer from an own-wallet counterparty, it adds the received amount as a zero-basis lot and emits a warning, because the source wallet was outside the queried address range.

To preserve basis across all your wallets, run glnc history separately for each, listing the others in --own-wallets each time, and concatenate the outputs. A future version may add a single-invocation mode that takes a list of addresses and tracks basis across all of them.

Multi-chain wallets

glnc history defaults to --chain ethereum for FIFO mode. v1.1.0 supports five EVM chains via Etherscan V2: ethereum, polygon, arbitrum, base, and optimism. If you run FIFO without an explicit --chain, glnc prints a banner reminding you that the export covers a single chain and that bridging activity will show up as cross-chain "transfer-out" rows with no offsetting acquisition.

For a multi-chain wallet, run once per chain and concatenate. Dedupe by hash if the wallet has activity on chains that share an EVM address — they shouldn't have shared txs, but cross-chain bridges sometimes emit on both sides:

for c in ethereum polygon arbitrum base optimism; do glnc history 0xd8dA... --chain $c --cost-basis fifo --out 2025-$c.csv done # concatenate, keep header from the first file, dedupe by hash head -1 2025-ethereum.csv > 2025-all.csv for c in ethereum polygon arbitrum base optimism; do tail -n +2 2025-$c.csv done | sort -u -t, -k3,3 >> 2025-all.csv
wrote 2025-ethereum.csv (1,243 rows)
wrote 2025-polygon.csv (412 rows)
wrote 2025-arbitrum.csv (88 rows)
wrote 2025-base.csv (31 rows)
wrote 2025-optimism.csv (19 rows)
wrote 2025-all.csv (1,793 unique rows)

Caveat: FIFO lot state is per-invocation, so cross-chain bridge activity has the same problem as cross-wallet transfers — basis is rebuilt from scratch on each chain. For any wallet that bridges meaningfully across chains, you will want to reconcile by hand or wait for v1.2's planned multi-chain mode.

Wrap and unwrap treatment

glnc treats WETH ↔ ETH wrap/unwrap (and analogous wrappers on other chains) as an ordinary swap — both sides realize. This is the conservative position: the taxpayer slightly over-reports gain, because a wrap that occurs near the cost basis produces a near-zero realized gain anyway, and an unwrap that occurs far from the cost basis correctly captures the price move. The IRS has not issued definitive guidance on whether a wrap is a "like-kind" exchange (which was disallowed for non-real-property by the 2017 Tax Cuts and Jobs Act anyway) or a non-event, so this stays the safe default until guidance lands.

If your CPA prefers the alternative treatment (basis carries through, no realization), filter kind == 'wrap' or kind == 'unwrap' rows out of the CSV before importing, and net the resulting WETH/ETH lots manually. A future version may add an override flag.

Known limitations

1. Schedule 1 ordinary income is not auto-classified. income_usd is populated for inbound transfers from non-own-wallets and is a hint, not a determination. Staking rewards, airdrops, hard forks, mining, lending interest, and referral payouts all flow through this column, mixed in with gifts and returned loans. You decide which is income, and you report on Schedule 1. The IRS treats the FMV at receipt as both the income amount and the cost basis of the resulting lot (Rev. Rul. 2019-24, 2023-14).

2. Cross-chain bridges and unsupported DeFi are not basis-tracked. Liquidity provision, lending, perpetuals, bridge deposits, and any contract call glnc does not specifically decode land in the generic contract-call bucket with no FIFO treatment. The asset movement is still in the CSV; the basis math is not.

3. Without --own-wallets, transfers to your own addresses look like disposals. Sending ETH from your hardware wallet to your exchange and back will produce fabricated taxable events unless you list every wallet you control. Run with --own-wallets from the start — there is no good way to reconstruct this after the fact.

4. Gas fees are not capitalized. fee_usd is recorded separately on every row but is not added to cost basis on acquisitions or netted from proceeds on disposals. Pub 551 allows capitalizing acquisition costs into basis, and Pub 544 allows netting disposal costs from amount realized — glnc defers this to your tax tool because the right answer depends on whether you treat trading as an investment activity or a business activity.

5. Wrap and unwrap are taxable in glnc. See the section above; this is a conservative choice and CPAs may disagree.

6. FIFO only. LIFO, HIFO, and specific-identification are not implemented in v1.1.0. Deferred to v1.2 or later. If you have elected specific-identification for digital assets in writing under the procedures clarified by Notice 2014-21 and subsequent guidance, FIFO output will not match your election.

7. Missing basis records as $0. If glnc sees a disposal of an asset it never saw acquired (because the acquisition was before the queried range, on a different chain, or on a wallet not listed in --own-wallets), it records cost_basis_usd = 0 and emits a warning. This is conservative — the taxpayer over-reports the gain — but you should backfill the real basis before filing.

8. Stablecoin micro-gains. CoinGecko's daily close prices for USDC, USDT, and DAI drift by a fraction of a cent day-to-day, so moving stablecoins around can produce $0.01–$0.10 "realized gains" per disposal. These are de minimis but technically reportable; aggregate or zero them in your tax tool if you prefer.

9. Holding-period boundary uses second-precision arithmetic. See the holding-period section. Verify any disposal within ten days of the 365-day boundary against a calendar-date calculation.

Flags

Tax-related flags on glnc history (v1.1.0).
FlagDescription
--cost-basis <fifo|none>Compute FIFO cost basis, realized gain, and holding period. Default "none" leaves the new columns blank (backward compatible).
--own-wallets <a,b,c>Comma-separated EVM addresses you also control. Transfers to/from these are not treated as disposals or acquisitions.
--chain <name>Restrict to a single chain. v1.1.0 supports ethereum, polygon, arbitrum, base, optimism for FIFO. Defaults to ethereum when --cost-basis is set.
--no-pricesIncompatible with --cost-basis fifo. FIFO requires USD prices; the combination hard-fails.