@@ -645,13 +645,15 @@ impl PlatformRuntimeHost {
645645 & self ,
646646 session : & SessionInfo ,
647647 signer : & str ,
648- ) -> Result < ( ) , v01:: HostSignPayloadError > {
648+ ) -> Result < [ u8 ; 32 ] , v01:: HostSignPayloadError > {
649649 let public_key = self
650650 . legacy_slot_zero_public_key ( session)
651651 . map_err ( |reason| v01:: HostSignPayloadError :: Unknown { reason } ) ?;
652652 let expected = product_public_key_to_address ( public_key) ;
653- if expected == signer {
654- Ok ( ( ) )
653+ if expected == signer
654+ || parse_legacy_signer_hex ( signer) . is_some_and ( |key| key == public_key)
655+ {
656+ Ok ( public_key)
655657 } else {
656658 Err ( v01:: HostSignPayloadError :: Unknown {
657659 reason : "Account can't be derived from product account id" . to_string ( ) ,
@@ -677,6 +679,17 @@ impl PlatformRuntimeHost {
677679 }
678680}
679681
682+ fn parse_legacy_signer_hex ( signer : & str ) -> Option < [ u8 ; 32 ] > {
683+ let raw = signer
684+ . strip_prefix ( "0x" )
685+ . or_else ( || signer. strip_prefix ( "0X" ) )
686+ . unwrap_or ( signer) ;
687+ if raw. len ( ) != 64 {
688+ return None ;
689+ }
690+ hex:: decode ( raw) . ok ( ) ?. try_into ( ) . ok ( )
691+ }
692+
680693/// Adapter from `truapi_platform::ChainProvider` into the
681694/// [`RuntimeChainProvider`] surface the chain runtime expects.
682695/// Reuses the platform-supplied json-rpc connection and converts the
@@ -3012,11 +3025,60 @@ mod tests {
30123025 crate :: host_logic:: sso:: messages:: RemoteMessageV1 :: SignRequest ( request)
30133026 ) if matches!(
30143027 request. as_ref( ) ,
3015- crate :: host_logic:: sso:: messages:: SigningRequest :: Raw ( _)
3028+ crate :: host_logic:: sso:: messages:: SigningRequest :: Raw ( raw)
3029+ if raw. product_account_id == account_id( "myapp.dot" , 0 )
3030+ && matches!(
3031+ & raw. data,
3032+ crate :: host_logic:: sso:: messages:: SigningRawPayload :: Bytes ( bytes)
3033+ if bytes == b"hello"
3034+ )
30163035 )
30173036 ) ) ;
30183037 }
30193038
3039+ #[ test]
3040+ fn legacy_sign_raw_accepts_derived_hex_then_returns_sso_response ( ) {
3041+ let session = sso_session_info ( ) ;
3042+ let signer = derive_product_public_key ( session. public_key , "myapp.dot" , 0 ) . unwrap ( ) ;
3043+ let platform = Arc :: new ( StubPlatform {
3044+ sign_raw_confirmed : true ,
3045+ rpc_responses : sso_success_responses (
3046+ & session,
3047+ "legacy-sign-raw-hex-1" ,
3048+ sign_response_message ( "legacy-sign-raw-hex-1" , vec ! [ 8 , 8 ] , None ) ,
3049+ ) ,
3050+ ..Default :: default ( )
3051+ } ) ;
3052+ let host = PlatformRuntimeHost :: new (
3053+ platform. clone ( ) ,
3054+ runtime_config ( "myapp.dot" ) ,
3055+ test_spawner ( ) ,
3056+ ) ;
3057+ host. session_state ( ) . set_session ( session. clone ( ) ) ;
3058+ let cx = CallContext :: with_request_id ( "legacy-sign-raw-hex-1" . to_string ( ) ) ;
3059+ let request =
3060+ HostSignRawWithLegacyAccountRequest :: V1 ( v01:: HostSignRawWithLegacyAccountRequest {
3061+ signer : format ! ( "0x{}" , hex:: encode( signer) ) ,
3062+ payload : raw_payload ( ) ,
3063+ } ) ;
3064+ let response =
3065+ futures:: executor:: block_on ( host. sign_raw_with_legacy_account ( & cx, request) ) . unwrap ( ) ;
3066+ let HostSignRawWithLegacyAccountResponse :: V1 ( inner) = response;
3067+ assert_eq ! ( inner. signature, vec![ 8 , 8 ] ) ;
3068+
3069+ let message = submitted_remote_message ( & platform, & session) ;
3070+ let crate :: host_logic:: sso:: messages:: RemoteMessageData :: V1 (
3071+ crate :: host_logic:: sso:: messages:: RemoteMessageV1 :: SignRequest ( request) ,
3072+ ) = message. data
3073+ else {
3074+ panic ! ( "expected raw signing request" ) ;
3075+ } ;
3076+ let crate :: host_logic:: sso:: messages:: SigningRequest :: Raw ( request) = * request else {
3077+ panic ! ( "expected raw signing request" ) ;
3078+ } ;
3079+ assert_eq ! ( request. product_account_id, account_id( "myapp.dot" , 0 ) ) ;
3080+ }
3081+
30203082 #[ test]
30213083 fn legacy_create_transaction_rejects_raw_key_mismatch ( ) {
30223084 let host =
@@ -3042,6 +3104,67 @@ mod tests {
30423104 }
30433105 }
30443106
3107+ #[ test]
3108+ fn legacy_create_transaction_accepts_derived_key_then_returns_sso_response ( ) {
3109+ let session = sso_session_info ( ) ;
3110+ let signer = derive_product_public_key ( session. public_key , "myapp.dot" , 0 ) . unwrap ( ) ;
3111+ let platform = Arc :: new ( StubPlatform {
3112+ create_transaction_confirmed : true ,
3113+ rpc_responses : sso_success_responses (
3114+ & session,
3115+ "legacy-create-tx-1" ,
3116+ crate :: host_logic:: sso:: messages:: RemoteMessage {
3117+ message_id : "wallet-legacy-create-tx-1" . to_string ( ) ,
3118+ data : crate :: host_logic:: sso:: messages:: RemoteMessageData :: V1 (
3119+ crate :: host_logic:: sso:: messages:: RemoteMessageV1 :: CreateTransactionResponse (
3120+ crate :: host_logic:: sso:: messages:: CreateTransactionResponse {
3121+ responding_to : "legacy-create-tx-1" . to_string ( ) ,
3122+ signed_transaction : Ok ( vec ! [ 0xca , 0xfe ] ) ,
3123+ } ,
3124+ ) ,
3125+ ) ,
3126+ } ,
3127+ ) ,
3128+ ..Default :: default ( )
3129+ } ) ;
3130+ let host = PlatformRuntimeHost :: new (
3131+ platform. clone ( ) ,
3132+ runtime_config ( "myapp.dot" ) ,
3133+ test_spawner ( ) ,
3134+ ) ;
3135+ host. session_state ( ) . set_session ( session. clone ( ) ) ;
3136+ let cx = CallContext :: with_request_id ( "legacy-create-tx-1" . to_string ( ) ) ;
3137+ let request =
3138+ HostCreateTransactionWithLegacyAccountRequest :: V1 ( v01:: LegacyAccountTxPayload {
3139+ signer,
3140+ genesis_hash : [ 1 ; 32 ] ,
3141+ call_data : vec ! [ 0 ] ,
3142+ extensions : vec ! [ ] ,
3143+ tx_ext_version : 0 ,
3144+ } ) ;
3145+
3146+ let response =
3147+ futures:: executor:: block_on ( host. create_transaction_with_legacy_account ( & cx, request) )
3148+ . unwrap ( ) ;
3149+
3150+ let HostCreateTransactionWithLegacyAccountResponse :: V1 ( inner) = response;
3151+ assert_eq ! ( inner. transaction, vec![ 0xca , 0xfe ] ) ;
3152+ let message = submitted_remote_message ( & platform, & session) ;
3153+ let crate :: host_logic:: sso:: messages:: RemoteMessageData :: V1 (
3154+ crate :: host_logic:: sso:: messages:: RemoteMessageV1 :: CreateTransactionRequest ( request) ,
3155+ ) = message. data
3156+ else {
3157+ panic ! ( "expected product transaction request" ) ;
3158+ } ;
3159+ let crate :: host_logic:: sso:: messages:: CreateTransactionPayload :: V1 ( payload) =
3160+ request. payload ;
3161+ assert_eq ! ( payload. signer, account_id( "myapp.dot" , 0 ) ) ;
3162+ assert_eq ! (
3163+ signer,
3164+ derive_product_public_key( session. public_key, "myapp.dot" , 0 ) . unwrap( )
3165+ ) ;
3166+ }
3167+
30453168 #[ test]
30463169 fn create_transaction_rejects_invalid_product_account ( ) {
30473170 let host =
0 commit comments