# Author: Simon-Pierre Boucher # Mail: contact@spboucher.ai """Unit checks for V3: bitcoin output parsing, EVM native whales, price rows.""" import pathlib import sys sys.path.insert(0, str(pathlib.Path(__file__).parent.parent)) from indexer import db from indexer.adapters.bitcoin import BitcoinIndexer from indexer.ingest import ChainIndexer BTC_CFG = {"rpcs": ["http://unused.invalid"], "confirmations": 1, "native": {"symbol": "BTC", "min": 5, "decimals": 8}} def make_btc(): ix = BitcoinIndexer("bitcoin", BTC_CFG, [], ":memory:") ix.conn = db.connect(":memory:") return ix def test_bitcoin_whale_outputs(): ix = make_btc() ix.pool.get = lambda path: ( {"timestamp": 1786000000} if path == "/block/HASH" else None) ix.block_txs = lambda h: [ { # 12 BTC to bob from a single-input-address tx → recorded "txid": "aa" * 32, "vin": [{"prevout": {"scriptpubkey_address": "bc1alice"}}], "vout": [ {"value": 12_0000_0000, "scriptpubkey_address": "bc1bob"}, {"value": 3_0000_0000, "scriptpubkey_address": "bc1alice"}, # change < min anyway ], }, { # multi-input (ambiguous sender) 7 BTC → recorded with from=None "txid": "bb" * 32, "vin": [{"prevout": {"scriptpubkey_address": "bc1x"}}, {"prevout": {"scriptpubkey_address": "bc1y"}}], "vout": [{"value": 7_0000_0000, "scriptpubkey_address": "bc1z"}], }, { # 20 BTC change back to the same sender → filtered out "txid": "cc" * 32, "vin": [{"prevout": {"scriptpubkey_address": "bc1self"}}], "vout": [{"value": 20_0000_0000, "scriptpubkey_address": "bc1self"}], }, { # below threshold → ignored "txid": "dd" * 32, "vin": [{"prevout": {"scriptpubkey_address": "bc1small"}}], "vout": [{"value": 1_0000_0000, "scriptpubkey_address": "bc1w"}], }, ] n = ix.process_block(961000, "HASH") rows = ix.conn.execute('SELECT tx_hash, "from", "to", amount FROM transfers ORDER BY tx_hash').fetchall() assert n == 2 and len(rows) == 2 assert rows[0][1] == "bc1alice" and rows[0][2] == "bc1bob" and rows[0][3] == "1200000000" assert rows[1][1] is None and rows[1][2] == "bc1z" EVM_CFG = {"rpcs": ["http://unused.invalid"], "max_range": 8, "confirmations": 2, "native": {"symbol": "ETH", "min": 50, "decimals": 18}} def test_evm_native_whales(): ix = ChainIndexer("ethereum", EVM_CFG, [], ":memory:") ix.conn = db.connect(":memory:") def fake_call(method, params=None): assert method == "eth_getBlockByNumber" and params[1] is True n = int(params[0], 16) return { "number": hex(n), "hash": "0x" + f"{n:x}".rjust(64, "b"), "timestamp": hex(1786000000 + n), "transactions": [ {"hash": "0x" + f"{n:x}1".rjust(64, "a"), "from": "0xAA", "to": "0xBB", "value": hex(60 * 10**18)}, # 60 ETH → recorded {"hash": "0x" + f"{n:x}2".rjust(64, "a"), "from": "0xCC", "to": "0xDD", "value": hex(1 * 10**18)}, # 1 ETH → ignored ], } ix.pool.batch = lambda calls: [fake_call(m, p) for m, p in calls] ix.process_native(100, 101) rows = ix.conn.execute("SELECT symbol, token, amount FROM transfers").fetchall() assert len(rows) == 2 # one whale per block assert all(r[0] == "ETH" and r[1] == "native" and r[2] == str(60 * 10**18) for r in rows) def test_prices_upsert_and_join(): conn = db.connect(":memory:") db.upsert_prices(conn, [("ETH", 3000.0, 1786000000), ("USDT", 1.0, 1786000000)]) db.upsert_prices(conn, [("ETH", 3100.0, 1786000300)]) # update wins r = conn.execute("SELECT usd FROM prices WHERE symbol = 'ETH'").fetchone() assert r[0] == 3100.0 if __name__ == "__main__": for name, fn in sorted(globals().items()): if name.startswith("test_"): fn() print(f"ok {name}") print("all v3 tests passed")