@@ -518,11 +518,11 @@ fn exit_base_token_to_near(
518518 match exit_params. message {
519519 Some ( Message :: Omni ( msg) ) => Ok ( (
520520 eth_connector_account_id,
521- format ! (
522- r#"{{"receiver_id":"{}","amount":"{}","msg":"{msg}"}}"# ,
523- exit_params . receiver_account_id ,
524- context . apparent_value . as_u128 ( ) ,
525- ) ,
521+ ft_transfer_call_args (
522+ & exit_params . receiver_account_id ,
523+ context . apparent_value ,
524+ msg ,
525+ ) ? ,
526526 events:: ExitToNear :: Omni ( ExitToNearOmni {
527527 sender : Address :: new ( context. caller ) ,
528528 erc20_address : events:: ETH_ADDRESS ,
@@ -613,11 +613,7 @@ fn exit_erc20_token_to_near<I: IO>(
613613 // In this flow, we're just forwarding the `msg` to the `ft_transfer_call` transaction.
614614 Some ( Message :: Omni ( msg) ) => (
615615 nep141_account_id,
616- format ! (
617- r#"{{"receiver_id":"{}","amount":"{}","msg":"{msg}"}}"# ,
618- exit_params. receiver_account_id, // the locker's account id in case of OMNI
619- exit_params. amount. as_u128( ) ,
620- ) ,
616+ ft_transfer_call_args ( & exit_params. receiver_account_id , exit_params. amount , msg) ?,
621617 "ft_transfer_call" ,
622618 None ,
623619 events:: ExitToNear :: Omni ( ExitToNearOmni {
@@ -795,6 +791,30 @@ fn parse_input(input: &[u8]) -> Result<&[u8], ExitError> {
795791 Ok ( & input[ 1 ..] )
796792}
797793
794+ #[ derive( serde:: Serialize ) ]
795+ struct FtTransferCallArgs < ' a > {
796+ receiver_id : & ' a AccountId ,
797+ amount : String ,
798+ msg : & ' a str ,
799+ }
800+
801+ fn ft_transfer_call_args (
802+ receiver_id : & AccountId ,
803+ amount : U256 ,
804+ msg : & str ,
805+ ) -> Result < String , ExitError > {
806+ if amount > U256 :: from ( u128:: MAX ) {
807+ return Err ( ExitError :: Other ( Cow :: from ( "ERR_INVALID_AMOUNT" ) ) ) ;
808+ }
809+
810+ serde_json:: to_string ( & FtTransferCallArgs {
811+ receiver_id,
812+ amount : format ! ( "{amount}" ) ,
813+ msg,
814+ } )
815+ . map_err ( |_| ExitError :: Other ( Cow :: from ( "ERR_SERIALIZE_JSON" ) ) )
816+ }
817+
798818pub struct ExitToEthereum < I > {
799819 io : I ,
800820 #[ cfg( not( feature = "ext-connector" ) ) ]
@@ -1274,4 +1294,38 @@ mod tests {
12741294 } )
12751295 ) ;
12761296 }
1297+
1298+ #[ test]
1299+ fn test_ft_transfer_call_args ( ) {
1300+ let receiver_id = "test.near" . parse ( ) . unwrap ( ) ;
1301+ let amount = U256 :: from ( 100 ) ;
1302+ let msg = "some message" ;
1303+
1304+ let args = super :: ft_transfer_call_args ( & receiver_id, amount, msg) . unwrap ( ) ;
1305+ let expected =
1306+ format ! ( r#"{{"receiver_id":"{receiver_id}","amount":"{amount}","msg":"{msg}"}}"# , ) ;
1307+ assert_eq ! ( args, expected) ;
1308+ }
1309+
1310+ #[ test]
1311+ fn test_ft_transfer_call_args_json_injection ( ) {
1312+ let receiver_id = "test.near" . parse ( ) . unwrap ( ) ;
1313+ let amount = U256 :: from ( 100 ) ;
1314+ let msg = "some message\" , \" amount\" : \" 1000" ; // attempt to increase amount
1315+
1316+ let args = super :: ft_transfer_call_args ( & receiver_id, amount, msg) . unwrap ( ) ;
1317+ let expected = format ! (
1318+ r#"{{"receiver_id":"{receiver_id}","amount":"{amount}","msg":"some message\", \"amount\": \"1000"}}"#
1319+ ) ;
1320+ assert_eq ! ( args, expected) ;
1321+ }
1322+
1323+ #[ test]
1324+ #[ should_panic( expected = "ERR_INVALID_AMOUNT" ) ]
1325+ fn test_ft_transfer_call_args_u256 ( ) {
1326+ let receiver_id = "test.near" . parse ( ) . unwrap ( ) ;
1327+ let amount = U256 :: from ( u128:: MAX ) + 1 ;
1328+ let msg = "some message" ;
1329+ let _ = super :: ft_transfer_call_args ( & receiver_id, amount, msg) . unwrap ( ) ;
1330+ }
12771331}
0 commit comments