@@ -299,6 +299,16 @@ pub async fn process(request: &Transaction<'_>) -> Result<Response, Error> {
299299 }
300300 super :: keypath:: warn_unusual_keypath ( & params, params. name , request. keypath ( ) ) . await ?;
301301
302+ // Show chain confirmation only for known networks
303+ if super :: params:: is_known_network ( request. coin ( ) ?, request. chain_id ( ) ) {
304+ confirm:: confirm ( & confirm:: Params {
305+ body : & format ! ( "Sign transaction on\n \n {}" , params. name) ,
306+ accept_is_nextarrow : true ,
307+ ..Default :: default ( )
308+ } )
309+ . await ?;
310+ }
311+
302312 // Size limits.
303313 if request. nonce ( ) . len ( ) > 16
304314 || request. gas_limit ( ) . len ( ) > 16
@@ -472,6 +482,11 @@ mod tests {
472482 const KEYPATH : & [ u32 ] = & [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 , 0 ] ;
473483
474484 mock ( Data {
485+ ui_confirm_create : Some ( Box :: new ( |params| {
486+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
487+ assert ! ( params. accept_is_nextarrow) ;
488+ true
489+ } ) ) ,
475490 ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
476491 assert_eq ! ( amount, "0.530564 ETH" ) ;
477492 assert_eq ! ( address, "0x04F264Cf34440313B4A0192A352814FBe927b885" ) ;
@@ -546,6 +561,11 @@ mod tests {
546561 UI_COUNTER
547562 } {
548563 1 => {
564+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
565+ assert ! ( params. accept_is_nextarrow) ;
566+ true
567+ }
568+ 2 => {
549569 assert_eq ! ( params. title, "High fee" ) ;
550570 assert_eq ! ( params. body, "The fee is 12.0%\n the send amount.\n Proceed?" ) ;
551571 assert ! ( params. longtouch) ;
@@ -575,7 +595,7 @@ mod tests {
575595 address_case: pb:: EthAddressCase :: Mixed as _,
576596 } ) ) )
577597 . is_ok( ) ) ;
578- assert_eq ! ( unsafe { UI_COUNTER } , 1 ) ;
598+ assert_eq ! ( unsafe { UI_COUNTER } , 2 ) ;
579599 }
580600
581601 /// Test an EIP-1559 transaction with an unusually high fee.
@@ -598,6 +618,11 @@ mod tests {
598618 UI_COUNTER
599619 } {
600620 1 => {
621+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
622+ assert ! ( params. accept_is_nextarrow) ;
623+ true
624+ }
625+ 2 => {
601626 assert_eq ! ( params. title, "High fee" ) ;
602627 assert_eq ! ( params. body, "The fee is 12.0%\n the send amount.\n Proceed?" ) ;
603628 assert ! ( params. longtouch) ;
@@ -627,7 +652,7 @@ mod tests {
627652 address_case: pb:: EthAddressCase :: Mixed as _,
628653 } ) ) )
629654 . is_ok( ) ) ;
630- assert_eq ! ( unsafe { UI_COUNTER } , 1 ) ;
655+ assert_eq ! ( unsafe { UI_COUNTER } , 2 ) ;
631656 }
632657
633658 /// Standard ETH transaction on an unusual keypath (Sepolia on mainnet keypath)
@@ -647,6 +672,10 @@ mod tests {
647672 assert_eq ! ( params. body, "Warning: unusual keypath m/44'/60'/0'/0/0. Proceed only if you know what you are doing." ) ;
648673 true
649674 }
675+ 2 => {
676+ assert_eq ! ( params. body, "Sign transaction on\n \n Sepolia" ) ;
677+ true
678+ }
650679 _ => panic ! ( "too many user confirmations" ) ,
651680 }
652681 } ) ) ,
@@ -681,7 +710,7 @@ mod tests {
681710 address_case : pb:: EthAddressCase :: Mixed as _ ,
682711 } ) ) )
683712 . unwrap ( ) ;
684- assert_eq ! ( unsafe { CONFIRM_COUNTER } , 1 ) ;
713+ assert_eq ! ( unsafe { CONFIRM_COUNTER } , 2 ) ;
685714 }
686715
687716 /// Standard ETH transaction with an unknown data field.
@@ -692,8 +721,12 @@ mod tests {
692721 mock ( Data {
693722 ui_confirm_create : Some ( Box :: new ( |params| {
694723 match unsafe { CONFIRM_COUNTER } {
695- 0 | 1 => assert_eq ! ( params. title, "Unknown\n contract" ) ,
696- 2 => {
724+ 0 => {
725+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
726+ assert ! ( params. accept_is_nextarrow) ;
727+ }
728+ 1 | 2 => assert_eq ! ( params. title, "Unknown\n contract" ) ,
729+ 3 => {
697730 assert_eq ! ( params. title, "Transaction\n data" ) ;
698731 assert_eq ! ( params. body, "666f6f20626172" ) ; // "foo bar" in hex.
699732 assert ! ( params. scrollable) ;
@@ -748,8 +781,12 @@ mod tests {
748781 mock ( Data {
749782 ui_confirm_create : Some ( Box :: new ( |params| {
750783 match unsafe { CONFIRM_COUNTER } {
751- 0 | 1 => assert_eq ! ( params. title, "Unknown\n contract" ) ,
752- 2 => {
784+ 0 => {
785+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
786+ assert ! ( params. accept_is_nextarrow) ;
787+ }
788+ 1 | 2 => assert_eq ! ( params. title, "Unknown\n contract" ) ,
789+ 3 => {
753790 assert_eq ! ( params. title, "Transaction\n data" ) ;
754791 assert_eq ! ( params. body, "666f6f20626172" ) ; // "foo bar" in hex.
755792 assert ! ( params. scrollable) ;
@@ -803,6 +840,11 @@ mod tests {
803840 const KEYPATH : & [ u32 ] = & [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 , 0 ] ;
804841
805842 mock ( Data {
843+ ui_confirm_create : Some ( Box :: new ( |params| {
844+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
845+ assert ! ( params. accept_is_nextarrow) ;
846+ true
847+ } ) ) ,
806848 ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
807849 assert_eq ! ( amount, "57 USDT" ) ;
808850 assert_eq ! ( address, "0xE6CE0a092A99700CD4ccCcBb1fEDc39Cf53E6330" ) ;
@@ -863,6 +905,11 @@ mod tests {
863905 const KEYPATH : & [ u32 ] = & [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 , 0 ] ;
864906
865907 mock ( Data {
908+ ui_confirm_create : Some ( Box :: new ( |params| {
909+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
910+ assert ! ( params. accept_is_nextarrow) ;
911+ true
912+ } ) ) ,
866913 ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
867914 assert_eq ! ( amount, "Unknown token" ) ;
868915 assert_eq ! ( address, "0x857B3D969eAcB775a9f79cabc62Ec4bB1D1cd60e" ) ;
@@ -938,6 +985,7 @@ mod tests {
938985 {
939986 // Check that the above is valid before making invalid variants.
940987 mock ( Data {
988+ ui_confirm_create : Some ( Box :: new ( |_| true ) ) ,
941989 ui_transaction_address_create : Some ( Box :: new ( |_, _| true ) ) ,
942990 ui_transaction_fee_create : Some ( Box :: new ( |_, _, _| true ) ) ,
943991 ..Default :: default ( )
@@ -1006,9 +1054,30 @@ mod tests {
10061054 ) ;
10071055 }
10081056
1057+ {
1058+ // User rejects chain confirmation
1059+ mock ( Data {
1060+ ui_confirm_create : Some ( Box :: new ( |params| {
1061+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
1062+ assert ! ( params. accept_is_nextarrow) ;
1063+ false
1064+ } ) ) ,
1065+ ..Default :: default ( )
1066+ } ) ;
1067+ assert_eq ! (
1068+ block_on( process( & Transaction :: Legacy ( & valid_request) ) ) ,
1069+ Err ( Error :: UserAbort )
1070+ ) ;
1071+ }
1072+
10091073 {
10101074 // User rejects recipient/value.
10111075 mock ( Data {
1076+ ui_confirm_create : Some ( Box :: new ( |params| {
1077+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
1078+ assert ! ( params. accept_is_nextarrow) ;
1079+ true
1080+ } ) ) ,
10121081 ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
10131082 assert_eq ! ( amount, "0.530564 ETH" ) ;
10141083 assert_eq ! ( address, "0x04F264Cf34440313B4A0192A352814FBe927b885" ) ;
@@ -1024,6 +1093,11 @@ mod tests {
10241093 {
10251094 // User rejects total/fee.
10261095 mock ( Data {
1096+ ui_confirm_create : Some ( Box :: new ( |params| {
1097+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
1098+ assert ! ( params. accept_is_nextarrow) ;
1099+ true
1100+ } ) ) ,
10271101 ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
10281102 assert_eq ! ( amount, "0.530564 ETH" ) ;
10291103 assert_eq ! ( address, "0x04F264Cf34440313B4A0192A352814FBe927b885" ) ;
@@ -1045,6 +1119,7 @@ mod tests {
10451119 {
10461120 // Keystore locked.
10471121 mock ( Data {
1122+ ui_confirm_create : Some ( Box :: new ( |_| true ) ) ,
10481123 ui_transaction_address_create : Some ( Box :: new ( |_, _| true ) ) ,
10491124 ui_transaction_fee_create : Some ( Box :: new ( |_, _, _| true ) ) ,
10501125 ..Default :: default ( )
@@ -1077,6 +1152,7 @@ mod tests {
10771152 {
10781153 // Check that the above is valid before making invalid variants.
10791154 mock ( Data {
1155+ ui_confirm_create : Some ( Box :: new ( |_| true ) ) ,
10801156 ui_transaction_address_create : Some ( Box :: new ( |_, _| true ) ) ,
10811157 ui_transaction_fee_create : Some ( Box :: new ( |_, _, _| true ) ) ,
10821158 ..Default :: default ( )
@@ -1175,4 +1251,88 @@ mod tests {
11751251 ) ;
11761252 assert_eq ! ( unsafe { CONFIRM_COUNTER } , 4 ) ;
11771253 }
1254+
1255+ /// Test that the chain confirmation screen appears for known non-mainnet networks.
1256+ #[ test]
1257+ pub fn test_chain_confirmation ( ) {
1258+ const KEYPATH : & [ u32 ] = & [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 , 0 ] ;
1259+ static mut CONFIRM_COUNTER : u32 = 0 ;
1260+ // Test with Arbitrum (chain_id 42161)
1261+ mock ( Data {
1262+ ui_confirm_create : Some ( Box :: new ( |params| {
1263+ unsafe {
1264+ if CONFIRM_COUNTER == 0 {
1265+ assert_eq ! ( params. body, "Sign transaction on\n \n Arbitrum One" ) ;
1266+ CONFIRM_COUNTER += 1 ;
1267+ }
1268+ }
1269+ true
1270+ } ) ) ,
1271+ // Skip checking these details
1272+ ui_transaction_address_create : Some ( Box :: new ( |_, _| true ) ) ,
1273+ ui_transaction_fee_create : Some ( Box :: new ( |_, _, _| true ) ) ,
1274+ ..Default :: default ( )
1275+ } ) ;
1276+ mock_unlocked ( ) ;
1277+
1278+ block_on ( process ( & Transaction :: Legacy ( & pb:: EthSignRequest {
1279+ coin : pb:: EthCoin :: Eth as _ ,
1280+ keypath : KEYPATH . to_vec ( ) ,
1281+ nonce : b"\x1f \xdc " . to_vec ( ) ,
1282+ gas_price : b"\x01 \x65 \xa0 \xbc \x00 " . to_vec ( ) ,
1283+ gas_limit : b"\x52 \x08 " . to_vec ( ) ,
1284+ recipient :
1285+ b"\x04 \xf2 \x64 \xcf \x34 \x44 \x03 \x13 \xb4 \xa0 \x19 \x2a \x35 \x28 \x14 \xfb \xe9 \x27 \xb8 \x85 "
1286+ . to_vec ( ) ,
1287+ value : b"\x07 \x5c \xf1 \x25 \x9e \x9c \x40 \x00 " . to_vec ( ) ,
1288+ data : b"" . to_vec ( ) ,
1289+ host_nonce_commitment : None ,
1290+ chain_id : 42161 ,
1291+ address_case : pb:: EthAddressCase :: Mixed as _ ,
1292+ } ) ) )
1293+ . unwrap ( ) ;
1294+ assert_eq ! ( unsafe { CONFIRM_COUNTER } , 1 ) ;
1295+ }
1296+
1297+ /// Test that EIP-1559 transactions also get the chain confirmation screen
1298+ #[ test]
1299+ pub fn test_chain_confirmation_for_eip1559 ( ) {
1300+ const KEYPATH : & [ u32 ] = & [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 , 0 ] ;
1301+ static mut CONFIRM_COUNTER : u32 = 0 ;
1302+
1303+ // Test with Polygon network (chain_id 137)
1304+ mock ( Data {
1305+ ui_confirm_create : Some ( Box :: new ( |params| {
1306+ unsafe {
1307+ if CONFIRM_COUNTER == 0 {
1308+ assert_eq ! ( params. body, "Sign transaction on\n \n Polygon" ) ;
1309+ CONFIRM_COUNTER += 1 ;
1310+ }
1311+ }
1312+ true
1313+ } ) ) ,
1314+ ui_transaction_address_create : Some ( Box :: new ( |_, _| true ) ) ,
1315+ ui_transaction_fee_create : Some ( Box :: new ( |_, _, _| true ) ) ,
1316+ ..Default :: default ( )
1317+ } ) ;
1318+ mock_unlocked ( ) ;
1319+
1320+ block_on ( process ( & Transaction :: Eip1559 ( & pb:: EthSignEip1559Request {
1321+ keypath : KEYPATH . to_vec ( ) ,
1322+ nonce : b"\x1f \xdc " . to_vec ( ) ,
1323+ max_priority_fee_per_gas : b"\x3b \x9a \xca \x00 " . to_vec ( ) ,
1324+ max_fee_per_gas : b"\x01 \x65 \xa0 \xbc \x00 " . to_vec ( ) ,
1325+ gas_limit : b"\x52 \x08 " . to_vec ( ) ,
1326+ recipient :
1327+ b"\x04 \xf2 \x64 \xcf \x34 \x44 \x03 \x13 \xb4 \xa0 \x19 \x2a \x35 \x28 \x14 \xfb \xe9 \x27 \xb8 \x85 "
1328+ . to_vec ( ) ,
1329+ value : b"\x07 \x5c \xf1 \x25 \x9e \x9c \x40 \x00 " . to_vec ( ) ,
1330+ data : b"" . to_vec ( ) ,
1331+ host_nonce_commitment : None ,
1332+ chain_id : 137 ,
1333+ address_case : pb:: EthAddressCase :: Mixed as _ ,
1334+ } ) ) )
1335+ . unwrap ( ) ;
1336+ assert_eq ! ( unsafe { CONFIRM_COUNTER } , 1 ) ;
1337+ }
11781338}
0 commit comments