Multi-chain NFT spend analyzer for Tezos, Ethereum, and Base.
Tells you exactly how much USD you've spent on NFTs (mints + secondary purchases) across these chains, converted at the historical XTZ/ETH price at the time of each transaction.
The naive approach — "sum all XTZ/ETH I sent to NFT marketplaces" — dramatically overstates spend on Tezos because:
offer/collection_offer/bidentrypoints lock XTZ in the marketplace contract.- Most offers never get accepted, and the XTZ refunds back to your wallet.
- A naive gross calculation can be 2-3× higher than your real net spend.
This tool computes net spend by also fetching refund inflows from those same contracts and subtracting them. On Ethereum/Base it uses an NFT-centric approach that sidesteps the problem entirely (only counts transactions where you actually received an NFT).
| Chain | Data source | Cost source | Free? |
|---|---|---|---|
| Tezos (mainnet) | TzKT API | TzKT quote=usd embedded historical price |
Yes |
| Ethereum (mainnet) | Etherscan V2 API | CryptoCompare daily ETH/USD | Free key needed |
| Base (mainnet) | Blockscout API | CryptoCompare daily ETH/USD | Yes |
Marketplaces classified out of the box:
- Tezos: fxhash (V1/V2/V3, plus V4 per-project detection by parameter shape), objkt.com (multiple versions), Teia, hicetnunc, akaSwap (Marketplace, Auction, Offer, Gacha), Versum, 8bidou, Kalamint, Typed, 8scribo, Marina Abramović NFT Sales, Emprops, Tezos Domains, plus generic detection for any contract with
mint/mint_token/claim/redeementrypoint. - Ethereum: OpenSea (Wyvern v1/v2, Seaport 1.1/1.4/1.5/1.6/new), LooksRare v1/v2, X2Y2, Blur (Marketplace v1/v2/v3 + Pool), SuperRare, Foundation, Zora, Rarible, Manifold, Feral File, Reservoir aggregator, ENS.
- Base: OpenSea Seaport, Zora (Protocol Rewards / Creator 1155 / Mints Manager), Highlight, Manifold, Reservoir, plus direct-mint detection (Base is mint-heavy).
Unknown / unclassified contract targets are listed in the output so you can extend the marketplace maps.
pip install -r requirements.txt
cp .env.example .env
# Edit .env: put your wallet addresses and (for Ethereum) Etherscan API key- Sign up at https://etherscan.io/register (free).
- Visit https://etherscan.io/myapikey and click Add.
- Paste the key into
.envasETHERSCAN_API_KEY=....
Free tier is 100K calls/day, 5 calls/sec — plenty for one wallet. Base does not need a key (uses Blockscout).
# Tezos — gross spend (raw outflow to marketplaces)
python analyze_tezos.py
# Tezos — net spend (subtracts refunds/proceeds — RECOMMENDED)
python analyze_tezos_net.py
# Tezos — audit: top tx, entrypoint breakdown, duplicate-hash check
python audit_tezos.py
# Ethereum
python analyze_eth.py
# Base
python analyze_base.pyEach script writes a nft_spend_<chain>.csv with every classified transaction, and prints aggregate summaries (by kind, by marketplace, by year, by wallet) to stdout.
The CSVs are gitignored — they contain your personal transaction history.
nft_spend_<chain>.csv columns (Tezos):
| column | meaning |
|---|---|
wallet |
Your Tezos address that sent the tx |
timestamp |
Block timestamp (UTC) |
marketplace |
Classified marketplace name |
kind |
mint or purchase |
entrypoint |
Smart contract entrypoint called |
xtz |
XTZ paid |
usd_rate |
XTZ/USD at tx time (from TzKT) |
usd |
xtz × usd_rate |
target |
KT1 contract address |
target_alias |
Contract alias from TzKT registry |
hash |
Tezos operation hash |
EVM CSVs (nft_spend_eth.csv, nft_spend_base.csv) instead group by NFT acquisition — one row per parent tx that brought NFTs into your wallet, with eth (direct ETH sent) and weth (WETH sent in same tx) summed as total_eth_eq.
analyze_tezos.py (gross):
- Fetches all outgoing tx from your wallets to KT1 contracts since
START_DATEwithamount > 0. - Classifies the target as one of the known marketplaces, or by fuzzy alias match, or by parameter shape (fxhash V4), or by mint/claim entrypoint.
- Converts XTZ to USD using TzKT's embedded
quote=usdhistorical rate.
analyze_tezos_net.py (net) does the above, then:
4. For every contract you sent XTZ to, fetches all incoming XTZ from that same contract back to your wallet.
5. Reports net = gross_out − gross_in per marketplace.
The inflows include both (a) refunded offers/bids and (b) sale proceeds if you also sold NFTs on that marketplace. Both are correctly subtracted to give net cash flow.
analyze_eth.py and analyze_base.py work differently:
- Fetch every incoming ERC-721 and ERC-1155 transfer to your wallet.
- Group by parent tx hash.
- For each parent tx, sum the tx's ETH
value+ any WETH outflow in the same tx. - Classify the marketplace from the parent tx's
tofield.
This means only NFT acquisitions are counted — offers that never settled simply don't appear (no NFT inflow → not counted), so the gross/net distinction doesn't apply. WETH is included because OpenSea Seaport bids, LooksRare bids, etc. settle in WETH rather than ETH.
NFTs received with value = 0 (free mints, gifts, airdrops) are skipped from spend totals but counted.
- Gas fees not included. Some chains (Ethereum) have non-trivial gas; this tool measures NFT cost only.
- FA2 token payments on Tezos (e.g. NFTs bought with kUSD / USDt) are not yet captured — only XTZ-denominated.
- Aggregator routing (Reservoir, OpenSea sweep) is classified by the aggregator's address; the underlying marketplace is not broken out.
- L2s other than Base (Polygon, Arbitrum, Optimism, Etherlink) not yet supported. The Base script is a template — copy it, swap the Blockscout URL and chain-specific WETH address.
To add a marketplace contract, edit the MARKETPLACES / ETH_MARKETPLACES / BASE_MARKETPLACES dict at the top of the relevant script. Run again — newly-classified contracts will move from the "unclassified" section into the main breakdown.
To add a chain: clone analyze_base.py, change BLOCKSCOUT_API to that chain's Blockscout instance (e.g. https://optimism.blockscout.com/api), update the WETH address, and seed the marketplace dict.
MIT — see LICENSE.