@@ -5,6 +5,7 @@ use crate::common::storage::types::{
55} ;
66use candid:: { Nat , Principal } ;
77use icrc_ledger_types:: icrc1:: account:: Account ;
8+ use icrc_ledger_types:: icrc122:: schema:: { BTYPE_122_BURN , BTYPE_122_MINT } ;
89use rusqlite:: { Connection , params} ;
910use tempfile:: tempdir;
1011
@@ -716,3 +717,250 @@ fn test_get_blocks_by_index_range_returns_ascending_order() {
716717 assert_eq ! ( retrieved[ 0 ] . index, 0 ) ;
717718 assert_eq ! ( retrieved[ 1 ] . index, 1 ) ;
718719}
720+
721+ // Helper function to create a test block with an AuthorizedMint operation
722+ fn create_test_authorized_mint_block (
723+ index : u64 ,
724+ timestamp : u64 ,
725+ principal : & [ u8 ] ,
726+ amount : u64 ,
727+ ) -> RosettaBlock {
728+ let account = Account {
729+ owner : Principal :: from_slice ( principal) ,
730+ subaccount : None ,
731+ } ;
732+
733+ let transaction = IcrcTransaction {
734+ operation : IcrcOperation :: AuthorizedMint {
735+ to : account,
736+ amount : Nat :: from ( amount) ,
737+ caller : Some ( Principal :: from_slice ( b"\x01 " ) ) ,
738+ mthd : Some ( "152mint" . to_string ( ) ) ,
739+ reason : Some ( "test" . to_string ( ) ) ,
740+ } ,
741+ memo : None ,
742+ created_at_time : Some ( timestamp) ,
743+ } ;
744+
745+ let icrc_block = IcrcBlock {
746+ parent_hash : None ,
747+ transaction,
748+ timestamp,
749+ effective_fee : None ,
750+ fee_collector : None ,
751+ fee_collector_block_index : None ,
752+ btype : Some ( BTYPE_122_MINT . to_string ( ) ) ,
753+ } ;
754+
755+ RosettaBlock {
756+ index,
757+ block : icrc_block,
758+ }
759+ }
760+
761+ // Helper function to create a test block with an AuthorizedBurn operation
762+ fn create_test_authorized_burn_block (
763+ index : u64 ,
764+ timestamp : u64 ,
765+ principal : & [ u8 ] ,
766+ amount : u64 ,
767+ ) -> RosettaBlock {
768+ let account = Account {
769+ owner : Principal :: from_slice ( principal) ,
770+ subaccount : None ,
771+ } ;
772+
773+ let transaction = IcrcTransaction {
774+ operation : IcrcOperation :: AuthorizedBurn {
775+ from : account,
776+ amount : Nat :: from ( amount) ,
777+ caller : Some ( Principal :: from_slice ( b"\x01 " ) ) ,
778+ mthd : Some ( "152burn" . to_string ( ) ) ,
779+ reason : Some ( "compliance" . to_string ( ) ) ,
780+ } ,
781+ memo : None ,
782+ created_at_time : Some ( timestamp) ,
783+ } ;
784+
785+ let icrc_block = IcrcBlock {
786+ parent_hash : None ,
787+ transaction,
788+ timestamp,
789+ effective_fee : None ,
790+ fee_collector : None ,
791+ fee_collector_block_index : None ,
792+ btype : Some ( BTYPE_122_BURN . to_string ( ) ) ,
793+ } ;
794+
795+ RosettaBlock {
796+ index,
797+ block : icrc_block,
798+ }
799+ }
800+
801+ #[ test]
802+ fn test_store_and_read_authorized_mint_block ( ) -> anyhow:: Result < ( ) > {
803+ let temp_dir = tempdir ( ) ?;
804+ let db_path = temp_dir. path ( ) . join ( "test_authorized_mint_db.sqlite" ) ;
805+ let mut connection = Connection :: open ( & db_path) ?;
806+ schema:: create_tables ( & connection) ?;
807+
808+ let principal = vec ! [ 1 , 2 , 3 , 4 ] ;
809+ let block = create_test_authorized_mint_block ( 0 , 1000000000 , & principal, 500 ) ;
810+
811+ store_blocks ( & mut connection, vec ! [ block. clone( ) ] ) ?;
812+
813+ let retrieved = get_block_at_idx ( & connection, 0 ) ?. unwrap ( ) ;
814+
815+ assert_eq ! ( retrieved. index, block. index) ;
816+ assert_eq ! ( retrieved. get_timestamp( ) , 1000000000 ) ;
817+ assert_eq ! (
818+ retrieved. block. transaction. created_at_time,
819+ block. block. transaction. created_at_time
820+ ) ;
821+ assert_eq ! (
822+ retrieved. block. btype,
823+ Some ( BTYPE_122_MINT . to_string( ) ) ,
824+ "btype should be preserved as BTYPE_122_MINT"
825+ ) ;
826+
827+ match & retrieved. block . transaction . operation {
828+ IcrcOperation :: AuthorizedMint {
829+ to,
830+ amount,
831+ caller,
832+ mthd,
833+ reason,
834+ } => {
835+ assert_eq ! (
836+ * to,
837+ Account {
838+ owner: Principal :: from_slice( & principal) ,
839+ subaccount: None ,
840+ }
841+ ) ;
842+ assert_eq ! ( * amount, Nat :: from( 500_u64 ) ) ;
843+ assert_eq ! ( * caller, Some ( Principal :: from_slice( b"\x01 " ) ) ) ;
844+ assert_eq ! ( * mthd, Some ( "152mint" . to_string( ) ) ) ;
845+ assert_eq ! ( * reason, Some ( "test" . to_string( ) ) ) ;
846+ }
847+ _ => panic ! ( "Expected AuthorizedMint operation" ) ,
848+ }
849+
850+ Ok ( ( ) )
851+ }
852+
853+ #[ test]
854+ fn test_store_and_read_authorized_burn_block ( ) -> anyhow:: Result < ( ) > {
855+ let temp_dir = tempdir ( ) ?;
856+ let db_path = temp_dir. path ( ) . join ( "test_authorized_burn_db.sqlite" ) ;
857+ let mut connection = Connection :: open ( & db_path) ?;
858+ schema:: create_tables ( & connection) ?;
859+
860+ let principal = vec ! [ 5 , 6 , 7 , 8 ] ;
861+ let block = create_test_authorized_burn_block ( 0 , 2000000000 , & principal, 300 ) ;
862+
863+ store_blocks ( & mut connection, vec ! [ block. clone( ) ] ) ?;
864+
865+ let retrieved = get_block_at_idx ( & connection, 0 ) ?. unwrap ( ) ;
866+
867+ assert_eq ! ( retrieved. index, block. index) ;
868+ assert_eq ! ( retrieved. get_timestamp( ) , 2000000000 ) ;
869+ assert_eq ! (
870+ retrieved. block. transaction. created_at_time,
871+ block. block. transaction. created_at_time
872+ ) ;
873+ assert_eq ! (
874+ retrieved. block. btype,
875+ Some ( BTYPE_122_BURN . to_string( ) ) ,
876+ "btype should be preserved as BTYPE_122_BURN"
877+ ) ;
878+
879+ match & retrieved. block . transaction . operation {
880+ IcrcOperation :: AuthorizedBurn {
881+ from,
882+ amount,
883+ caller,
884+ mthd,
885+ reason,
886+ } => {
887+ assert_eq ! (
888+ * from,
889+ Account {
890+ owner: Principal :: from_slice( & principal) ,
891+ subaccount: None ,
892+ }
893+ ) ;
894+ assert_eq ! ( * amount, Nat :: from( 300_u64 ) ) ;
895+ assert_eq ! ( * caller, Some ( Principal :: from_slice( b"\x01 " ) ) ) ;
896+ assert_eq ! ( * mthd, Some ( "152burn" . to_string( ) ) ) ;
897+ assert_eq ! ( * reason, Some ( "compliance" . to_string( ) ) ) ;
898+ }
899+ _ => panic ! ( "Expected AuthorizedBurn operation" ) ,
900+ }
901+
902+ Ok ( ( ) )
903+ }
904+
905+ #[ test]
906+ fn test_update_account_balances_authorized_mint ( ) -> anyhow:: Result < ( ) > {
907+ let temp_dir = tempdir ( ) ?;
908+ let db_path = temp_dir
909+ . path ( )
910+ . join ( "test_balance_authorized_mint_db.sqlite" ) ;
911+ let mut connection = Connection :: open ( & db_path) ?;
912+ schema:: create_tables ( & connection) ?;
913+
914+ let principal = vec ! [ 1 , 2 , 3 , 4 ] ;
915+ let account = Account {
916+ owner : Principal :: from_slice ( & principal) ,
917+ subaccount : None ,
918+ } ;
919+
920+ let block = create_test_authorized_mint_block ( 0 , 1000000000 , & principal, 500 ) ;
921+ store_blocks ( & mut connection, vec ! [ block] ) ?;
922+
923+ update_account_balances ( & mut connection, false , BALANCE_SYNC_BATCH_SIZE_DEFAULT ) ?;
924+
925+ let balance = get_account_balance_at_block_idx ( & connection, & account, 0 ) ?;
926+ assert_eq ! (
927+ balance,
928+ Some ( Nat :: from( 500_u64 ) ) ,
929+ "AuthorizedMint should credit the 'to' account"
930+ ) ;
931+
932+ Ok ( ( ) )
933+ }
934+
935+ #[ test]
936+ fn test_update_account_balances_authorized_burn ( ) -> anyhow:: Result < ( ) > {
937+ let temp_dir = tempdir ( ) ?;
938+ let db_path = temp_dir
939+ . path ( )
940+ . join ( "test_balance_authorized_burn_db.sqlite" ) ;
941+ let mut connection = Connection :: open ( & db_path) ?;
942+ schema:: create_tables ( & connection) ?;
943+
944+ let principal = vec ! [ 5 , 6 , 7 , 8 ] ;
945+ let account = Account {
946+ owner : Principal :: from_slice ( & principal) ,
947+ subaccount : None ,
948+ } ;
949+
950+ // First mint tokens so the account has a balance to burn from
951+ let mint_block = create_test_authorized_mint_block ( 0 , 1000000000 , & principal, 1000 ) ;
952+ let burn_block = create_test_authorized_burn_block ( 1 , 1000000001 , & principal, 300 ) ;
953+
954+ store_blocks ( & mut connection, vec ! [ mint_block, burn_block] ) ?;
955+
956+ update_account_balances ( & mut connection, false , BALANCE_SYNC_BATCH_SIZE_DEFAULT ) ?;
957+
958+ let balance = get_account_balance_at_block_idx ( & connection, & account, 1 ) ?;
959+ assert_eq ! (
960+ balance,
961+ Some ( Nat :: from( 700_u64 ) ) ,
962+ "AuthorizedBurn should debit the 'from' account (1000 - 300 = 700)"
963+ ) ;
964+
965+ Ok ( ( ) )
966+ }
0 commit comments