@@ -7,13 +7,13 @@ use mina_p2p_messages::v2::MinaBaseUserCommandStableV2;
77use mina_p2p_messages:: v2:: MinaBaseZkappCommandTStableV1WireStableV1 ;
88use mina_p2p_messages:: v2:: TokenIdKeyHash ;
99use node:: rpc:: RpcTransactionInjectResponse ;
10- use node:: rpc:: RpcTransactionInjectedCommand ;
1110use node:: rpc:: { GetBlockQuery , RpcGetBlockResponse , RpcTransactionStatusGetResponse } ;
1211use node:: {
1312 account:: AccountPublicKey ,
1413 rpc:: { AccountQuery , RpcRequest , RpcSyncStatsGetResponse , SyncStatsQuery } ,
1514 stats:: sync:: SyncKind ,
1615} ;
16+ use o1_utils:: field_helpers:: FieldHelpersError ;
1717use openmina_core:: block:: AppliedBlock ;
1818use openmina_core:: consensus:: ConsensusConstants ;
1919use openmina_core:: constants:: constraint_constants;
@@ -26,6 +26,7 @@ pub mod account;
2626pub mod block;
2727pub mod constants;
2828pub mod transaction;
29+ pub mod user_command;
2930pub mod zkapp;
3031
3132#[ derive( Debug , thiserror:: Error ) ]
@@ -54,6 +55,8 @@ pub enum ConversionError {
5455 InvalidDecimalNumber ( #[ from] mina_p2p_messages:: bigint:: InvalidDecimalNumber ) ,
5556 #[ error( "Invalid bigint" ) ]
5657 InvalidBigInt ,
58+ #[ error( "Invalid hex" ) ]
59+ InvalidHex ,
5760 #[ error( transparent) ]
5861 ParseInt ( #[ from] std:: num:: ParseIntError ) ,
5962 #[ error( transparent) ]
@@ -66,6 +69,14 @@ pub enum ConversionError {
6669 InvalidLength ,
6770 #[ error( "Custom: {0}" ) ]
6871 Custom ( String ) ,
72+ #[ error( transparent) ]
73+ FieldHelpers ( #[ from] FieldHelpersError ) ,
74+ }
75+
76+ impl From < ConversionError > for Error {
77+ fn from ( value : ConversionError ) -> Self {
78+ Error :: Conversion ( value)
79+ }
6980}
7081
7182struct Context ( RpcSender ) ;
@@ -310,6 +321,56 @@ impl Query {
310321 }
311322}
312323
324+ async fn inject_tx < R > (
325+ cmd : MinaBaseUserCommandStableV2 ,
326+ context : & Context ,
327+ ) -> juniper:: FieldResult < R >
328+ where
329+ R : TryFrom < MinaBaseUserCommandStableV2 > ,
330+ {
331+ let res: RpcTransactionInjectResponse = context
332+ . 0
333+ . oneshot_request ( RpcRequest :: TransactionInject ( vec ! [ cmd] ) )
334+ . await
335+ . ok_or ( Error :: StateMachineEmptyResponse ) ?;
336+
337+ match res {
338+ RpcTransactionInjectResponse :: Success ( res) => {
339+ let cmd: MinaBaseUserCommandStableV2 = match res. first ( ) . cloned ( ) {
340+ Some ( cmd) => cmd. into ( ) ,
341+ _ => unreachable ! ( ) ,
342+ } ;
343+ cmd. try_into ( ) . map_err ( |_| {
344+ FieldError :: new (
345+ "Failed to convert transaction to the required type" . to_string ( ) ,
346+ graphql_value ! ( null) ,
347+ )
348+ } )
349+ }
350+ RpcTransactionInjectResponse :: Rejected ( rejected) => {
351+ let error_list = rejected
352+ . into_iter ( )
353+ . map ( |( _, err) | graphql_value ! ( { "message" : err. to_string( ) } ) )
354+ . collect :: < Vec < _ > > ( ) ;
355+
356+ Err ( FieldError :: new (
357+ "Transaction rejected" ,
358+ graphql_value ! ( juniper:: Value :: List ( error_list) ) ,
359+ ) )
360+ }
361+ RpcTransactionInjectResponse :: Failure ( failure) => {
362+ let error_list = failure
363+ . into_iter ( )
364+ . map ( |err| graphql_value ! ( { "message" : err. to_string( ) } ) )
365+ . collect :: < Vec < _ > > ( ) ;
366+
367+ Err ( FieldError :: new (
368+ "Transaction failed" ,
369+ graphql_value ! ( juniper:: Value :: List ( error_list) ) ,
370+ ) )
371+ }
372+ }
373+ }
313374#[ derive( Clone , Debug ) ]
314375struct Mutation ;
315376
@@ -319,43 +380,64 @@ impl Mutation {
319380 input : zkapp:: SendZkappInput ,
320381 context : & Context ,
321382 ) -> juniper:: FieldResult < zkapp:: GraphQLSendZkappResponse > {
322- let res: RpcTransactionInjectResponse = context
383+ inject_tx ( input. try_into ( ) ?, context) . await
384+ }
385+
386+ async fn send_payment (
387+ input : user_command:: InputGraphQLPayment ,
388+ signature : user_command:: UserCommandSignature ,
389+ context : & Context ,
390+ ) -> juniper:: FieldResult < user_command:: GraphQLSendPaymentResponse > {
391+ // Grab the sender's account to get the infered nonce
392+ let token_id = TokenIdKeyHash :: default ( ) ;
393+ let public_key = AccountPublicKey :: from_str ( & input. from )
394+ . map_err ( |e| Error :: Conversion ( ConversionError :: Base58Check ( e) ) ) ?;
395+
396+ let accounts: Vec < Account > = context
323397 . 0
324- . oneshot_request ( RpcRequest :: TransactionInject ( vec ! [ input. try_into( ) ?] ) )
398+ . oneshot_request ( RpcRequest :: LedgerAccountsGet (
399+ AccountQuery :: PubKeyWithTokenId ( public_key, token_id) ,
400+ ) )
325401 . await
326402 . ok_or ( Error :: StateMachineEmptyResponse ) ?;
327403
328- match res {
329- RpcTransactionInjectResponse :: Success ( res) => {
330- let zkapp_cmd: MinaBaseUserCommandStableV2 = match res. first ( ) . cloned ( ) {
331- Some ( RpcTransactionInjectedCommand :: Zkapp ( zkapp_cmd) ) => zkapp_cmd. into ( ) ,
332- _ => unreachable ! ( ) ,
333- } ;
334- Ok ( zkapp_cmd. try_into ( ) ?)
335- }
336- RpcTransactionInjectResponse :: Rejected ( rejected) => {
337- let error_list = rejected
338- . into_iter ( )
339- . map ( |( _, err) | graphql_value ! ( { "message" : err. to_string( ) } ) )
340- . collect :: < Vec < _ > > ( ) ;
341-
342- Err ( FieldError :: new (
343- "Transaction rejected" ,
344- graphql_value ! ( juniper:: Value :: List ( error_list) ) ,
345- ) )
346- }
347- RpcTransactionInjectResponse :: Failure ( failure) => {
348- let error_list = failure
349- . into_iter ( )
350- . map ( |err| graphql_value ! ( { "message" : err. to_string( ) } ) )
351- . collect :: < Vec < _ > > ( ) ;
352-
353- Err ( FieldError :: new (
354- "Transaction failed" ,
355- graphql_value ! ( juniper:: Value :: List ( error_list) ) ,
356- ) )
357- }
358- }
404+ let infered_nonce = accounts
405+ . first ( )
406+ . ok_or ( Error :: StateMachineEmptyResponse ) ?
407+ . nonce ;
408+
409+ let command = input
410+ . create_user_command ( infered_nonce, signature)
411+ . map_err ( Error :: Conversion ) ?;
412+
413+ inject_tx ( command, context) . await
414+ }
415+
416+ async fn send_delegation (
417+ input : user_command:: InputGraphQLDelegation ,
418+ signature : user_command:: UserCommandSignature ,
419+ context : & Context ,
420+ ) -> juniper:: FieldResult < user_command:: GraphQLSendDelegationResponse > {
421+ // Payment commands are always for the default (MINA) token
422+ let token_id = TokenIdKeyHash :: default ( ) ;
423+ let public_key = AccountPublicKey :: from_str ( & input. from ) ?;
424+
425+ // Grab the sender's account to get the infered nonce
426+ let accounts: Vec < Account > = context
427+ . 0
428+ . oneshot_request ( RpcRequest :: LedgerAccountsGet (
429+ AccountQuery :: PubKeyWithTokenId ( public_key, token_id) ,
430+ ) )
431+ . await
432+ . ok_or ( Error :: StateMachineEmptyResponse ) ?;
433+
434+ let infered_nonce = accounts
435+ . first ( )
436+ . ok_or ( Error :: StateMachineEmptyResponse ) ?
437+ . nonce ;
438+ let command = input. create_user_command ( infered_nonce, signature) ?;
439+
440+ inject_tx ( command, context) . await
359441 }
360442}
361443
0 commit comments