@@ -7,13 +7,13 @@ use mina_p2p_messages::v2::MinaBaseUserCommandStableV2;
7
7
use mina_p2p_messages:: v2:: MinaBaseZkappCommandTStableV1WireStableV1 ;
8
8
use mina_p2p_messages:: v2:: TokenIdKeyHash ;
9
9
use node:: rpc:: RpcTransactionInjectResponse ;
10
- use node:: rpc:: RpcTransactionInjectedCommand ;
11
10
use node:: rpc:: { GetBlockQuery , RpcGetBlockResponse , RpcTransactionStatusGetResponse } ;
12
11
use node:: {
13
12
account:: AccountPublicKey ,
14
13
rpc:: { AccountQuery , RpcRequest , RpcSyncStatsGetResponse , SyncStatsQuery } ,
15
14
stats:: sync:: SyncKind ,
16
15
} ;
16
+ use o1_utils:: field_helpers:: FieldHelpersError ;
17
17
use openmina_core:: block:: AppliedBlock ;
18
18
use openmina_core:: consensus:: ConsensusConstants ;
19
19
use openmina_core:: constants:: constraint_constants;
@@ -26,6 +26,7 @@ pub mod account;
26
26
pub mod block;
27
27
pub mod constants;
28
28
pub mod transaction;
29
+ pub mod user_command;
29
30
pub mod zkapp;
30
31
31
32
#[ derive( Debug , thiserror:: Error ) ]
@@ -54,6 +55,8 @@ pub enum ConversionError {
54
55
InvalidDecimalNumber ( #[ from] mina_p2p_messages:: bigint:: InvalidDecimalNumber ) ,
55
56
#[ error( "Invalid bigint" ) ]
56
57
InvalidBigInt ,
58
+ #[ error( "Invalid hex" ) ]
59
+ InvalidHex ,
57
60
#[ error( transparent) ]
58
61
ParseInt ( #[ from] std:: num:: ParseIntError ) ,
59
62
#[ error( transparent) ]
@@ -66,6 +69,14 @@ pub enum ConversionError {
66
69
InvalidLength ,
67
70
#[ error( "Custom: {0}" ) ]
68
71
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
+ }
69
80
}
70
81
71
82
struct Context ( RpcSender ) ;
@@ -310,6 +321,56 @@ impl Query {
310
321
}
311
322
}
312
323
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
+ }
313
374
#[ derive( Clone , Debug ) ]
314
375
struct Mutation ;
315
376
@@ -319,43 +380,64 @@ impl Mutation {
319
380
input : zkapp:: SendZkappInput ,
320
381
context : & Context ,
321
382
) -> 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
323
397
. 0
324
- . oneshot_request ( RpcRequest :: TransactionInject ( vec ! [ input. try_into( ) ?] ) )
398
+ . oneshot_request ( RpcRequest :: LedgerAccountsGet (
399
+ AccountQuery :: PubKeyWithTokenId ( public_key, token_id) ,
400
+ ) )
325
401
. await
326
402
. ok_or ( Error :: StateMachineEmptyResponse ) ?;
327
403
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
359
441
}
360
442
}
361
443
0 commit comments