@@ -372,7 +372,7 @@ impl AccountInfo {
372372 let secp256k1blob = CheckSecp256k1 :: new ( calldata, nonce. to_string ( ) . as_bytes ( ) ) . expect ( ) ?;
373373 let public_key = hex:: encode ( secp256k1blob. public_key ) ;
374374
375- self . verify_and_update_nonce ( nonce) ?;
375+ self . verify_and_update_nonce ( nonce, calldata ) ?;
376376
377377 self . use_session_key ( public_key, calldata)
378378 }
@@ -389,7 +389,7 @@ impl AccountInfo {
389389 if self . identity != account {
390390 return Err ( "Account does not match registered identity" . to_string ( ) ) ;
391391 }
392- self . verify_and_update_nonce ( nonce)
392+ self . verify_and_update_nonce ( nonce, calldata )
393393 }
394394 WalletAction :: AddSessionKey {
395395 account,
@@ -402,7 +402,7 @@ impl AccountInfo {
402402 // Verify identity before executing the action
403403 self . auth_method . verify ( calldata, nonce) ?;
404404
405- self . verify_and_update_nonce ( nonce) ?;
405+ self . verify_and_update_nonce ( nonce, calldata ) ?;
406406
407407 if self . identity != account {
408408 return Err ( "Account does not match registered identity" . to_string ( ) ) ;
@@ -413,13 +413,46 @@ impl AccountInfo {
413413 // Verify identity before executing the action
414414 self . auth_method . verify ( calldata, nonce) ?;
415415
416- self . verify_and_update_nonce ( nonce) ?;
416+ self . verify_and_update_nonce ( nonce, calldata ) ?;
417417
418418 self . remove_session_key ( key)
419419 }
420420 _ => unreachable ! ( ) ,
421421 }
422422 }
423+
424+ /// Helper function to check if a VerifyIdentity action exists in previous blobs for the same user
425+ fn check_verify_identity_in_previous_blobs (
426+ & self ,
427+ calldata : & sdk:: Calldata ,
428+ expected_account : & str ,
429+ ) -> Result < ( ) , String > {
430+ // Iterate through blobs before the current one
431+ for ( blob_index, blob) in & calldata. blobs {
432+ // Skip the current blob and any after it
433+ if blob_index >= & calldata. index {
434+ break ;
435+ }
436+
437+ // Check if this is a wallet blob
438+ if blob. contract_name . 0 == "wallet" {
439+ // Try to decode the blob as a WalletAction
440+ if let Ok (
441+ WalletAction :: VerifyIdentity { account, .. }
442+ | WalletAction :: RegisterIdentity { account, .. } ,
443+ ) = WalletAction :: from_blob_data ( & blob. data )
444+ {
445+ if account == expected_account {
446+ return Ok ( ( ) ) ;
447+ }
448+ }
449+ }
450+ }
451+
452+ Err ( format ! (
453+ "No action that proves identity found in previous blobs for account: {expected_account}. calldata.blobs: {:?}" , calldata. blobs
454+ ) )
455+ }
423456}
424457
425458/// State management methods for the Wallet contract
@@ -442,10 +475,19 @@ impl AccountInfo {
442475 Ok ( ret)
443476 }
444477
445- fn verify_and_update_nonce ( & mut self , nonce : u128 ) -> Result < String , String > {
446- if nonce <= self . nonce {
478+ fn verify_and_update_nonce (
479+ & mut self ,
480+ nonce : u128 ,
481+ calldata : & sdk:: Calldata ,
482+ ) -> Result < String , String > {
483+ if nonce < self . nonce {
447484 return Err ( "Invalid nonce" . to_string ( ) ) ;
448485 }
486+ if nonce == self . nonce {
487+ // Check if there's a VerifyIdentity action in previous blobs for this user
488+ self . check_verify_identity_in_previous_blobs ( calldata, & self . identity ) ?;
489+ return Ok ( "Identity verified" . to_string ( ) ) ;
490+ }
449491 self . nonce = nonce;
450492 Ok ( "Identity verified" . to_string ( ) )
451493 }
@@ -1004,4 +1046,127 @@ mod tests {
10041046 . handle ( register_call)
10051047 . expect ( "Failed to handle register call" ) ;
10061048 }
1049+
1050+ #[ test]
1051+ fn test_check_verify_identity_in_previous_blobs ( ) {
1052+ let nonce = 1769086402327 ;
1053+ // Test based on the image showing 3 blobs with bob identity
1054+ let account_info = AccountInfo {
1055+ identity : "bob" . to_string ( ) ,
1056+ auth_method : AuthMethod :: Ethereum {
1057+ address : "0x6853cc7d35451325053706ad5f188df79f0387c" . to_string ( ) ,
1058+ } ,
1059+ session_keys : vec ! [ ] ,
1060+ nonce,
1061+ } ;
1062+
1063+ // Create blob #0 - secp256k1 blob (from image)
1064+ let secp256k1_blob = Blob {
1065+ contract_name : sdk:: ContractName ( "secp256k1" . to_string ( ) ) ,
1066+ data : sdk:: BlobData ( vec ! [ /* secp256k1 data would go here */ ] ) ,
1067+ } ;
1068+
1069+ // Create blob #1 - secp256k1 blob (from image)
1070+ let secp256k1_blob2 = Blob {
1071+ contract_name : sdk:: ContractName ( "secp256k1" . to_string ( ) ) ,
1072+ data : sdk:: BlobData ( vec ! [ /* secp256k1 data would go here */ ] ) ,
1073+ } ;
1074+
1075+ // Create blob #2 - RegisterIdentity action for bob (from image)
1076+ let register_identity_blob = WalletAction :: RegisterIdentity {
1077+ account : "bob" . to_string ( ) ,
1078+ nonce,
1079+ salt : "***" . to_string ( ) ,
1080+ auth_method : AuthMethod :: Ethereum {
1081+ address : "0x6853cc7d35451325053706ad5f188df79f0387c" . to_string ( ) ,
1082+ } ,
1083+ invite_code : "***" . to_string ( ) ,
1084+ }
1085+ . as_blob ( sdk:: ContractName ( "wallet" . to_string ( ) ) ) ;
1086+
1087+ // Create blob #3 - AddSessionKey action for bob (from image)
1088+ let add_session_key_blob = WalletAction :: AddSessionKey {
1089+ account : "bob" . to_string ( ) ,
1090+ key : "0288fb774209924f7ea2221bf136919b3765d662f6d1d93c36c2ef0b8c3b71db6" . to_string ( ) ,
1091+ expiration_date : 1769945603806 ,
1092+ whitelist : None ,
1093+ lane_id : None ,
1094+ nonce,
1095+ }
1096+ . as_blob ( sdk:: ContractName ( "wallet" . to_string ( ) ) ) ;
1097+
1098+ // Test case 1: Current blob is #3, should find RegisterIdentity in blob #2
1099+ let calldata_with_register = Calldata {
1100+ blobs : IndexedBlobs :: from ( vec ! [
1101+ secp256k1_blob. clone( ) ,
1102+ secp256k1_blob2. clone( ) ,
1103+ register_identity_blob. clone( ) ,
1104+ add_session_key_blob. clone( ) ,
1105+ ] ) ,
1106+ index : BlobIndex ( 3 ) , // Current blob is #3 (AddSessionKey)
1107+ identity : "bob" . into ( ) ,
1108+ ..Default :: default ( )
1109+ } ;
1110+
1111+ // Should succeed because RegisterIdentity for bob exists in blob #2
1112+ let result =
1113+ account_info. check_verify_identity_in_previous_blobs ( & calldata_with_register, "bob" ) ;
1114+ assert ! (
1115+ result. is_ok( ) ,
1116+ "Should find RegisterIdentity in previous blobs"
1117+ ) ;
1118+
1119+ // Test case 2: Current blob is #2, should not find any previous identity proof
1120+ let calldata_current_register = Calldata {
1121+ blobs : IndexedBlobs :: from ( vec ! [
1122+ secp256k1_blob. clone( ) ,
1123+ secp256k1_blob2. clone( ) ,
1124+ register_identity_blob. clone( ) ,
1125+ add_session_key_blob. clone( ) ,
1126+ ] ) ,
1127+ index : BlobIndex ( 2 ) , // Current blob is #2 (RegisterIdentity)
1128+ identity : "bob" . into ( ) ,
1129+ ..Default :: default ( )
1130+ } ;
1131+
1132+ // Should fail because no previous identity proof exists before blob #2
1133+ let result =
1134+ account_info. check_verify_identity_in_previous_blobs ( & calldata_current_register, "bob" ) ;
1135+ assert ! (
1136+ result. is_err( ) ,
1137+ "Should not find identity proof in previous blobs"
1138+ ) ;
1139+
1140+ // Test case 3: Wrong account name
1141+ let result = account_info
1142+ . check_verify_identity_in_previous_blobs ( & calldata_with_register, "wrongAccount" ) ;
1143+ assert ! ( result. is_err( ) , "Should fail with wrong account name" ) ;
1144+
1145+ // Test case 4: Test with VerifyIdentity action instead of RegisterIdentity
1146+ let verify_identity_blob = WalletAction :: VerifyIdentity {
1147+ account : "bob" . to_string ( ) ,
1148+ nonce,
1149+ }
1150+ . as_blob ( sdk:: ContractName ( "wallet" . to_string ( ) ) ) ;
1151+
1152+ let calldata_with_verify = Calldata {
1153+ blobs : IndexedBlobs :: from ( vec ! [
1154+ secp256k1_blob. clone( ) ,
1155+ secp256k1_blob2. clone( ) ,
1156+ verify_identity_blob. clone( ) ,
1157+ add_session_key_blob. clone( ) ,
1158+ ] ) ,
1159+ index : BlobIndex ( 3 ) , // Current blob is #3
1160+ identity : "bob" . into ( ) ,
1161+ ..Default :: default ( )
1162+ } ;
1163+
1164+ // Should succeed because VerifyIdentity for bob exists in blob #2
1165+ let result =
1166+ account_info. check_verify_identity_in_previous_blobs ( & calldata_with_verify, "bob" ) ;
1167+ assert ! (
1168+ result. is_ok( ) ,
1169+ "Should find VerifyIdentity in previous blobs"
1170+ ) ;
1171+ }
10071172}
0 commit comments