"""Tests for batch settlement orchestration.""" from src.crdt.batch_settlement import ( BatchConfig, PendingBatch, Settlement, create_batch, net_curve_position, simulate_batch_efficiency, solve_batch, ) from src.crdt.intent_matching import Intent, IntentSet, add_intent from src.crdt.labor_crdt import ( AttestationEntry, CRDTLaborSystem, submit_attestation, ) RATES = {"code": 10.0, "governance": 5.0} def _buy(iid: str, amount: float = 100.0) -> Intent: return Intent(iid, "buyer", "USDC", amount, "MYCO", amount * 0.9, 1000.0) def _sell(iid: str, amount: float = 100.0) -> Intent: return Intent(iid, "seller", "MYCO", amount, "USDC", amount * 0.9, 1000.0) class TestCreateBatch: def test_creates_batch(self): iset = IntentSet() iset = add_intent(iset, _buy("b1")) config = BatchConfig() batch = create_batch(iset, CRDTLaborSystem(), config, 0.0) assert len(batch.intents.intents) == 1 assert batch.window_end == config.settlement_interval def test_expires_stale_intents(self): iset = IntentSet() iset = add_intent(iset, Intent("old", "alice", "USDC", 100, "MYCO", 90, valid_until=5.0)) iset = add_intent(iset, _buy("new")) config = BatchConfig() batch = create_batch(iset, CRDTLaborSystem(), config, 10.0) assert batch.intents.intents["old"].status == "expired" assert batch.intents.intents["new"].status == "open" def test_caps_batch_size(self): iset = IntentSet() for i in range(20): iset = add_intent(iset, _buy(f"b{i}")) config = BatchConfig(max_batch_size=5) batch = create_batch(iset, CRDTLaborSystem(), config, 0.0) open_count = sum(1 for i in batch.intents.intents.values() if i.status == "open") assert open_count <= 5 class TestSolveBatch: def test_cow_matching(self): iset = IntentSet() iset = add_intent(iset, _buy("b1")) iset = add_intent(iset, _sell("s1")) config = BatchConfig() batch = create_batch(iset, CRDTLaborSystem(), config, 0.0) settlement = solve_batch(batch, RATES) assert len(settlement.cow_matches) == 1 assert settlement.net_curve_buy == 0.0 assert settlement.net_curve_sell == 0.0 def test_unmatched_goes_to_curve(self): iset = IntentSet() iset = add_intent(iset, _buy("b1", 100.0)) config = BatchConfig() batch = create_batch(iset, CRDTLaborSystem(), config, 0.0) settlement = solve_batch(batch, RATES) assert len(settlement.cow_matches) == 0 assert settlement.net_curve_buy == 100.0 def test_labor_mints_included(self): labor = CRDTLaborSystem() entry = AttestationEntry("e1", "code", 5.0, 0.0, "oracle") labor = submit_attestation(labor, "alice", entry) config = BatchConfig() batch = create_batch(IntentSet(), labor, config, 0.0) settlement = solve_batch(batch, RATES) assert "alice" in settlement.labor_mints assert settlement.labor_mints["alice"] == 50.0 # 5 * 10 def test_mixed_batch(self): iset = IntentSet() iset = add_intent(iset, _buy("b1")) iset = add_intent(iset, _sell("s1")) iset = add_intent(iset, _buy("b2", 50.0)) # Unmatched labor = CRDTLaborSystem() labor = submit_attestation(labor, "alice", AttestationEntry("e1", "code", 3.0, 0.0, "oracle")) config = BatchConfig() batch = create_batch(iset, labor, config, 0.0) settlement = solve_batch(batch, RATES) assert len(settlement.cow_matches) == 1 assert settlement.net_curve_buy == 50.0 assert settlement.labor_mints["alice"] == 30.0 class TestNetPosition: def test_net_position(self): settlement = Settlement( net_curve_buy=500.0, net_curve_sell=200.0, ) usdc, myco = net_curve_position(settlement) assert usdc == 500.0 assert myco == 200.0 class TestSimulation: def test_simulation_returns_stats(self): result = simulate_batch_efficiency( n_intents=20, cow_probability=0.5, n_batches=10, ) assert "avg_match_rate" in result assert "avg_surplus" in result assert "avg_unmatched" in result assert 0 <= result["avg_match_rate"] <= 1.0 def test_more_intents_more_matches(self): small = simulate_batch_efficiency(n_intents=4, cow_probability=0.5, n_batches=50) large = simulate_batch_efficiency(n_intents=40, cow_probability=0.5, n_batches=50) # Larger batches should have at least as good match rates on average # (not guaranteed per run but statistically likely) # Just check both are valid assert small["avg_match_rate"] >= 0 assert large["avg_match_rate"] >= 0