@@ -293,7 +293,7 @@ def test_delegates_post(self):
293293 data ["signature" ] = to_0x_hex_str (signature )
294294 response = self .client .post (url , format = "json" , data = data )
295295 self .assertIn (
296- f"Signature of type=CONTRACT_SIGNATURE for signer={ delegator .address } is not valid " ,
296+ f"No valid signature found for signer={ delegator .address } " ,
297297 response .data ["non_field_errors" ][0 ],
298298 )
299299 self .assertEqual (response .status_code , status .HTTP_400_BAD_REQUEST )
@@ -354,6 +354,79 @@ def test_delegate_creation_without_chain_id_with_safe(self):
354354 self .assertEqual (safe_contract_delegate .delegator , delegator .address )
355355 self .assertEqual (safe_contract_delegate .safe_contract_id , safe .address )
356356
357+ def _test_add_delegate_using_1271_signature (self , safe_deployment_fn ):
358+ account_a = Account .create ()
359+ account_b = Account .create ()
360+ safe_owner = safe_deployment_fn (
361+ owners = [account_a .address , account_b .address ], threshold = 2
362+ )
363+ SafeContractFactory (address = safe_owner .address )
364+
365+ nested_safe = safe_deployment_fn (owners = [safe_owner .address ])
366+ SafeContractFactory (address = nested_safe .address )
367+
368+ chain_id = self .ethereum_client .get_chain_id ()
369+ delegate = Account .create ()
370+
371+ _ , preimage_to_sign = DelegateSignatureHelperV2 .calculate_hash_and_preimage (
372+ delegate .address , chain_id , previous_totp = False
373+ )
374+
375+ safe_owner_message_hash , _ = safe_owner .get_message_hash_and_preimage (
376+ preimage_to_sign
377+ )
378+
379+ safe_owner_account_a_signature = account_a .unsafe_sign_hash (
380+ safe_owner_message_hash
381+ )["signature" ]
382+ safe_owner_account_b_signature = account_b .unsafe_sign_hash (
383+ safe_owner_message_hash
384+ )["signature" ]
385+
386+ # Build EIP1271 signature v=0 r=safe v=dynamic_part dynamic_part=size+owner_signature
387+ signatures_with_addresses = [
388+ (account_a .address .lower (), safe_owner_account_a_signature ),
389+ (account_b .address .lower (), safe_owner_account_b_signature ),
390+ ]
391+ signatures_with_addresses .sort (key = lambda x : x [0 ])
392+ ordered_signatures = b"" .join (sig for _ , sig in signatures_with_addresses )
393+
394+ signature_1271 = (
395+ signature_to_bytes (
396+ 0 , int .from_bytes (HexBytes (safe_owner .address ), byteorder = "big" ), 65
397+ )
398+ + eth_abi .encode (["bytes" ], [ordered_signatures ])[32 :]
399+ )
400+
401+ data = {
402+ "label" : "Nested safe delegator" ,
403+ "safe" : nested_safe .address ,
404+ "delegate" : delegate .address ,
405+ "delegator" : safe_owner .address ,
406+ "signature" : to_0x_hex_str (HexBytes (signature_1271 )),
407+ }
408+ response = self .client .post (
409+ reverse ("v2:history:delegates" ),
410+ format = "json" ,
411+ data = data ,
412+ )
413+ self .assertEqual (response .status_code , status .HTTP_201_CREATED )
414+ self .assertEqual (SafeContractDelegate .objects .count (), 1 )
415+ safe_contract_delegate = SafeContractDelegate .objects .get ()
416+ self .assertEqual (safe_contract_delegate .delegate , delegate .address )
417+ self .assertEqual (safe_contract_delegate .delegator , safe_owner .address )
418+ self .assertEqual (safe_contract_delegate .safe_contract_id , nested_safe .address )
419+
420+ def test_add_delegate_using_1271_signature_v1_3_0 (self ):
421+ return self ._test_add_delegate_using_1271_signature (
422+ self .deploy_test_safe_v1_3_0
423+ )
424+
425+ def test_add_delegate_using_1271_signature_v1_4_1 (self ):
426+ return self ._test_add_delegate_using_1271_signature (
427+ self .deploy_test_safe_v1_4_1
428+ )
429+
357430 def test_delegates_get (self ):
358431 url = reverse ("v2:history:delegates" )
359432 response = self .client .get (url , format = "json" )
0 commit comments