@@ -1943,3 +1943,116 @@ fn test_clear_score_does_not_affect_history() {
19431943 assert_eq ! ( client. get_score_history( & wallet, & pair) . len( ) , 1 ) ;
19441944 assert_eq ! ( client. get_score_history( & wallet, & pair) . get( 0 ) . unwrap( ) . score, 33 ) ;
19451945}
1946+
1947+ // ── Wallet Score Delegation ───────────────────────────────────────────────────
1948+
1949+ #[ test]
1950+ fn test_delegate_inherits_custodian_score ( ) {
1951+ let ( env, client, _admin, _service) = initialized ( ) ;
1952+ let custodian = Address :: generate ( & env) ;
1953+ let sub_wallet = Address :: generate ( & env) ;
1954+ let pair = symbol_short ! ( "XLM_USDC" ) ;
1955+
1956+ // 1. Set delegate
1957+ client. set_score_delegate ( & sub_wallet, & custodian) ;
1958+
1959+ // 2. Submit score to custodian
1960+ client. submit_score ( & Vec :: new ( & env) , & custodian, & pair, & 40 , & false , & false , & 1 , & 80 , & 1 , & None ) ;
1961+
1962+ // 3. Sub-wallet inherits score
1963+ let score = client. get_score ( & sub_wallet, & pair) ;
1964+ assert_eq ! ( score. score, 40 ) ;
1965+
1966+ // 4. Sub-wallet inherits gate check
1967+ let is_safe = client. query_risk_gate ( & sub_wallet, & pair, & 50 ) ;
1968+ assert ! ( is_safe) ;
1969+
1970+ // 5. Sub-wallet inherits aggregate score
1971+ let aggregate = client. get_aggregate_score ( & sub_wallet) ;
1972+ assert_eq ! ( aggregate. aggregate_score, 40 ) ;
1973+ }
1974+
1975+ #[ test]
1976+ fn test_delegate_direct_score_overrides_delegation ( ) {
1977+ let ( env, client, _admin, _service) = initialized ( ) ;
1978+ let custodian = Address :: generate ( & env) ;
1979+ let sub_wallet = Address :: generate ( & env) ;
1980+ let pair = symbol_short ! ( "XLM_USDC" ) ;
1981+
1982+ client. set_score_delegate ( & sub_wallet, & custodian) ;
1983+ client. submit_score ( & Vec :: new ( & env) , & custodian, & pair, & 80 , & false , & false , & 1 , & 80 , & 1 , & None ) ;
1984+
1985+ // Sub-wallet overrides with its own score
1986+ client. submit_score ( & Vec :: new ( & env) , & sub_wallet, & pair, & 10 , & false , & false , & 1 , & 80 , & 1 , & None ) ;
1987+
1988+ let score = client. get_score ( & sub_wallet, & pair) ;
1989+ assert_eq ! ( score. score, 10 ) ; // Not 80
1990+ }
1991+
1992+ #[ test]
1993+ fn test_cyclic_delegation_rejected ( ) {
1994+ let ( env, client, _admin, _service) = initialized ( ) ;
1995+ let wallet_a = Address :: generate ( & env) ;
1996+ let wallet_b = Address :: generate ( & env) ;
1997+
1998+ // A -> A is rejected
1999+ assert_eq ! ( client. try_set_score_delegate( & wallet_a, & wallet_a) , Err ( Ok ( Error :: CyclicDelegation ) ) ) ;
2000+
2001+ // A -> B -> A is rejected
2002+ client. set_score_delegate ( & wallet_a, & wallet_b) ;
2003+ assert_eq ! ( client. try_set_score_delegate( & wallet_b, & wallet_a) , Err ( Ok ( Error :: CyclicDelegation ) ) ) ;
2004+ }
2005+
2006+ #[ test]
2007+ fn test_remove_delegate_clears_fallback ( ) {
2008+ let ( env, client, _admin, _service) = initialized ( ) ;
2009+ let custodian = Address :: generate ( & env) ;
2010+ let sub_wallet = Address :: generate ( & env) ;
2011+ let pair = symbol_short ! ( "XLM_USDC" ) ;
2012+
2013+ client. set_score_delegate ( & sub_wallet, & custodian) ;
2014+ client. submit_score ( & Vec :: new ( & env) , & custodian, & pair, & 40 , & false , & false , & 1 , & 80 , & 1 , & None ) ;
2015+
2016+ // Works with delegate
2017+ assert_eq ! ( client. get_score( & sub_wallet, & pair) . score, 40 ) ;
2018+
2019+ client. remove_score_delegate ( & sub_wallet) ;
2020+
2021+ // Fallback is gone
2022+ assert_eq ! ( client. try_get_score( & sub_wallet, & pair) , Err ( Ok ( Error :: ScoreNotFound ) ) ) ;
2023+ }
2024+
2025+ #[ test]
2026+ fn test_delegate_propagates_embargo ( ) {
2027+ let ( env, client, _admin, _service) = initialized ( ) ;
2028+ let custodian = Address :: generate ( & env) ;
2029+ let sub_wallet = Address :: generate ( & env) ;
2030+ let pair = symbol_short ! ( "XLM_USDC" ) ;
2031+
2032+ client. set_score_delegate ( & sub_wallet, & custodian) ;
2033+ // Submit embargo score (e.g. 90) which is >= gate_threshold of 75
2034+ client. submit_score ( & Vec :: new ( & env) , & custodian, & pair, & 90 , & false , & false , & 1 , & 80 , & 1 , & None ) ;
2035+
2036+ let is_safe = client. query_risk_gate ( & sub_wallet, & pair, & 75 ) ;
2037+ assert ! ( !is_safe) ; // Embargo propagates
2038+ }
2039+
2040+ #[ test]
2041+ fn test_delegate_snapshot ( ) {
2042+ let ( env, client, _admin, _service) = initialized ( ) ;
2043+ let custodian = Address :: generate ( & env) ;
2044+ let sub_wallet = Address :: generate ( & env) ;
2045+ let pair = symbol_short ! ( "XLM_USDC" ) ;
2046+
2047+ client. set_score_delegate ( & sub_wallet, & custodian) ;
2048+ client. submit_score ( & Vec :: new ( & env) , & custodian, & pair, & 20 , & false , & false , & 1 , & 80 , & 1 , & None ) ;
2049+
2050+ assert_eq ! ( client. get_score( & sub_wallet, & pair) . score, 20 ) ;
2051+
2052+ // Update custodian's score
2053+ env. ledger ( ) . with_mut ( |l| l. timestamp += 3_601 ) ;
2054+ client. submit_score ( & Vec :: new ( & env) , & custodian, & pair, & 50 , & false , & false , & 2 , & 80 , & 1 , & None ) ;
2055+
2056+ // Sub-wallet immediately sees the new score without any update to itself
2057+ assert_eq ! ( client. get_score( & sub_wallet, & pair) . score, 50 ) ;
2058+ }
0 commit comments