9
9
#include "ethUtils.h"
10
10
#include "common_ui.h"
11
11
#include "ui_callbacks.h"
12
+ #include <ctype.h>
12
13
13
14
#define ERR_SILENT_MODE_CHECK_FAILED 0x6001
14
15
@@ -170,26 +171,6 @@ customStatus_e customProcessor(txContext_t *context) {
170
171
return CUSTOM_NOT_HANDLED ;
171
172
}
172
173
173
- void to_uppercase (char * str , unsigned char size ) {
174
- for (unsigned char i = 0 ; i < size && str [i ] != 0 ; i ++ ) {
175
- str [i ] = str [i ] >= 'a' ? str [i ] - ('a' - 'A' ) : str [i ];
176
- }
177
- }
178
-
179
- void compareOrCopy (char * preapproved_string , size_t size , char * parsed_string , bool silent_mode ) {
180
- if (silent_mode ) {
181
- /* ETH address are not fundamentally case sensitive but might
182
- have some for checksum purpose, so let's get rid of these diffs */
183
- to_uppercase (preapproved_string , strlen (preapproved_string ));
184
- to_uppercase (parsed_string , strlen (parsed_string ));
185
- if (memcmp (preapproved_string , parsed_string , strlen (preapproved_string ))) {
186
- THROW (ERR_SILENT_MODE_CHECK_FAILED );
187
- }
188
- } else {
189
- strlcpy (preapproved_string , parsed_string , size );
190
- }
191
- }
192
-
193
174
void reportFinalizeError (bool direct ) {
194
175
reset_app_context ();
195
176
if (direct ) {
@@ -200,20 +181,20 @@ void reportFinalizeError(bool direct) {
200
181
}
201
182
}
202
183
203
- // Convert `BEgasPrice` and `BEgasLimit` to Uint256 and then stores the multiplication of both in
204
- // `output`.
205
- static void computeFees ( txInt256_t * BEgasPrice , txInt256_t * BEgasLimit , uint256_t * output ) {
206
- uint256_t gasPrice = { 0 };
207
- uint256_t gasLimit = { 0 };
208
-
209
- PRINTF ( "Gas price %.*H\n" , BEgasPrice -> length , BEgasPrice -> value );
210
- PRINTF ( "Gas limit %.*H\n" , BEgasLimit -> length , BEgasLimit -> value );
211
- convertUint256BE ( BEgasPrice -> value , BEgasPrice -> length , & gasPrice );
212
- convertUint256BE ( BEgasLimit -> value , BEgasLimit -> length , & gasLimit );
213
- mul256 ( & gasPrice , & gasLimit , output );
184
+ static void address_to_string ( uint8_t * in ,
185
+ size_t in_len ,
186
+ char * out ,
187
+ size_t out_len ,
188
+ cx_sha3_t * sha3 ,
189
+ uint64_t chainId ) {
190
+ if ( in_len != 0 ) {
191
+ getEthDisplayableAddress ( in , out , out_len , sha3 , chainId );
192
+ } else {
193
+ strlcpy ( out , "Contract" , out_len );
194
+ }
214
195
}
215
196
216
- static void feesToString (uint256_t * rawFee , char * displayBuffer , uint32_t displayBufferSize ) {
197
+ static void raw_fee_to_string (uint256_t * rawFee , char * displayBuffer , uint32_t displayBufferSize ) {
217
198
const char * feeTicker = get_network_ticker ();
218
199
uint8_t tickerOffset = 0 ;
219
200
uint32_t i ;
@@ -255,32 +236,40 @@ static void feesToString(uint256_t *rawFee, char *displayBuffer, uint32_t displa
255
236
}
256
237
257
238
// Compute the fees, transform it to a string, prepend a ticker to it and copy everything to
258
- // `displayBuffer`.
259
- void prepareAndCopyFees (txInt256_t * BEGasPrice ,
260
- txInt256_t * BEGasLimit ,
261
- char * displayBuffer ,
262
- uint32_t displayBufferSize ) {
239
+ // `displayBuffer` output
240
+ static void max_transaction_fee_to_string (const txInt256_t * BEGasPrice ,
241
+ const txInt256_t * BEGasLimit ,
242
+ char * displayBuffer ,
243
+ uint32_t displayBufferSize ) {
244
+ // Use temporary variables to convert values to uint256_t
245
+ uint256_t gasPrice = {0 };
246
+ uint256_t gasLimit = {0 };
247
+ // Use temporary variable to store the result of the operation in uint256_t
263
248
uint256_t rawFee = {0 };
264
- computeFees (BEGasPrice , BEGasLimit , & rawFee );
265
- feesToString (& rawFee , displayBuffer , displayBufferSize );
249
+
250
+ PRINTF ("Gas price %.*H\n" , BEGasPrice -> length , BEGasPrice -> value );
251
+ PRINTF ("Gas limit %.*H\n" , BEGasLimit -> length , BEGasLimit -> value );
252
+ convertUint256BE (BEGasPrice -> value , BEGasPrice -> length , & gasPrice );
253
+ convertUint256BE (BEGasLimit -> value , BEGasLimit -> length , & gasLimit );
254
+ mul256 (& gasPrice , & gasLimit , & rawFee );
255
+ raw_fee_to_string (& rawFee , displayBuffer , displayBufferSize );
266
256
}
267
257
268
- void prepareFeeDisplay () {
269
- prepareAndCopyFees (& tmpContent .txContent .gasprice ,
270
- & tmpContent .txContent .startgas ,
271
- strings .common .maxFee ,
272
- sizeof (strings .common .maxFee ));
258
+ static void nonce_to_string (const txInt256_t * nonce , char * out , size_t out_size ) {
259
+ uint256_t nonce_uint256 ;
260
+ convertUint256BE (nonce -> value , nonce -> length , & nonce_uint256 );
261
+ tostring256 (& nonce_uint256 , 10 , out , out_size );
273
262
}
274
263
275
- void prepareNetworkDisplay ( ) {
264
+ static void get_network_as_string ( char * out , size_t out_size ) {
276
265
const char * name = get_network_name ();
277
266
if (name == NULL ) {
278
267
// No network name found so simply copy the chain ID as the network name.
279
268
uint64_t chain_id = get_chain_id ();
280
- u64_to_string (chain_id , strings . common . network_name , sizeof ( strings . common . network_name ) );
269
+ u64_to_string (chain_id , out , out_size );
281
270
} else {
282
271
// Network name found, simply copy it.
283
- strlcpy (strings . common . network_name , name , sizeof ( strings . common . network_name ) );
272
+ strlcpy (out , name , out_size );
284
273
}
285
274
}
286
275
@@ -305,12 +294,27 @@ static void get_public_key(uint8_t *out, uint8_t outLength) {
305
294
getEthAddressFromKey (& publicKey , out , & global_sha3 );
306
295
}
307
296
297
+ /* Local implmentation of strncasecmp, workaround of the segfaulting base implem
298
+ * Remove once strncasecmp is fixed
299
+ */
300
+ static int strcasecmp_workaround (const char * str1 , const char * str2 ) {
301
+ unsigned char c1 , c2 ;
302
+ do {
303
+ c1 = * str1 ++ ;
304
+ c2 = * str2 ++ ;
305
+ if (toupper (c1 ) != toupper (c2 )) {
306
+ return toupper (c1 ) - toupper (c2 );
307
+ }
308
+ } while (c1 != '\0' );
309
+ return 0 ;
310
+ }
311
+
308
312
void finalizeParsing (bool direct ) {
309
313
char displayBuffer [50 ];
310
314
uint8_t decimals = WEI_TO_ETHER ;
311
315
const char * ticker = get_network_ticker ();
312
316
ethPluginFinalize_t pluginFinalize ;
313
- bool genericUI = true;
317
+ bool use_standard_UI = true;
314
318
315
319
// Verify the chain
316
320
if (chainConfig -> chainId != ETHEREUM_MAINNET_CHAINID ) {
@@ -335,7 +339,6 @@ void finalizeParsing(bool direct) {
335
339
336
340
// Finalize the plugin handling
337
341
if (dataContext .tokenContext .pluginStatus >= ETH_PLUGIN_RESULT_SUCCESSFUL ) {
338
- genericUI = false;
339
342
eth_plugin_prepare_finalize (& pluginFinalize );
340
343
341
344
uint8_t msg_sender [ADDRESS_LENGTH ] = {0 };
@@ -381,14 +384,17 @@ void finalizeParsing(bool direct) {
381
384
// Handle the right interface
382
385
switch (pluginFinalize .uiType ) {
383
386
case ETH_UI_TYPE_GENERIC :
387
+ // Use the dedicated ETH plugin UI
388
+ use_standard_UI = false;
384
389
tmpContent .txContent .dataPresent = false;
385
390
// Add the number of screens + the number of additional screens to get the total
386
391
// number of screens needed.
387
392
dataContext .tokenContext .pluginUiMaxItems =
388
393
pluginFinalize .numScreens + pluginProvideInfo .additionalScreens ;
389
394
break ;
390
395
case ETH_UI_TYPE_AMOUNT_ADDRESS :
391
- genericUI = true;
396
+ // Use the standard ETH UI as this plugin uses the amount/address UI
397
+ use_standard_UI = true;
392
398
tmpContent .txContent .dataPresent = false;
393
399
if ((pluginFinalize .amount == NULL ) || (pluginFinalize .address == NULL )) {
394
400
PRINTF ("Incorrect amount/address set by plugin\n" );
@@ -413,11 +419,15 @@ void finalizeParsing(bool direct) {
413
419
return ;
414
420
}
415
421
}
416
- } else {
417
- genericUI = true;
418
422
}
419
423
}
420
424
425
+ // User has just validated a swap but ETH received apdus about a non standard plugin / contract
426
+ if (called_from_swap && !use_standard_UI ) {
427
+ PRINTF ("ERR_SILENT_MODE_CHECK_FAILED, called_from_swap\n" );
428
+ THROW (ERR_SILENT_MODE_CHECK_FAILED );
429
+ }
430
+
421
431
if (tmpContent .txContent .dataPresent && !N_storage .dataAllowed ) {
422
432
reportFinalizeError (direct );
423
433
ui_warning_contract_data ();
@@ -426,66 +436,94 @@ void finalizeParsing(bool direct) {
426
436
}
427
437
}
428
438
429
- // Prepare destination address to display
430
- if (genericUI ) {
431
- if (tmpContent .txContent .destinationLength != 0 ) {
432
- getEthDisplayableAddress (tmpContent .txContent .destination ,
433
- displayBuffer ,
434
- sizeof (displayBuffer ),
435
- & global_sha3 ,
436
- chainConfig -> chainId );
437
- compareOrCopy (strings .common .fullAddress ,
438
- sizeof (strings .common .fullAddress ),
439
+ // Prepare destination address and amount to display
440
+ if (use_standard_UI ) {
441
+ // Format the address in a temporary buffer, if in swap case compare it with validated
442
+ // address, else commit it
443
+ address_to_string (tmpContent .txContent .destination ,
444
+ tmpContent .txContent .destinationLength ,
439
445
displayBuffer ,
440
- called_from_swap );
446
+ sizeof (displayBuffer ),
447
+ & global_sha3 ,
448
+ chainConfig -> chainId );
449
+ if (called_from_swap ) {
450
+ // Ensure the values are the same that the ones that have been previously validated
451
+ if (strcasecmp_workaround (strings .common .fullAddress , displayBuffer ) != 0 ) {
452
+ PRINTF ("ERR_SILENT_MODE_CHECK_FAILED, address check failed\n" );
453
+ THROW (ERR_SILENT_MODE_CHECK_FAILED );
454
+ }
441
455
} else {
442
- strcpy (strings .common .fullAddress , "Contract" );
456
+ strlcpy (strings .common .fullAddress , displayBuffer , sizeof ( strings . common . fullAddress ) );
443
457
}
444
- }
458
+ PRINTF ( "Address displayed: %s\n" , strings . common . fullAddress );
445
459
446
- // Prepare amount to display
447
- if ( genericUI ) {
460
+ // Format the amount in a temporary buffer, if in swap case compare it with validated
461
+ // amount, else commit it
448
462
amountToString (tmpContent .txContent .value .value ,
449
463
tmpContent .txContent .value .length ,
450
464
decimals ,
451
465
ticker ,
452
466
displayBuffer ,
453
467
sizeof (displayBuffer ));
454
- compareOrCopy (strings .common .fullAmount ,
455
- sizeof (strings .common .fullAmount ),
456
- displayBuffer ,
457
- called_from_swap );
468
+ if (called_from_swap ) {
469
+ // Ensure the values are the same that the ones that have been previously validated
470
+ if (strcmp (strings .common .fullAmount , displayBuffer ) != 0 ) {
471
+ PRINTF ("ERR_SILENT_MODE_CHECK_FAILED, amount check failed\n" );
472
+ THROW (ERR_SILENT_MODE_CHECK_FAILED );
473
+ }
474
+ } else {
475
+ strlcpy (strings .common .fullAmount , displayBuffer , sizeof (strings .common .fullAmount ));
476
+ }
477
+ PRINTF ("Amount displayed: %s\n" , strings .common .fullAmount );
458
478
}
459
479
460
- // Prepare nonce to display
461
- uint256_t nonce ;
462
- convertUint256BE (tmpContent .txContent .nonce .value , tmpContent .txContent .nonce .length , & nonce );
463
- tostring256 (& nonce , 10 , displayBuffer , sizeof (displayBuffer ));
464
- strlcpy (strings .common .nonce , displayBuffer , sizeof (strings .common .nonce ));
480
+ // Compute the max fee in a temporary buffer, if in swap case compare it with validated max fee,
481
+ // else commit it
482
+ max_transaction_fee_to_string (& tmpContent .txContent .gasprice ,
483
+ & tmpContent .txContent .startgas ,
484
+ displayBuffer ,
485
+ sizeof (displayBuffer ));
486
+ if (called_from_swap ) {
487
+ // Ensure the values are the same that the ones that have been previously validated
488
+ if (strcmp (strings .common .maxFee , displayBuffer ) != 0 ) {
489
+ PRINTF ("ERR_SILENT_MODE_CHECK_FAILED, fees check failed\n" );
490
+ THROW (ERR_SILENT_MODE_CHECK_FAILED );
491
+ }
492
+ } else {
493
+ strlcpy (strings .common .maxFee , displayBuffer , sizeof (strings .common .maxFee ));
494
+ }
465
495
466
- // Compute maximum fee
467
- prepareFeeDisplay ();
468
496
PRINTF ("Fees displayed: %s\n" , strings .common .maxFee );
469
497
498
+ // Prepare nonce to display
499
+ nonce_to_string (& tmpContent .txContent .nonce ,
500
+ strings .common .nonce ,
501
+ sizeof (strings .common .nonce ));
502
+ PRINTF ("Nonce: %s\n" , strings .common .nonce );
503
+
470
504
// Prepare chainID field
471
- prepareNetworkDisplay ( );
505
+ get_network_as_string ( strings . common . network_name , sizeof ( strings . common . network_name ) );
472
506
PRINTF ("Network: %s\n" , strings .common .network_name );
473
507
474
- bool no_consent ;
508
+ bool no_consent_check ;
475
509
476
- no_consent = called_from_swap ;
510
+ // If called from swap, the user as already validated a standard transaction
511
+ // We have already checked the fields of this transaction above
512
+ no_consent_check = called_from_swap && use_standard_UI ;
477
513
478
514
#ifdef NO_CONSENT
479
- no_consent = true;
515
+ no_consent_check = true;
480
516
#endif // NO_CONSENT
481
517
482
- if (no_consent ) {
518
+ if (no_consent_check ) {
483
519
io_seproxyhal_touch_tx_ok (NULL );
484
520
} else {
485
- if (genericUI ) {
521
+ if (use_standard_UI ) {
486
522
ux_approve_tx (false);
487
523
} else {
488
- plugin_ui_start ();
524
+ dataContext .tokenContext .pluginUiState = PLUGIN_UI_OUTSIDE ;
525
+ dataContext .tokenContext .pluginUiCurrentItem = 0 ;
526
+ ux_approve_tx (true);
489
527
}
490
528
}
491
529
}
0 commit comments