@@ -299,6 +299,16 @@ pub async fn process(request: &Transaction<'_>) -> Result<Response, Error> {
299
299
}
300
300
super :: keypath:: warn_unusual_keypath ( & params, params. name , request. keypath ( ) ) . await ?;
301
301
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
+
302
312
// Size limits.
303
313
if request. nonce ( ) . len ( ) > 16
304
314
|| request. gas_limit ( ) . len ( ) > 16
@@ -472,6 +482,11 @@ mod tests {
472
482
const KEYPATH : & [ u32 ] = & [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 , 0 ] ;
473
483
474
484
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
+ } ) ) ,
475
490
ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
476
491
assert_eq ! ( amount, "0.530564 ETH" ) ;
477
492
assert_eq ! ( address, "0x04F264Cf34440313B4A0192A352814FBe927b885" ) ;
@@ -546,6 +561,11 @@ mod tests {
546
561
UI_COUNTER
547
562
} {
548
563
1 => {
564
+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
565
+ assert ! ( params. accept_is_nextarrow) ;
566
+ true
567
+ }
568
+ 2 => {
549
569
assert_eq ! ( params. title, "High fee" ) ;
550
570
assert_eq ! ( params. body, "The fee is 12.0%\n the send amount.\n Proceed?" ) ;
551
571
assert ! ( params. longtouch) ;
@@ -575,7 +595,7 @@ mod tests {
575
595
address_case: pb:: EthAddressCase :: Mixed as _,
576
596
} ) ) )
577
597
. is_ok( ) ) ;
578
- assert_eq ! ( unsafe { UI_COUNTER } , 1 ) ;
598
+ assert_eq ! ( unsafe { UI_COUNTER } , 2 ) ;
579
599
}
580
600
581
601
/// Test an EIP-1559 transaction with an unusually high fee.
@@ -598,6 +618,11 @@ mod tests {
598
618
UI_COUNTER
599
619
} {
600
620
1 => {
621
+ assert_eq ! ( params. body, "Sign transaction on\n \n Ethereum" ) ;
622
+ assert ! ( params. accept_is_nextarrow) ;
623
+ true
624
+ }
625
+ 2 => {
601
626
assert_eq ! ( params. title, "High fee" ) ;
602
627
assert_eq ! ( params. body, "The fee is 12.0%\n the send amount.\n Proceed?" ) ;
603
628
assert ! ( params. longtouch) ;
@@ -627,7 +652,7 @@ mod tests {
627
652
address_case: pb:: EthAddressCase :: Mixed as _,
628
653
} ) ) )
629
654
. is_ok( ) ) ;
630
- assert_eq ! ( unsafe { UI_COUNTER } , 1 ) ;
655
+ assert_eq ! ( unsafe { UI_COUNTER } , 2 ) ;
631
656
}
632
657
633
658
/// Standard ETH transaction on an unusual keypath (Sepolia on mainnet keypath)
@@ -647,6 +672,10 @@ mod tests {
647
672
assert_eq ! ( params. body, "Warning: unusual keypath m/44'/60'/0'/0/0. Proceed only if you know what you are doing." ) ;
648
673
true
649
674
}
675
+ 2 => {
676
+ assert_eq ! ( params. body, "Sign transaction on\n \n Sepolia" ) ;
677
+ true
678
+ }
650
679
_ => panic ! ( "too many user confirmations" ) ,
651
680
}
652
681
} ) ) ,
@@ -681,7 +710,7 @@ mod tests {
681
710
address_case : pb:: EthAddressCase :: Mixed as _ ,
682
711
} ) ) )
683
712
. unwrap ( ) ;
684
- assert_eq ! ( unsafe { CONFIRM_COUNTER } , 1 ) ;
713
+ assert_eq ! ( unsafe { CONFIRM_COUNTER } , 2 ) ;
685
714
}
686
715
687
716
/// Standard ETH transaction with an unknown data field.
@@ -692,8 +721,12 @@ mod tests {
692
721
mock ( Data {
693
722
ui_confirm_create : Some ( Box :: new ( |params| {
694
723
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 => {
697
730
assert_eq ! ( params. title, "Transaction\n data" ) ;
698
731
assert_eq ! ( params. body, "666f6f20626172" ) ; // "foo bar" in hex.
699
732
assert ! ( params. scrollable) ;
@@ -748,8 +781,12 @@ mod tests {
748
781
mock ( Data {
749
782
ui_confirm_create : Some ( Box :: new ( |params| {
750
783
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 => {
753
790
assert_eq ! ( params. title, "Transaction\n data" ) ;
754
791
assert_eq ! ( params. body, "666f6f20626172" ) ; // "foo bar" in hex.
755
792
assert ! ( params. scrollable) ;
@@ -803,6 +840,11 @@ mod tests {
803
840
const KEYPATH : & [ u32 ] = & [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 , 0 ] ;
804
841
805
842
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
+ } ) ) ,
806
848
ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
807
849
assert_eq ! ( amount, "57 USDT" ) ;
808
850
assert_eq ! ( address, "0xE6CE0a092A99700CD4ccCcBb1fEDc39Cf53E6330" ) ;
@@ -863,6 +905,11 @@ mod tests {
863
905
const KEYPATH : & [ u32 ] = & [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 , 0 ] ;
864
906
865
907
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
+ } ) ) ,
866
913
ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
867
914
assert_eq ! ( amount, "Unknown token" ) ;
868
915
assert_eq ! ( address, "0x857B3D969eAcB775a9f79cabc62Ec4bB1D1cd60e" ) ;
@@ -938,6 +985,7 @@ mod tests {
938
985
{
939
986
// Check that the above is valid before making invalid variants.
940
987
mock ( Data {
988
+ ui_confirm_create : Some ( Box :: new ( |_| true ) ) ,
941
989
ui_transaction_address_create : Some ( Box :: new ( |_, _| true ) ) ,
942
990
ui_transaction_fee_create : Some ( Box :: new ( |_, _, _| true ) ) ,
943
991
..Default :: default ( )
@@ -1006,9 +1054,30 @@ mod tests {
1006
1054
) ;
1007
1055
}
1008
1056
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
+
1009
1073
{
1010
1074
// User rejects recipient/value.
1011
1075
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
+ } ) ) ,
1012
1081
ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
1013
1082
assert_eq ! ( amount, "0.530564 ETH" ) ;
1014
1083
assert_eq ! ( address, "0x04F264Cf34440313B4A0192A352814FBe927b885" ) ;
@@ -1024,6 +1093,11 @@ mod tests {
1024
1093
{
1025
1094
// User rejects total/fee.
1026
1095
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
+ } ) ) ,
1027
1101
ui_transaction_address_create : Some ( Box :: new ( |amount, address| {
1028
1102
assert_eq ! ( amount, "0.530564 ETH" ) ;
1029
1103
assert_eq ! ( address, "0x04F264Cf34440313B4A0192A352814FBe927b885" ) ;
@@ -1045,6 +1119,7 @@ mod tests {
1045
1119
{
1046
1120
// Keystore locked.
1047
1121
mock ( Data {
1122
+ ui_confirm_create : Some ( Box :: new ( |_| true ) ) ,
1048
1123
ui_transaction_address_create : Some ( Box :: new ( |_, _| true ) ) ,
1049
1124
ui_transaction_fee_create : Some ( Box :: new ( |_, _, _| true ) ) ,
1050
1125
..Default :: default ( )
@@ -1077,6 +1152,7 @@ mod tests {
1077
1152
{
1078
1153
// Check that the above is valid before making invalid variants.
1079
1154
mock ( Data {
1155
+ ui_confirm_create : Some ( Box :: new ( |_| true ) ) ,
1080
1156
ui_transaction_address_create : Some ( Box :: new ( |_, _| true ) ) ,
1081
1157
ui_transaction_fee_create : Some ( Box :: new ( |_, _, _| true ) ) ,
1082
1158
..Default :: default ( )
@@ -1175,4 +1251,88 @@ mod tests {
1175
1251
) ;
1176
1252
assert_eq ! ( unsafe { CONFIRM_COUNTER } , 4 ) ;
1177
1253
}
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
+ }
1178
1338
}
0 commit comments