"""Tests for CoW intent matching.""" import math from src.crdt.intent_matching import ( Intent, IntentSet, Match, add_intent, compute_clearing_price, expire_intents, fill_intent, find_cows, merge_intents, total_surplus, ) def _buy_intent(iid: str, sell: float = 100.0, min_buy: float = 95.0, valid: float = 100.0) -> Intent: """Create a USDC->MYCO buy intent.""" return Intent(iid, "alice", "USDC", sell, "MYCO", min_buy, valid) def _sell_intent(iid: str, sell: float = 100.0, min_buy: float = 90.0, valid: float = 100.0) -> Intent: """Create a MYCO->USDC sell intent.""" return Intent(iid, "bob", "MYCO", sell, "USDC", min_buy, valid) class TestIntentSet: def test_add_intent(self): iset = IntentSet() intent = _buy_intent("i1") iset = add_intent(iset, intent) assert "i1" in iset.intents def test_add_duplicate_noop(self): iset = IntentSet() intent = _buy_intent("i1") s1 = add_intent(iset, intent) s2 = add_intent(s1, intent) assert len(s2.intents) == 1 def test_expire_intents(self): iset = IntentSet() iset = add_intent(iset, _buy_intent("i1", valid=10.0)) iset = add_intent(iset, _buy_intent("i2", valid=50.0)) expired = expire_intents(iset, 20.0) assert expired.intents["i1"].status == "expired" assert expired.intents["i2"].status == "open" def test_fill_intent(self): iset = IntentSet() iset = add_intent(iset, _buy_intent("i1")) filled = fill_intent(iset, "i1") assert filled.intents["i1"].status == "filled" def test_fill_already_expired_noop(self): iset = IntentSet() iset = add_intent(iset, _buy_intent("i1", valid=5.0)) iset = expire_intents(iset, 10.0) filled = fill_intent(iset, "i1") assert filled.intents["i1"].status == "expired" def test_pure_functional(self): iset = IntentSet() intent = _buy_intent("i1") updated = add_intent(iset, intent) assert "i1" not in iset.intents assert "i1" in updated.intents class TestClearingPrice: def test_equal_limits_geometric_mean(self): a = Intent("a", "alice", "USDC", 100.0, "MYCO", 100.0, 100.0) b = Intent("b", "bob", "MYCO", 100.0, "USDC", 100.0, 100.0) price = compute_clearing_price(a, b) assert abs(price - 1.0) < 1e-10 def test_asymmetric_prices(self): a = Intent("a", "alice", "USDC", 100.0, "MYCO", 90.0, 100.0) b = Intent("b", "bob", "MYCO", 110.0, "USDC", 100.0, 100.0) price = compute_clearing_price(a, b) # a's limit: 90/100 = 0.9, b's offer: 110/100 = 1.1 expected = math.sqrt(0.9 * 1.1) assert abs(price - expected) < 1e-10 class TestCoWMatching: def test_compatible_pair_matches(self): iset = IntentSet() # Alice: sell 100 USDC, want at least 90 MYCO iset = add_intent(iset, Intent("a", "alice", "USDC", 100.0, "MYCO", 90.0, 100.0)) # Bob: sell 100 MYCO, want at least 90 USDC iset = add_intent(iset, Intent("b", "bob", "MYCO", 100.0, "USDC", 90.0, 100.0)) result = find_cows(iset) assert len(result.matches) == 1 assert len(result.unmatched_ids) == 0 def test_incompatible_prices_no_match(self): iset = IntentSet() # Alice wants too much iset = add_intent(iset, Intent("a", "alice", "USDC", 100.0, "MYCO", 200.0, 100.0)) # Bob wants too much iset = add_intent(iset, Intent("b", "bob", "MYCO", 100.0, "USDC", 200.0, 100.0)) result = find_cows(iset) assert len(result.matches) == 0 assert len(result.unmatched_ids) == 2 def test_same_token_no_match(self): iset = IntentSet() iset = add_intent(iset, Intent("a", "alice", "USDC", 100.0, "MYCO", 90.0, 100.0)) iset = add_intent(iset, Intent("b", "bob", "USDC", 100.0, "MYCO", 90.0, 100.0)) result = find_cows(iset) assert len(result.matches) == 0 def test_multiple_pairs(self): iset = IntentSet() iset = add_intent(iset, Intent("a1", "alice", "USDC", 100.0, "MYCO", 90.0, 100.0)) iset = add_intent(iset, Intent("b1", "bob", "MYCO", 100.0, "USDC", 90.0, 100.0)) iset = add_intent(iset, Intent("a2", "carol", "USDC", 50.0, "MYCO", 45.0, 100.0)) iset = add_intent(iset, Intent("b2", "dave", "MYCO", 50.0, "USDC", 45.0, 100.0)) result = find_cows(iset) assert len(result.matches) == 2 assert len(result.unmatched_ids) == 0 def test_unmatched_remainder(self): iset = IntentSet() iset = add_intent(iset, Intent("a", "alice", "USDC", 100.0, "MYCO", 90.0, 100.0)) iset = add_intent(iset, Intent("b", "bob", "MYCO", 100.0, "USDC", 90.0, 100.0)) iset = add_intent(iset, Intent("c", "carol", "USDC", 50.0, "MYCO", 45.0, 100.0)) result = find_cows(iset) assert len(result.matches) == 1 assert len(result.unmatched_ids) == 1 class TestSurplus: def test_surplus_positive(self): matches = [Match("a", "b", 1.0, 100.0, 100.0)] s = total_surplus(matches) assert s > 0 class TestIntentMerge: def test_merge_commutativity(self): a = IntentSet() a = add_intent(a, _buy_intent("i1")) b = IntentSet() b = add_intent(b, _sell_intent("i2")) ab = merge_intents(a, b) ba = merge_intents(b, a) assert set(ab.intents) == set(ba.intents) def test_merge_idempotency(self): a = IntentSet() a = add_intent(a, _buy_intent("i1")) aa = merge_intents(a, a) assert len(aa.intents) == 1 assert aa.intents["i1"].status == "open" def test_merge_prefers_terminal_status(self): a = IntentSet() a = add_intent(a, _buy_intent("i1")) b = IntentSet() b = add_intent(b, _buy_intent("i1")) b = fill_intent(b, "i1") merged = merge_intents(a, b) assert merged.intents["i1"].status == "filled" def test_merge_filled_over_expired(self): a = IntentSet() a = add_intent(a, _buy_intent("i1", valid=5.0)) a = expire_intents(a, 10.0) b = IntentSet() b = add_intent(b, _buy_intent("i1", valid=5.0)) b = fill_intent(b, "i1") merged = merge_intents(a, b) assert merged.intents["i1"].status == "filled" def test_merge_union(self): a = IntentSet() a = add_intent(a, _buy_intent("i1")) b = IntentSet() b = add_intent(b, _sell_intent("i2")) merged = merge_intents(a, b) assert len(merged.intents) == 2