11use crate :: models:: { BalanceChange , Digest , Event , EventStake , EventUnstake , GasUsed , TransactionBlocks } ;
2- use crate :: { SUI_COIN_TYPE , SUI_STAKE_EVENT , SUI_UNSTAKE_EVENT , full_coin_type} ;
2+ use crate :: { SUI_COIN_TYPE , SUI_STAKE_EVENT , SUI_UNSTAKE_EVENT , full_coin_type, sui_framework_package_address } ;
33use chain_primitives:: { BalanceDiff , SwapMapper } ;
44use chrono:: { TimeZone , Utc } ;
55use num_bigint:: { BigUint , Sign } ;
@@ -33,7 +33,7 @@ pub fn map_transaction(transaction: Digest) -> Option<Transaction> {
3333 } ;
3434 let owner = effects. gas_object . owner . get_address_owner ( ) ;
3535
36- let ( asset_id, from, to, transaction_type, value, metadata) = map_transaction_type ( & transaction. events , & balance_changes, & owner, & fee) ?;
36+ let ( asset_id, from, to, transaction_type, value, metadata) = map_transaction_type ( & transaction. events , & transaction . move_call_packages , & balance_changes, & owner, & fee) ?;
3737
3838 Some ( Transaction :: new (
3939 hash,
@@ -54,6 +54,7 @@ pub fn map_transaction(transaction: Digest) -> Option<Transaction> {
5454
5555fn map_transaction_type (
5656 events : & [ Event ] ,
57+ move_call_packages : & [ String ] ,
5758 balance_changes : & [ BalanceChange ] ,
5859 owner : & Option < String > ,
5960 fee : & BigUint ,
@@ -135,10 +136,11 @@ fn map_transaction_type(
135136 let method_name = events. first ( ) ?. event_type . rsplit ( "::" ) . nth ( 1 ) ?. to_string ( ) ;
136137 let metadata = TransactionSmartContractMetadata { method_name } ;
137138 let owner = owner. clone ( ) ?;
139+ let contract = primary_contract ( move_call_packages. iter ( ) . map ( String :: as_str) ) . or_else ( || primary_contract ( events. iter ( ) . map ( |event| event. package_id . as_str ( ) ) ) ) ;
138140 return Some ( (
139141 chain. as_asset_id ( ) ,
140142 owner. clone ( ) ,
141- owner,
143+ contract . unwrap_or ( owner) ,
142144 TransactionType :: SmartContractCall ,
143145 "0" . to_string ( ) ,
144146 serde_json:: to_value ( metadata) . ok ( ) ,
@@ -148,6 +150,26 @@ fn map_transaction_type(
148150 None
149151}
150152
153+ fn primary_contract < ' a > ( contracts : impl IntoIterator < Item = & ' a str > ) -> Option < String > {
154+ let mut first = None ;
155+ for contract in contracts {
156+ if contract. is_empty ( ) {
157+ continue ;
158+ }
159+ if first. is_none ( ) {
160+ first = Some ( contract) ;
161+ }
162+ if !is_sui_framework_package ( contract) {
163+ return Some ( contract. to_string ( ) ) ;
164+ }
165+ }
166+ first. map ( ToString :: to_string)
167+ }
168+
169+ fn is_sui_framework_package ( package : & str ) -> bool {
170+ package. parse :: < sui_types:: Address > ( ) . is_ok_and ( |address| address == sui_framework_package_address ( ) )
171+ }
172+
151173fn map_transfer_balance_changes < ' a > ( balance_changes : & ' a [ BalanceChange ] , fee : & BigUint ) -> Option < ( & ' a BalanceChange , & ' a BalanceChange ) > {
152174 let to_change = single ( balance_changes. iter ( ) . filter ( |change| change. amount . sign ( ) == Sign :: Plus ) ) ?;
153175 let from_change = single ( outgoing_changes ( balance_changes, & to_change. coin_type ) ) . or_else ( || select_native_transfer_source ( balance_changes, to_change, fee) ) ?;
@@ -273,6 +295,7 @@ mod tests {
273295 status : Status { status : "success" . to_string ( ) } ,
274296 gas_object : GasObject { owner : owner ( OWNER_ADDRESS ) } ,
275297 } ,
298+ move_call_packages : Vec :: new ( ) ,
276299 balance_changes : Some ( balance_changes) ,
277300 events,
278301 timestamp_ms : 1778964551487 ,
@@ -298,6 +321,18 @@ mod tests {
298321 assert_eq ! ( metadata. method_name, "timevy_tipping" ) ;
299322 }
300323
324+ #[ test]
325+ fn test_map_mayan_mctp_smart_contract_call ( ) {
326+ let digest: Digest = serde_json:: from_str ( include_str ! ( "../../testdata/mayan_mctp_sui_usdc_to_arbitrum_usdc.json" ) ) . unwrap ( ) ;
327+ let expected_contract = primary_contract ( digest. move_call_packages . iter ( ) . map ( String :: as_str) ) . unwrap ( ) ;
328+ let transaction = map_transaction ( digest) . unwrap ( ) ;
329+
330+ assert_eq ! ( transaction. hash, "AqXACRuimqMVf4wiVjR3Ch5PBunhQAJY3ZfAMF3MXUsW" ) ;
331+ assert_eq ! ( transaction. transaction_type, TransactionType :: SmartContractCall ) ;
332+ assert_eq ! ( transaction. from, "0x1b4cd8b734f2465614678ca0450ce9c4f2ff4835c6a7545522892a1a8fb67991" ) ;
333+ assert_eq ! ( transaction. to, expected_contract) ;
334+ }
335+
301336 #[ test]
302337 fn test_map_transaction_by_hash ( ) {
303338 let digest: Digest = serde_json:: from_str ( include_str ! ( "../../testdata/transfer_sui.json" ) ) . unwrap ( ) ;
0 commit comments