@@ -76,7 +76,13 @@ pub mod tests {
7676 } ,
7777 } ,
7878 modular_smart_account:: {
79- deploy:: { DeployAccountParams , EOASigners , deploy_account} ,
79+ deploy:: {
80+ DeployAccountParams , EOASigners , deploy_account,
81+ user_op:: {
82+ DeployAccountWithUserOpParams ,
83+ deploy_account_with_user_op,
84+ } ,
85+ } ,
8086 passkey:: add:: {
8187 AddPasskeyParams , PasskeyPayload , add_passkey,
8288 } ,
@@ -88,6 +94,7 @@ pub mod tests {
8894 contract:: EntryPoint :: PackedUserOperation ,
8995 nonce:: { GetNonceWithKeyParams , get_nonce_with_key} ,
9096 } ,
97+ paymaster:: mock_paymaster:: deploy_mock_paymaster_and_deposit_amount,
9198 signer:: { create_eoa_signer, test_utils:: get_signature_from_js} ,
9299 user_operation:: hash:: user_operation_hash:: get_user_operation_hash_entry_point,
93100 } ,
@@ -98,6 +105,7 @@ pub mod tests {
98105 } ;
99106 use alloy:: {
100107 primitives:: { Bytes , U256 , Uint , address, bytes, fixed_bytes} ,
108+ providers:: ProviderBuilder ,
101109 rpc:: types:: {
102110 TransactionRequest ,
103111 erc4337:: PackedUserOperation as AlloyPackedUserOperation ,
@@ -259,6 +267,157 @@ pub mod tests {
259267 Ok ( ( ) )
260268 }
261269
270+ #[ tokio:: test]
271+ async fn test_send_transaction_webauthn_sponsored ( ) -> eyre:: Result < ( ) > {
272+ let (
273+ node_url,
274+ anvil_instance,
275+ provider,
276+ contracts,
277+ signer_private_key,
278+ bundler,
279+ bundler_client,
280+ ) = {
281+ let signer_private_key = "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6" . to_string ( ) ;
282+ start_anvil_and_deploy_contracts_and_start_bundler_with_config (
283+ & TestInfraConfig {
284+ signer_private_key : signer_private_key. clone ( ) ,
285+ } ,
286+ )
287+ . await ?
288+ } ;
289+
290+ let unfunded_provider =
291+ ProviderBuilder :: new ( ) . connect_http ( node_url. clone ( ) ) ;
292+
293+ let factory_address = contracts. account_factory ;
294+ let eoa_validator_address = contracts. eoa_validator ;
295+
296+ let entry_point_address =
297+ address ! ( "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108" ) ;
298+
299+ let eoa_signer_address =
300+ address ! ( "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720" ) ;
301+
302+ let ( mock_paymaster, paymaster_address) =
303+ deploy_mock_paymaster_and_deposit_amount (
304+ U256 :: from ( 1_000_000_000_000_000_000u64 ) ,
305+ provider. clone ( ) ,
306+ )
307+ . await ?;
308+ let paymaster = PaymasterParams :: default_paymaster ( paymaster_address) ;
309+ let paymaster_params = Some ( paymaster) ;
310+
311+ let signers = vec ! [ eoa_signer_address] ;
312+
313+ let eoa_signers = EOASigners {
314+ addresses : signers,
315+ validator_address : eoa_validator_address,
316+ } ;
317+
318+ let signer = create_eoa_signer (
319+ signer_private_key. clone ( ) ,
320+ eoa_validator_address,
321+ ) ?;
322+
323+ let address =
324+ deploy_account_with_user_op ( DeployAccountWithUserOpParams {
325+ deploy_params : DeployAccountParams {
326+ factory_address,
327+ eoa_signers : Some ( eoa_signers) ,
328+ webauthn_signer : None ,
329+ session_validator : None ,
330+ id : None ,
331+ provider : unfunded_provider. clone ( ) ,
332+ } ,
333+ entry_point_address,
334+ bundler_client : bundler_client. clone ( ) ,
335+ signer,
336+ paymaster : paymaster_params. clone ( ) ,
337+ nonce_key : None ,
338+ } )
339+ . await ?;
340+
341+ println ! ( "Account deployed" ) ;
342+
343+ fund_account_with_default_amount ( address, provider. clone ( ) ) . await ?;
344+
345+ let webauthn_module = contracts. webauthn_validator ;
346+
347+ let signer = create_eoa_signer (
348+ signer_private_key. clone ( ) ,
349+ eoa_validator_address,
350+ ) ?;
351+
352+ add_module ( AddModuleParams {
353+ account_address : address,
354+ module : AddModulePayload :: webauthn ( webauthn_module) ,
355+ entry_point_address,
356+ paymaster : paymaster_params. clone ( ) ,
357+ provider : unfunded_provider. clone ( ) ,
358+ bundler_client : bundler_client. clone ( ) ,
359+ signer : signer. clone ( ) ,
360+ } )
361+ . await ?;
362+
363+ let credential_id = bytes ! ( "0x2868baa08431052f6c7541392a458f64" ) ;
364+ let passkey = [
365+ fixed_bytes ! (
366+ "0xe0a43b9c64a2357ea7f66a0551f57442fbd32031162d9be762800864168fae40"
367+ ) ,
368+ fixed_bytes ! (
369+ "0x450875e2c28222e81eb25ae58d095a3e7ca295faa3fc26fb0e558a0b571da501"
370+ ) ,
371+ ] ;
372+ let origin_domain = "https://example.com" . to_string ( ) ;
373+
374+ let passkey = PasskeyPayload { credential_id, passkey, origin_domain } ;
375+
376+ add_passkey ( AddPasskeyParams {
377+ account_address : address,
378+ passkey,
379+ webauthn_validator : webauthn_module,
380+ entry_point_address,
381+ paymaster : paymaster_params. clone ( ) ,
382+ provider : unfunded_provider. clone ( ) ,
383+ bundler_client : bundler_client. clone ( ) ,
384+ signer,
385+ } )
386+ . await ?;
387+
388+ println ! ( "Passkey successfully added" ) ;
389+
390+ // Send transaction using passkey signer
391+ let calldata = encoded_call_data ( address, None , Some ( U256 :: from ( 1 ) ) ) ;
392+
393+ let signature_provider: SignatureProvider =
394+ Arc :: new ( move |hash : FixedBytes < 32 > | {
395+ Box :: pin ( async move {
396+ let result = get_signature_from_js ( hash. to_string ( ) ) ?;
397+ Ok ( result)
398+ } )
399+ } ) ;
400+
401+ passkey_send_transaction ( PasskeySendParams {
402+ account : address,
403+ _webauthn_validator : webauthn_module,
404+ entry_point : entry_point_address,
405+ call_data : calldata,
406+ paymaster : paymaster_params. clone ( ) ,
407+ bundler_client,
408+ provider : unfunded_provider. clone ( ) ,
409+ signature_provider,
410+ } )
411+ . await ?;
412+
413+ println ! ( "Passkey transaction successfully sent" ) ;
414+
415+ drop ( mock_paymaster) ;
416+ drop ( anvil_instance) ;
417+ drop ( bundler) ;
418+ Ok ( ( ) )
419+ }
420+
262421 /// Test that mimics the WASM two-step flow:
263422 /// 1. Build UserOp and get hash
264423 /// 2. Sign hash with passkey (simulated)
0 commit comments