@@ -1818,3 +1818,336 @@ fn test_optimistic_timeout_when_neither_side_reaches_majority_by_deadline() {
18181818 // on the challenger" case V2_RESOLUTION.md calls out.
18191819 assert_eq ! ( assertion. final_outcome, Some ( true ) ) ;
18201820}
1821+
1822+ #[ test]
1823+ fn test_settle_strict_majority_conserves_pool_and_pays_dust_to_asserter ( ) {
1824+ let f = Fixture :: new ( ) ;
1825+ let asserter = f. funded_address ( ) ;
1826+ let disputer = f. funded_address ( ) ;
1827+ let voter_x = f. funded_address ( ) ;
1828+ let voter_y = f. funded_address ( ) ;
1829+
1830+ let id = f. asserted ( & asserter) ;
1831+ f. client . dispute ( & disputer, & id) ;
1832+ let policy_hash = f. client . get_assertion ( & id) . policy_hash ;
1833+
1834+ let x_salt = salt ( & f. env , 1 ) ;
1835+ let x_commitment = compute_commitment (
1836+ & f. env ,
1837+ & f. client . address ,
1838+ & policy_hash,
1839+ id,
1840+ & voter_x,
1841+ true ,
1842+ & x_salt,
1843+ ) ;
1844+ f. client . register ( & voter_x, & id, & 300 , & x_commitment) ;
1845+ let y_salt = salt ( & f. env , 2 ) ;
1846+ let y_commitment = compute_commitment (
1847+ & f. env ,
1848+ & f. client . address ,
1849+ & policy_hash,
1850+ id,
1851+ & voter_y,
1852+ true ,
1853+ & y_salt,
1854+ ) ;
1855+ f. client . register ( & voter_y, & id, & 150 , & y_commitment) ;
1856+
1857+ f. advance_past_registration_deadline ( id) ;
1858+ f. client . reveal ( & voter_x, & id, & true , & x_salt) ;
1859+ f. client . reveal ( & voter_y, & id, & true , & y_salt) ;
1860+
1861+ let assertion = f. client . get_assertion ( & id) ;
1862+ assert_eq ! ( assertion. phase, PhaseV2 :: Resolved ) ;
1863+ assert_eq ! ( assertion. terminal_cause, TerminalCause :: StrictMajorityFor ) ;
1864+
1865+ // eligible_total = 100 + 100 + 300 + 150 = 650. recipient_weight (agree)
1866+ // = 100 + 300 + 150 = 550. forfeited_pool = 650 - 550 = 100 (the
1867+ // disputer's forfeited fixed bond).
1868+ // reward_asserter = floor(100 * 100 / 550) = 18
1869+ // reward_x = floor(300 * 100 / 550) = 54
1870+ // reward_y = floor(150 * 100 / 550) = 27
1871+ // sum = 99, dust = 1, credited to the asserter.
1872+ f. client . settle ( & id, & asserter) ;
1873+ f. client . settle ( & id, & voter_x) ;
1874+ f. client . settle ( & id, & voter_y) ;
1875+ f. client . settle ( & id, & disputer) ;
1876+
1877+ assert_eq ! ( f. client. get_credit( & id, & asserter) , 100 + 18 + 1 ) ;
1878+ assert_eq ! ( f. client. get_credit( & id, & voter_x) , 300 + 54 ) ;
1879+ assert_eq ! ( f. client. get_credit( & id, & voter_y) , 150 + 27 ) ;
1880+ assert_eq ! ( f. client. get_credit( & id, & disputer) , 0 ) ;
1881+
1882+ let total = f. client . get_credit ( & id, & asserter)
1883+ + f. client . get_credit ( & id, & voter_x)
1884+ + f. client . get_credit ( & id, & voter_y)
1885+ + f. client . get_credit ( & id, & disputer) ;
1886+ assert_eq ! ( total, 650 ) ;
1887+ }
1888+
1889+ #[ test]
1890+ fn test_settle_strict_majority_order_independent ( ) {
1891+ // Same scenario as
1892+ // test_settle_strict_majority_conserves_pool_and_pays_dust_to_asserter,
1893+ // but settled in a different order (loser first, dust recipient last),
1894+ // to confirm every payout is identical regardless of call order.
1895+ let f = Fixture :: new ( ) ;
1896+ let asserter = f. funded_address ( ) ;
1897+ let disputer = f. funded_address ( ) ;
1898+ let voter_x = f. funded_address ( ) ;
1899+ let voter_y = f. funded_address ( ) ;
1900+
1901+ let id = f. asserted ( & asserter) ;
1902+ f. client . dispute ( & disputer, & id) ;
1903+ let policy_hash = f. client . get_assertion ( & id) . policy_hash ;
1904+
1905+ let x_salt = salt ( & f. env , 1 ) ;
1906+ let x_commitment = compute_commitment (
1907+ & f. env ,
1908+ & f. client . address ,
1909+ & policy_hash,
1910+ id,
1911+ & voter_x,
1912+ true ,
1913+ & x_salt,
1914+ ) ;
1915+ f. client . register ( & voter_x, & id, & 300 , & x_commitment) ;
1916+ let y_salt = salt ( & f. env , 2 ) ;
1917+ let y_commitment = compute_commitment (
1918+ & f. env ,
1919+ & f. client . address ,
1920+ & policy_hash,
1921+ id,
1922+ & voter_y,
1923+ true ,
1924+ & y_salt,
1925+ ) ;
1926+ f. client . register ( & voter_y, & id, & 150 , & y_commitment) ;
1927+
1928+ f. advance_past_registration_deadline ( id) ;
1929+ f. client . reveal ( & voter_x, & id, & true , & x_salt) ;
1930+ f. client . reveal ( & voter_y, & id, & true , & y_salt) ;
1931+
1932+ f. client . settle ( & id, & disputer) ;
1933+ f. client . settle ( & id, & voter_y) ;
1934+ f. client . settle ( & id, & voter_x) ;
1935+ f. client . settle ( & id, & asserter) ;
1936+
1937+ assert_eq ! ( f. client. get_credit( & id, & asserter) , 100 + 18 + 1 ) ;
1938+ assert_eq ! ( f. client. get_credit( & id, & voter_x) , 300 + 54 ) ;
1939+ assert_eq ! ( f. client. get_credit( & id, & voter_y) , 150 + 27 ) ;
1940+ assert_eq ! ( f. client. get_credit( & id, & disputer) , 0 ) ;
1941+ }
1942+
1943+ #[ test]
1944+ fn test_settle_optimistic_timeout_conserves_pool_and_pays_dust_to_asserter ( ) {
1945+ let f = Fixture :: new ( ) ;
1946+ let asserter = f. funded_address ( ) ;
1947+ let disputer = f. funded_address ( ) ;
1948+ let voter_a = f. funded_address ( ) ;
1949+ let voter_b = f. funded_address ( ) ;
1950+ let never_revealed = f. funded_address ( ) ;
1951+
1952+ let id = f. asserted ( & asserter) ;
1953+ f. client . dispute ( & disputer, & id) ;
1954+ let policy_hash = f. client . get_assertion ( & id) . policy_hash ;
1955+
1956+ let a_salt = salt ( & f. env , 1 ) ;
1957+ let a_commitment = compute_commitment (
1958+ & f. env ,
1959+ & f. client . address ,
1960+ & policy_hash,
1961+ id,
1962+ & voter_a,
1963+ true ,
1964+ & a_salt,
1965+ ) ;
1966+ f. client . register ( & voter_a, & id, & 300 , & a_commitment) ;
1967+ let b_salt = salt ( & f. env , 2 ) ;
1968+ let b_commitment = compute_commitment (
1969+ & f. env ,
1970+ & f. client . address ,
1971+ & policy_hash,
1972+ id,
1973+ & voter_b,
1974+ false ,
1975+ & b_salt,
1976+ ) ;
1977+ f. client . register ( & voter_b, & id, & 200 , & b_commitment) ;
1978+ f. client
1979+ . register ( & never_revealed, & id, & 150 , & commitment ( & f. env , 9 ) ) ;
1980+
1981+ f. advance_past_registration_deadline ( id) ;
1982+ f. client . reveal ( & voter_a, & id, & true , & a_salt) ;
1983+ f. client . reveal ( & voter_b, & id, & false , & b_salt) ;
1984+
1985+ f. advance_past_reveal_deadline ( id) ;
1986+ let cause = f. client . resolve_outcome ( & id) ;
1987+ assert_eq ! ( cause, TerminalCause :: OptimisticTimeout ) ;
1988+
1989+ // eligible_total = 100 + 100 + 300 + 200 + 150 = 850. recipient_weight
1990+ // (revealed_weight) = 100 + 100 + 300 + 200 = 700. forfeited_pool =
1991+ // 850 - 700 = 150 (never_revealed's stake).
1992+ // reward_asserter = floor(100 * 150 / 700) = 21
1993+ // reward_disputer = floor(100 * 150 / 700) = 21
1994+ // reward_a = floor(300 * 150 / 700) = 64
1995+ // reward_b = floor(200 * 150 / 700) = 42
1996+ // sum = 148, dust = 2, credited to the asserter (timeout default).
1997+ f. client . settle ( & id, & asserter) ;
1998+ f. client . settle ( & id, & disputer) ;
1999+ f. client . settle ( & id, & voter_a) ;
2000+ f. client . settle ( & id, & voter_b) ;
2001+ f. client . settle ( & id, & never_revealed) ;
2002+
2003+ assert_eq ! ( f. client. get_credit( & id, & asserter) , 100 + 21 + 2 ) ;
2004+ assert_eq ! ( f. client. get_credit( & id, & disputer) , 100 + 21 ) ;
2005+ assert_eq ! ( f. client. get_credit( & id, & voter_a) , 300 + 64 ) ;
2006+ assert_eq ! ( f. client. get_credit( & id, & voter_b) , 200 + 42 ) ;
2007+ assert_eq ! ( f. client. get_credit( & id, & never_revealed) , 0 ) ;
2008+
2009+ let total = f. client . get_credit ( & id, & asserter)
2010+ + f. client . get_credit ( & id, & disputer)
2011+ + f. client . get_credit ( & id, & voter_a)
2012+ + f. client . get_credit ( & id, & voter_b)
2013+ + f. client . get_credit ( & id, & never_revealed) ;
2014+ assert_eq ! ( total, 850 ) ;
2015+ }
2016+
2017+ #[ test]
2018+ fn test_settle_optimistic_timeout_fully_revealed_skips_dust_step ( ) {
2019+ let f = Fixture :: new ( ) ;
2020+ let asserter = f. funded_address ( ) ;
2021+ let disputer = f. funded_address ( ) ;
2022+
2023+ let id = f. asserted ( & asserter) ;
2024+ f. client . dispute ( & disputer, & id) ;
2025+
2026+ f. advance_past_registration_deadline ( id) ;
2027+ let cause = f. client . resolve_outcome ( & id) ;
2028+ assert_eq ! ( cause, TerminalCause :: OptimisticTimeout ) ;
2029+
2030+ // eligible_total = 200, recipient_weight = 200 (both fixed positions
2031+ // auto-revealed), forfeited_pool = 0: nothing forfeited, so the dust
2032+ // step never runs, and every position just recovers its own principal.
2033+ f. client . settle ( & id, & asserter) ;
2034+ f. client . settle ( & id, & disputer) ;
2035+
2036+ assert_eq ! ( f. client. get_credit( & id, & asserter) , 100 ) ;
2037+ assert_eq ! ( f. client. get_credit( & id, & disputer) , 100 ) ;
2038+ }
2039+
2040+ #[ test]
2041+ fn test_settle_strict_majority_against_dust_goes_to_disputer ( ) {
2042+ let f = Fixture :: new ( ) ;
2043+ let asserter = f. funded_address ( ) ;
2044+ let disputer = f. funded_address ( ) ;
2045+ let voter = f. funded_address ( ) ;
2046+
2047+ let id = f. asserted ( & asserter) ;
2048+ f. client . dispute ( & disputer, & id) ;
2049+ let policy_hash = f. client . get_assertion ( & id) . policy_hash ;
2050+
2051+ let voter_salt = salt ( & f. env , 1 ) ;
2052+ let voter_commitment = compute_commitment (
2053+ & f. env ,
2054+ & f. client . address ,
2055+ & policy_hash,
2056+ id,
2057+ & voter,
2058+ false ,
2059+ & voter_salt,
2060+ ) ;
2061+ f. client . register ( & voter, & id, & 301 , & voter_commitment) ;
2062+
2063+ f. advance_past_registration_deadline ( id) ;
2064+ f. client . reveal ( & voter, & id, & false , & voter_salt) ;
2065+
2066+ let assertion = f. client . get_assertion ( & id) ;
2067+ assert_eq ! (
2068+ assertion. terminal_cause,
2069+ TerminalCause :: StrictMajorityAgainst
2070+ ) ;
2071+
2072+ // eligible_total = 100 + 100 + 301 = 501. recipient_weight (disagree) =
2073+ // 100 + 301 = 401. forfeited_pool = 501 - 401 = 100 (asserter's fixed
2074+ // bond, the losing side here).
2075+ // reward_disputer = floor(100 * 100 / 401) = 24
2076+ // reward_voter = floor(301 * 100 / 401) = 75
2077+ // sum = 99, dust = 1, credited to the disputer (the winning party).
2078+ f. client . settle ( & id, & asserter) ;
2079+ f. client . settle ( & id, & voter) ;
2080+ f. client . settle ( & id, & disputer) ;
2081+
2082+ assert_eq ! ( f. client. get_credit( & id, & asserter) , 0 ) ;
2083+ assert_eq ! ( f. client. get_credit( & id, & voter) , 301 + 75 ) ;
2084+ assert_eq ! ( f. client. get_credit( & id, & disputer) , 100 + 24 + 1 ) ;
2085+ }
2086+
2087+ #[ test]
2088+ fn test_settle_before_resolved_fails ( ) {
2089+ let f = Fixture :: new ( ) ;
2090+ let asserter = f. funded_address ( ) ;
2091+ let disputer = f. funded_address ( ) ;
2092+
2093+ let id = f. asserted ( & asserter) ;
2094+ f. client . dispute ( & disputer, & id) ;
2095+
2096+ let result = f. client . try_settle ( & id, & asserter) ;
2097+ assert_eq ! ( result, Err ( Ok ( Error :: NotResolved ) ) ) ;
2098+ }
2099+
2100+ #[ test]
2101+ fn test_settle_on_uncontested_finalize_fails ( ) {
2102+ let f = Fixture :: new ( ) ;
2103+ let asserter = f. funded_address ( ) ;
2104+
2105+ let id = f. asserted ( & asserter) ;
2106+ f. advance_past_window ( ) ;
2107+ f. client . finalize ( & asserter, & id) ;
2108+
2109+ let result = f. client . try_settle ( & id, & asserter) ;
2110+ assert_eq ! ( result, Err ( Ok ( Error :: NotResolved ) ) ) ;
2111+ }
2112+
2113+ #[ test]
2114+ fn test_settle_twice_fails ( ) {
2115+ let f = Fixture :: new ( ) ;
2116+ let asserter = f. funded_address ( ) ;
2117+ let disputer = f. funded_address ( ) ;
2118+
2119+ let id = f. asserted ( & asserter) ;
2120+ f. client . dispute ( & disputer, & id) ;
2121+ f. advance_past_registration_deadline ( id) ;
2122+ f. client . resolve_outcome ( & id) ;
2123+
2124+ f. client . settle ( & id, & asserter) ;
2125+ let result = f. client . try_settle ( & id, & asserter) ;
2126+ assert_eq ! ( result, Err ( Ok ( Error :: AlreadySettled ) ) ) ;
2127+ }
2128+
2129+ #[ test]
2130+ fn test_settle_nonexistent_position_fails ( ) {
2131+ let f = Fixture :: new ( ) ;
2132+ let asserter = f. funded_address ( ) ;
2133+ let disputer = f. funded_address ( ) ;
2134+ let stranger = f. funded_address ( ) ;
2135+
2136+ let id = f. asserted ( & asserter) ;
2137+ f. client . dispute ( & disputer, & id) ;
2138+ f. advance_past_registration_deadline ( id) ;
2139+ f. client . resolve_outcome ( & id) ;
2140+
2141+ let result = f. client . try_settle ( & id, & stranger) ;
2142+ assert_eq ! ( result, Err ( Ok ( Error :: AssertionNotFound ) ) ) ;
2143+ }
2144+
2145+ #[ test]
2146+ fn test_get_credit_returns_zero_for_unknown_address ( ) {
2147+ let f = Fixture :: new ( ) ;
2148+ let asserter = f. funded_address ( ) ;
2149+ let stranger = f. funded_address ( ) ;
2150+
2151+ let id = f. asserted ( & asserter) ;
2152+ assert_eq ! ( f. client. get_credit( & id, & stranger) , 0 ) ;
2153+ }
0 commit comments