@@ -415,7 +415,9 @@ pub fn build_request_payload(
415415 } )
416416 . transpose ( ) ?;
417417
418- // For backwards compatibility we hash the signal
418+ // Legacy v3 payloads send only the signal hash. `Signal::from_string`
419+ // intentionally mirrors JS `hashSignal`, including decoding valid `0x`
420+ // strings as bytes so address signals match `abi.encodePacked(address)`.
419421 let legacy_signal_hash =
420422 crate :: crypto:: hash_signal ( & Signal :: from_string ( params. legacy_signal . clone ( ) ) ) ;
421423
@@ -1664,6 +1666,56 @@ mod tests {
16641666 assert ! ( payload_bridge. get( "timestamp" ) . is_none( ) ) ;
16651667 }
16661668
1669+ #[ test]
1670+ fn test_legacy_payload_hashes_address_shaped_signal_as_raw_bytes ( ) {
1671+ let address = "0x3df41d9d0ba00d8fbe5a9896bb01efc4b3787b7c" ;
1672+ let address_bytes = hex:: decode ( address. strip_prefix ( "0x" ) . unwrap ( ) ) . unwrap ( ) ;
1673+ let expected = crate :: crypto:: hash_signal ( & Signal :: from_bytes ( address_bytes) ) ;
1674+ let utf8_hash = crate :: crypto:: hash_signal ( & Signal :: from_bytes ( address. as_bytes ( ) ) ) ;
1675+
1676+ assert_ne ! ( expected, utf8_hash) ;
1677+ let app_id = AppId :: new ( "app_test" ) . unwrap ( ) ;
1678+ let sig = "0x" . to_string ( ) + & "00" . repeat ( 64 ) + "1b" ;
1679+ let rp_context = RpContext :: new (
1680+ "rp_1234567890abcdef" ,
1681+ "0x0000000000000000000000000000000000000000000000000000000000000001" ,
1682+ 1_700_000_000 ,
1683+ 1_700_003_600 ,
1684+ & sig,
1685+ )
1686+ . unwrap ( ) ;
1687+
1688+ let params = BridgeConnectionParams {
1689+ app_id,
1690+ kind : RequestKind :: Uniqueness {
1691+ action : "my-action" . to_string ( ) ,
1692+ } ,
1693+ constraints : None ,
1694+ rp_context,
1695+ action_description : None ,
1696+ legacy_verification_level : VerificationLevel :: Orb ,
1697+ legacy_signal : address. to_string ( ) ,
1698+ bridge_url : None ,
1699+ allow_legacy_proofs : false ,
1700+
1701+ override_connect_base_url : None ,
1702+ return_to : None ,
1703+ environment : None ,
1704+ } ;
1705+
1706+ let cached = CachedSignalHashes :: compute ( & params) ;
1707+ assert_eq ! ( cached. legacy_signal_hash, expected) ;
1708+
1709+ let bridge_payload = build_request_payload ( & params, false ) . unwrap ( ) ;
1710+ assert_eq ! ( bridge_payload[ "signal" ] , expected) ;
1711+
1712+ let native_payload = build_request_payload ( & params, true ) . unwrap ( ) ;
1713+ assert_eq ! ( native_payload[ "signal" ] , expected) ;
1714+
1715+ let native_v1_payload = build_native_v1_payload ( & params) . unwrap ( ) ;
1716+ assert_eq ! ( native_v1_payload[ "signal" ] , expected) ;
1717+ }
1718+
16671719 fn sample_connection ( return_to : Option < String > ) -> BridgeConnection {
16681720 BridgeConnection {
16691721 bridge_url : BridgeUrl :: default ( ) ,
0 commit comments