Apply clang-format
This commit is contained in:
@@ -3,74 +3,79 @@
|
||||
#include "ui_flow.h"
|
||||
#include "feature_signTx.h"
|
||||
|
||||
void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
|
||||
UNUSED(tx);
|
||||
parserStatus_e txResult;
|
||||
uint32_t i;
|
||||
if (p1 == P1_FIRST) {
|
||||
if (dataLength < 1) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
void handleSign(uint8_t p1,
|
||||
uint8_t p2,
|
||||
uint8_t *workBuffer,
|
||||
uint16_t dataLength,
|
||||
unsigned int *flags,
|
||||
unsigned int *tx) {
|
||||
UNUSED(tx);
|
||||
parserStatus_e txResult;
|
||||
uint32_t i;
|
||||
if (p1 == P1_FIRST) {
|
||||
if (dataLength < 1) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
if (appState != APP_STATE_IDLE) {
|
||||
reset_app_context();
|
||||
}
|
||||
appState = APP_STATE_SIGNING_TX;
|
||||
tmpCtx.transactionContext.pathLength = workBuffer[0];
|
||||
if ((tmpCtx.transactionContext.pathLength < 0x01) ||
|
||||
(tmpCtx.transactionContext.pathLength > MAX_BIP32_PATH)) {
|
||||
PRINTF("Invalid path\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
workBuffer++;
|
||||
dataLength--;
|
||||
for (i = 0; i < tmpCtx.transactionContext.pathLength; i++) {
|
||||
if (dataLength < 4) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
tmpCtx.transactionContext.bip32Path[i] = U4BE(workBuffer, 0);
|
||||
workBuffer += 4;
|
||||
dataLength -= 4;
|
||||
}
|
||||
dataPresent = false;
|
||||
dataContext.tokenContext.pluginAvailable = 0;
|
||||
initTx(&txContext, &global_sha3, &tmpContent.txContent, customProcessor, NULL);
|
||||
} else if (p1 != P1_MORE) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if (appState != APP_STATE_IDLE) {
|
||||
reset_app_context();
|
||||
if (p2 != 0) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
appState = APP_STATE_SIGNING_TX;
|
||||
tmpCtx.transactionContext.pathLength = workBuffer[0];
|
||||
if ((tmpCtx.transactionContext.pathLength < 0x01) ||
|
||||
(tmpCtx.transactionContext.pathLength > MAX_BIP32_PATH)) {
|
||||
PRINTF("Invalid path\n");
|
||||
THROW(0x6a80);
|
||||
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_TX)) {
|
||||
PRINTF("Signature not initialized\n");
|
||||
THROW(0x6985);
|
||||
}
|
||||
workBuffer++;
|
||||
dataLength--;
|
||||
for (i = 0; i < tmpCtx.transactionContext.pathLength; i++) {
|
||||
if (dataLength < 4) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
tmpCtx.transactionContext.bip32Path[i] = U4BE(workBuffer, 0);
|
||||
workBuffer += 4;
|
||||
dataLength -= 4;
|
||||
if (txContext.currentField == TX_RLP_NONE) {
|
||||
PRINTF("Parser not initialized\n");
|
||||
THROW(0x6985);
|
||||
}
|
||||
txResult = processTx(&txContext,
|
||||
workBuffer,
|
||||
dataLength,
|
||||
(chainConfig->kind == CHAIN_KIND_WANCHAIN ? TX_FLAG_TYPE : 0));
|
||||
switch (txResult) {
|
||||
case USTREAM_SUSPENDED:
|
||||
break;
|
||||
case USTREAM_FINISHED:
|
||||
break;
|
||||
case USTREAM_PROCESSING:
|
||||
THROW(0x9000);
|
||||
case USTREAM_FAULT:
|
||||
THROW(0x6A80);
|
||||
default:
|
||||
PRINTF("Unexpected parser status\n");
|
||||
THROW(0x6A80);
|
||||
}
|
||||
dataPresent = false;
|
||||
dataContext.tokenContext.pluginAvailable = 0;
|
||||
initTx(&txContext, &global_sha3, &tmpContent.txContent, customProcessor, NULL);
|
||||
}
|
||||
else
|
||||
if (p1 != P1_MORE) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if (p2 != 0) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_TX)) {
|
||||
PRINTF("Signature not initialized\n");
|
||||
THROW(0x6985);
|
||||
}
|
||||
if (txContext.currentField == TX_RLP_NONE) {
|
||||
PRINTF("Parser not initialized\n");
|
||||
THROW(0x6985);
|
||||
}
|
||||
txResult = processTx(&txContext, workBuffer, dataLength, (chainConfig->kind == CHAIN_KIND_WANCHAIN ? TX_FLAG_TYPE : 0));
|
||||
switch (txResult) {
|
||||
case USTREAM_SUSPENDED:
|
||||
break;
|
||||
case USTREAM_FINISHED:
|
||||
break;
|
||||
case USTREAM_PROCESSING:
|
||||
THROW(0x9000);
|
||||
case USTREAM_FAULT:
|
||||
THROW(0x6A80);
|
||||
default:
|
||||
PRINTF("Unexpected parser status\n");
|
||||
THROW(0x6A80);
|
||||
}
|
||||
|
||||
if (txResult == USTREAM_FINISHED) {
|
||||
finalizeParsing(false);
|
||||
}
|
||||
if (txResult == USTREAM_FINISHED) {
|
||||
finalizeParsing(false);
|
||||
}
|
||||
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,3 @@
|
||||
|
||||
customStatus_e customProcessor(txContext_t *context);
|
||||
void finalizeParsing(bool direct);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
|
||||
uint32_t i;
|
||||
for (i=0; i<8; i++) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (parameter[i] != 0x00) {
|
||||
break;
|
||||
}
|
||||
@@ -21,16 +21,14 @@ uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
|
||||
result[1] = '0';
|
||||
result[2] = '\0';
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
array_hexstr(result, parameter + i, 8 - i);
|
||||
return ((8 - i) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
customStatus_e customProcessor(txContext_t *context) {
|
||||
if ((context->currentField == TX_RLP_DATA) &&
|
||||
(context->currentFieldLength != 0)) {
|
||||
if ((context->currentField == TX_RLP_DATA) && (context->currentFieldLength != 0)) {
|
||||
dataPresent = true;
|
||||
// If handling a new contract rather than a function call, abort immediately
|
||||
if (tmpContent.txContent.destinationLength == 0) {
|
||||
@@ -38,320 +36,341 @@ customStatus_e customProcessor(txContext_t *context) {
|
||||
}
|
||||
if (context->currentFieldPos == 0) {
|
||||
ethPluginInitContract_t pluginInit;
|
||||
// If handling the beginning of the data field, assume that the function selector is present
|
||||
// If handling the beginning of the data field, assume that the function selector is
|
||||
// present
|
||||
if (context->commandLength < 4) {
|
||||
PRINTF("Missing function selector\n");
|
||||
return CUSTOM_FAULT;
|
||||
}
|
||||
eth_plugin_prepare_init(&pluginInit, context->workBuffer, context->currentFieldLength);
|
||||
dataContext.tokenContext.pluginAvailable = eth_plugin_perform_init(tmpContent.txContent.destination, &pluginInit);
|
||||
dataContext.tokenContext.pluginAvailable =
|
||||
eth_plugin_perform_init(tmpContent.txContent.destination, &pluginInit);
|
||||
PRINTF("pluginAvailable %d\n", dataContext.tokenContext.pluginAvailable);
|
||||
if (dataContext.tokenContext.pluginAvailable) {
|
||||
dataContext.tokenContext.fieldIndex = 0;
|
||||
dataContext.tokenContext.fieldOffset = 0;
|
||||
copyTxData(context, NULL, 4);
|
||||
if (context->currentFieldLength == 4) {
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
dataContext.tokenContext.fieldIndex = 0;
|
||||
dataContext.tokenContext.fieldOffset = 0;
|
||||
copyTxData(context, NULL, 4);
|
||||
if (context->currentFieldLength == 4) {
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t blockSize;
|
||||
uint32_t copySize;
|
||||
uint32_t fieldPos = context->currentFieldPos;
|
||||
if (fieldPos == 0) { // not reached if a plugin is available
|
||||
if (!N_storage.dataAllowed) {
|
||||
uint32_t blockSize;
|
||||
uint32_t copySize;
|
||||
uint32_t fieldPos = context->currentFieldPos;
|
||||
if (fieldPos == 0) { // not reached if a plugin is available
|
||||
if (!N_storage.dataAllowed) {
|
||||
PRINTF("Data field forbidden\n");
|
||||
return CUSTOM_FAULT;
|
||||
}
|
||||
if (!N_storage.contractDetails) {
|
||||
}
|
||||
if (!N_storage.contractDetails) {
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
dataContext.tokenContext.fieldIndex = 0;
|
||||
dataContext.tokenContext.fieldOffset = 0;
|
||||
blockSize = 4;
|
||||
}
|
||||
else {
|
||||
if (!N_storage.contractDetails && !dataContext.tokenContext.pluginAvailable) {
|
||||
}
|
||||
dataContext.tokenContext.fieldIndex = 0;
|
||||
dataContext.tokenContext.fieldOffset = 0;
|
||||
blockSize = 4;
|
||||
} else {
|
||||
if (!N_storage.contractDetails && !dataContext.tokenContext.pluginAvailable) {
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
blockSize = 32 - (dataContext.tokenContext.fieldOffset % 32);
|
||||
}
|
||||
}
|
||||
blockSize = 32 - (dataContext.tokenContext.fieldOffset % 32);
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if ((context->currentFieldLength - fieldPos) < blockSize) {
|
||||
PRINTF("Unconsistent data\n");
|
||||
return CUSTOM_FAULT;
|
||||
}
|
||||
// Sanity check
|
||||
if ((context->currentFieldLength - fieldPos) < blockSize) {
|
||||
PRINTF("Unconsistent data\n");
|
||||
return CUSTOM_FAULT;
|
||||
}
|
||||
|
||||
copySize = (context->commandLength < blockSize ? context->commandLength : blockSize);
|
||||
copySize = (context->commandLength < blockSize ? context->commandLength : blockSize);
|
||||
|
||||
PRINTF("currentFieldPos %d copySize %d\n", context->currentFieldPos, copySize);
|
||||
PRINTF("currentFieldPos %d copySize %d\n", context->currentFieldPos, copySize);
|
||||
|
||||
copyTxData(context,
|
||||
dataContext.tokenContext.data + dataContext.tokenContext.fieldOffset,
|
||||
copySize);
|
||||
copyTxData(context,
|
||||
dataContext.tokenContext.data + dataContext.tokenContext.fieldOffset,
|
||||
copySize);
|
||||
|
||||
if (context->currentFieldPos == context->currentFieldLength) {
|
||||
context->currentField++;
|
||||
context->processingField = false;
|
||||
}
|
||||
if (context->currentFieldPos == context->currentFieldLength) {
|
||||
context->currentField++;
|
||||
context->processingField = false;
|
||||
}
|
||||
|
||||
dataContext.tokenContext.fieldOffset += copySize;
|
||||
dataContext.tokenContext.fieldOffset += copySize;
|
||||
|
||||
if (copySize == blockSize) {
|
||||
// Can process or display
|
||||
if (dataContext.tokenContext.pluginAvailable) {
|
||||
if (copySize == blockSize) {
|
||||
// Can process or display
|
||||
if (dataContext.tokenContext.pluginAvailable) {
|
||||
ethPluginProvideParameter_t pluginProvideParameter;
|
||||
eth_plugin_prepare_provide_parameter(&pluginProvideParameter,
|
||||
dataContext.tokenContext.data,
|
||||
dataContext.tokenContext.fieldIndex * 32 + 4);
|
||||
if (!eth_plugin_call(NULL, ETH_PLUGIN_PROVIDE_PARAMETER, (void*)&pluginProvideParameter)) {
|
||||
PRINTF("Plugin parameter call failed\n");
|
||||
return CUSTOM_FAULT;
|
||||
eth_plugin_prepare_provide_parameter(&pluginProvideParameter,
|
||||
dataContext.tokenContext.data,
|
||||
dataContext.tokenContext.fieldIndex * 32 + 4);
|
||||
if (!eth_plugin_call(NULL,
|
||||
ETH_PLUGIN_PROVIDE_PARAMETER,
|
||||
(void *) &pluginProvideParameter)) {
|
||||
PRINTF("Plugin parameter call failed\n");
|
||||
return CUSTOM_FAULT;
|
||||
}
|
||||
dataContext.tokenContext.fieldIndex++;
|
||||
dataContext.tokenContext.fieldOffset = 0;
|
||||
return CUSTOM_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldPos != 0) {
|
||||
dataContext.tokenContext.fieldIndex++;
|
||||
}
|
||||
dataContext.tokenContext.fieldOffset = 0;
|
||||
if (fieldPos == 0) {
|
||||
array_hexstr(strings.tmp.tmp, dataContext.tokenContext.data, 4);
|
||||
ux_flow_init(0, ux_confirm_selector_flow, NULL);
|
||||
}
|
||||
else {
|
||||
uint32_t offset = 0;
|
||||
uint32_t i;
|
||||
snprintf(strings.tmp.tmp2, sizeof(strings.tmp.tmp2), "Field %d", dataContext.tokenContext.fieldIndex);
|
||||
for (i=0; i<4; i++) {
|
||||
offset += splitBinaryParameterPart(strings.tmp.tmp + offset, dataContext.tokenContext.data + 8 * i);
|
||||
if (i != 3) {
|
||||
strings.tmp.tmp[offset++] = ':';
|
||||
}
|
||||
}
|
||||
ux_flow_init(0, ux_confirm_parameter_flow, NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return CUSTOM_HANDLED;
|
||||
}
|
||||
if (fieldPos != 0) {
|
||||
dataContext.tokenContext.fieldIndex++;
|
||||
}
|
||||
dataContext.tokenContext.fieldOffset = 0;
|
||||
if (fieldPos == 0) {
|
||||
array_hexstr(strings.tmp.tmp, dataContext.tokenContext.data, 4);
|
||||
ux_flow_init(0, ux_confirm_selector_flow, NULL);
|
||||
} else {
|
||||
uint32_t offset = 0;
|
||||
uint32_t i;
|
||||
snprintf(strings.tmp.tmp2,
|
||||
sizeof(strings.tmp.tmp2),
|
||||
"Field %d",
|
||||
dataContext.tokenContext.fieldIndex);
|
||||
for (i = 0; i < 4; i++) {
|
||||
offset += splitBinaryParameterPart(strings.tmp.tmp + offset,
|
||||
dataContext.tokenContext.data + 8 * i);
|
||||
if (i != 3) {
|
||||
strings.tmp.tmp[offset++] = ':';
|
||||
}
|
||||
}
|
||||
ux_flow_init(0, ux_confirm_parameter_flow, NULL);
|
||||
}
|
||||
} else {
|
||||
return CUSTOM_HANDLED;
|
||||
}
|
||||
|
||||
return CUSTOM_SUSPENDED;
|
||||
return CUSTOM_SUSPENDED;
|
||||
}
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
void to_uppercase(char* str, unsigned char size){
|
||||
for (unsigned char i = 0; i < size && str[i] != 0; i++)
|
||||
{
|
||||
void to_uppercase(char *str, unsigned char size) {
|
||||
for (unsigned char i = 0; i < size && str[i] != 0; i++) {
|
||||
str[i] = str[i] >= 'a' ? str[i] - ('a' - 'A') : str[i];
|
||||
}
|
||||
}
|
||||
|
||||
void compareOrCopy(char* preapproved_string, char* parsed_string, bool silent_mode){
|
||||
if(silent_mode){
|
||||
/* ETH address are not fundamentally case sensitive but might
|
||||
have some for checksum purpose, so let's get rid of these diffs */
|
||||
to_uppercase(preapproved_string, strlen(preapproved_string));
|
||||
to_uppercase(parsed_string, strlen(parsed_string));
|
||||
if(memcmp(preapproved_string, parsed_string, strlen(preapproved_string))){
|
||||
THROW(ERR_SILENT_MODE_CHECK_FAILED);
|
||||
void compareOrCopy(char *preapproved_string, char *parsed_string, bool silent_mode) {
|
||||
if (silent_mode) {
|
||||
/* ETH address are not fundamentally case sensitive but might
|
||||
have some for checksum purpose, so let's get rid of these diffs */
|
||||
to_uppercase(preapproved_string, strlen(preapproved_string));
|
||||
to_uppercase(parsed_string, strlen(parsed_string));
|
||||
if (memcmp(preapproved_string, parsed_string, strlen(preapproved_string))) {
|
||||
THROW(ERR_SILENT_MODE_CHECK_FAILED);
|
||||
}
|
||||
} else {
|
||||
strcpy(preapproved_string, parsed_string);
|
||||
}
|
||||
}
|
||||
else{
|
||||
strcpy(preapproved_string, parsed_string);
|
||||
}
|
||||
}
|
||||
|
||||
void reportFinalizeError(bool direct) {
|
||||
reset_app_context();
|
||||
if (direct) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
else {
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
}
|
||||
reset_app_context();
|
||||
if (direct) {
|
||||
THROW(0x6A80);
|
||||
} else {
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
}
|
||||
}
|
||||
|
||||
void computeFees(char *displayBuffer, uint32_t displayBufferSize) {
|
||||
uint256_t gasPrice, startGas, uint256;
|
||||
uint8_t *feeTicker = (uint8_t *)PIC(chainConfig->coinName);
|
||||
uint8_t tickerOffset = 0;
|
||||
uint32_t i;
|
||||
uint256_t gasPrice, startGas, uint256;
|
||||
uint8_t *feeTicker = (uint8_t *) PIC(chainConfig->coinName);
|
||||
uint8_t tickerOffset = 0;
|
||||
uint32_t i;
|
||||
|
||||
PRINTF("Max fee\n");
|
||||
PRINTF("Gasprice %.*H\n", tmpContent.txContent.gasprice.length, tmpContent.txContent.gasprice.value);
|
||||
PRINTF("Startgas %.*H\n", tmpContent.txContent.startgas.length, tmpContent.txContent.startgas.value);
|
||||
convertUint256BE(tmpContent.txContent.gasprice.value, tmpContent.txContent.gasprice.length, &gasPrice);
|
||||
convertUint256BE(tmpContent.txContent.startgas.value, tmpContent.txContent.startgas.length, &startGas);
|
||||
mul256(&gasPrice, &startGas, &uint256);
|
||||
tostring256(&uint256, 10, (char *)(G_io_apdu_buffer + 100), 100);
|
||||
i = 0;
|
||||
while (G_io_apdu_buffer[100 + i]) {
|
||||
i++;
|
||||
}
|
||||
adjustDecimals((char *)(G_io_apdu_buffer + 100), i, (char *)G_io_apdu_buffer, 100, WEI_TO_ETHER);
|
||||
i = 0;
|
||||
tickerOffset=0;
|
||||
memset(displayBuffer, 0, displayBufferSize);
|
||||
while (feeTicker[tickerOffset]) {
|
||||
displayBuffer[tickerOffset] = feeTicker[tickerOffset];
|
||||
tickerOffset++;
|
||||
}
|
||||
while (G_io_apdu_buffer[i]) {
|
||||
displayBuffer[tickerOffset + i] = G_io_apdu_buffer[i];
|
||||
i++;
|
||||
}
|
||||
displayBuffer[tickerOffset + i] = '\0';
|
||||
PRINTF("Max fee\n");
|
||||
PRINTF("Gasprice %.*H\n",
|
||||
tmpContent.txContent.gasprice.length,
|
||||
tmpContent.txContent.gasprice.value);
|
||||
PRINTF("Startgas %.*H\n",
|
||||
tmpContent.txContent.startgas.length,
|
||||
tmpContent.txContent.startgas.value);
|
||||
convertUint256BE(tmpContent.txContent.gasprice.value,
|
||||
tmpContent.txContent.gasprice.length,
|
||||
&gasPrice);
|
||||
convertUint256BE(tmpContent.txContent.startgas.value,
|
||||
tmpContent.txContent.startgas.length,
|
||||
&startGas);
|
||||
mul256(&gasPrice, &startGas, &uint256);
|
||||
tostring256(&uint256, 10, (char *) (G_io_apdu_buffer + 100), 100);
|
||||
i = 0;
|
||||
while (G_io_apdu_buffer[100 + i]) {
|
||||
i++;
|
||||
}
|
||||
adjustDecimals((char *) (G_io_apdu_buffer + 100),
|
||||
i,
|
||||
(char *) G_io_apdu_buffer,
|
||||
100,
|
||||
WEI_TO_ETHER);
|
||||
i = 0;
|
||||
tickerOffset = 0;
|
||||
memset(displayBuffer, 0, displayBufferSize);
|
||||
while (feeTicker[tickerOffset]) {
|
||||
displayBuffer[tickerOffset] = feeTicker[tickerOffset];
|
||||
tickerOffset++;
|
||||
}
|
||||
while (G_io_apdu_buffer[i]) {
|
||||
displayBuffer[tickerOffset + i] = G_io_apdu_buffer[i];
|
||||
i++;
|
||||
}
|
||||
displayBuffer[tickerOffset + i] = '\0';
|
||||
}
|
||||
|
||||
void finalizeParsing(bool direct) {
|
||||
char displayBuffer[50];
|
||||
uint8_t decimals = WEI_TO_ETHER;
|
||||
uint8_t *ticker = (uint8_t *)PIC(chainConfig->coinName);
|
||||
ethPluginFinalize_t pluginFinalize;
|
||||
tokenDefinition_t *token1 = NULL, *token2 = NULL;
|
||||
bool genericUI = true;
|
||||
void finalizeParsing(bool direct) {
|
||||
char displayBuffer[50];
|
||||
uint8_t decimals = WEI_TO_ETHER;
|
||||
uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName);
|
||||
ethPluginFinalize_t pluginFinalize;
|
||||
tokenDefinition_t *token1 = NULL, *token2 = NULL;
|
||||
bool genericUI = true;
|
||||
|
||||
// Verify the chain
|
||||
if (chainConfig->chainId != 0) {
|
||||
uint32_t v = getV(&tmpContent.txContent);
|
||||
if (chainConfig->chainId != v) {
|
||||
reset_app_context();
|
||||
PRINTF("Invalid chainId %d expected %d\n", v, chainConfig->chainId);
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Store the hash
|
||||
cx_hash((cx_hash_t *)&global_sha3, CX_LAST, tmpCtx.transactionContext.hash, 0, tmpCtx.transactionContext.hash, 32);
|
||||
|
||||
// Finalize the plugin handling
|
||||
if (dataContext.tokenContext.pluginAvailable) {
|
||||
genericUI = false;
|
||||
eth_plugin_prepare_finalize(&pluginFinalize);
|
||||
if (!eth_plugin_call(NULL, ETH_PLUGIN_FINALIZE, (void*)&pluginFinalize)) {
|
||||
PRINTF("Plugin finalize call failed\n");
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Lookup tokens if requested
|
||||
if (pluginFinalize.tokenLookup1 != NULL) {
|
||||
ethPluginProvideToken_t pluginProvideToken;
|
||||
token1 = getKnownToken(pluginFinalize.tokenLookup1);
|
||||
if (pluginFinalize.tokenLookup2 != NULL) {
|
||||
token2 = getKnownToken(pluginFinalize.tokenLookup2);
|
||||
}
|
||||
eth_plugin_prepare_provide_token(&pluginProvideToken, token1, token2);
|
||||
if (!eth_plugin_call(NULL, ETH_PLUGIN_PROVIDE_TOKEN, (void*)&pluginProvideToken)) {
|
||||
PRINTF("Plugin provide token call failed\n");
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
pluginFinalize.result = pluginProvideToken.result;
|
||||
}
|
||||
if (pluginFinalize.result != ETH_PLUGIN_RESULT_FALLBACK) {
|
||||
// Handle the right interface
|
||||
switch(pluginFinalize.uiType) {
|
||||
case ETH_UI_TYPE_GENERIC:
|
||||
dataPresent = false;
|
||||
dataContext.tokenContext.pluginUiMaxItems = pluginFinalize.numScreens;
|
||||
break;
|
||||
case ETH_UI_TYPE_AMOUNT_ADDRESS:
|
||||
genericUI = true;
|
||||
dataPresent = false;
|
||||
if ((pluginFinalize.amount == NULL) || (pluginFinalize.address == NULL)) {
|
||||
PRINTF("Incorrect amount/address set by plugin\n");
|
||||
// Verify the chain
|
||||
if (chainConfig->chainId != 0) {
|
||||
uint32_t v = getV(&tmpContent.txContent);
|
||||
if (chainConfig->chainId != v) {
|
||||
reset_app_context();
|
||||
PRINTF("Invalid chainId %d expected %d\n", v, chainConfig->chainId);
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
memmove(tmpContent.txContent.value.value, pluginFinalize.amount, 32);
|
||||
tmpContent.txContent.value.length = 32;
|
||||
memmove(tmpContent.txContent.destination, pluginFinalize.address, 20);
|
||||
tmpContent.txContent.destinationLength = 20;
|
||||
if (token1 != NULL) {
|
||||
decimals = token1->decimals;
|
||||
ticker = token1->ticker;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PRINTF("ui type %d not supported\n", pluginFinalize.uiType);
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Store the hash
|
||||
cx_hash((cx_hash_t *) &global_sha3,
|
||||
CX_LAST,
|
||||
tmpCtx.transactionContext.hash,
|
||||
0,
|
||||
tmpCtx.transactionContext.hash,
|
||||
32);
|
||||
|
||||
// Finalize the plugin handling
|
||||
if (dataContext.tokenContext.pluginAvailable) {
|
||||
genericUI = false;
|
||||
eth_plugin_prepare_finalize(&pluginFinalize);
|
||||
if (!eth_plugin_call(NULL, ETH_PLUGIN_FINALIZE, (void *) &pluginFinalize)) {
|
||||
PRINTF("Plugin finalize call failed\n");
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Lookup tokens if requested
|
||||
if (pluginFinalize.tokenLookup1 != NULL) {
|
||||
ethPluginProvideToken_t pluginProvideToken;
|
||||
token1 = getKnownToken(pluginFinalize.tokenLookup1);
|
||||
if (pluginFinalize.tokenLookup2 != NULL) {
|
||||
token2 = getKnownToken(pluginFinalize.tokenLookup2);
|
||||
}
|
||||
eth_plugin_prepare_provide_token(&pluginProvideToken, token1, token2);
|
||||
if (!eth_plugin_call(NULL, ETH_PLUGIN_PROVIDE_TOKEN, (void *) &pluginProvideToken)) {
|
||||
PRINTF("Plugin provide token call failed\n");
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
pluginFinalize.result = pluginProvideToken.result;
|
||||
}
|
||||
if (pluginFinalize.result != ETH_PLUGIN_RESULT_FALLBACK) {
|
||||
// Handle the right interface
|
||||
switch (pluginFinalize.uiType) {
|
||||
case ETH_UI_TYPE_GENERIC:
|
||||
dataPresent = false;
|
||||
dataContext.tokenContext.pluginUiMaxItems = pluginFinalize.numScreens;
|
||||
break;
|
||||
case ETH_UI_TYPE_AMOUNT_ADDRESS:
|
||||
genericUI = true;
|
||||
dataPresent = false;
|
||||
if ((pluginFinalize.amount == NULL) || (pluginFinalize.address == NULL)) {
|
||||
PRINTF("Incorrect amount/address set by plugin\n");
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
memmove(tmpContent.txContent.value.value, pluginFinalize.amount, 32);
|
||||
tmpContent.txContent.value.length = 32;
|
||||
memmove(tmpContent.txContent.destination, pluginFinalize.address, 20);
|
||||
tmpContent.txContent.destinationLength = 20;
|
||||
if (token1 != NULL) {
|
||||
decimals = token1->decimals;
|
||||
ticker = token1->ticker;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PRINTF("ui type %d not supported\n", pluginFinalize.uiType);
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
genericUI = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataPresent && !N_storage.dataAllowed) {
|
||||
PRINTF("Data field forbidden\n");
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
genericUI = true;
|
||||
// Prepare destination address to display
|
||||
if (genericUI) {
|
||||
if (tmpContent.txContent.destinationLength != 0) {
|
||||
displayBuffer[0] = '0';
|
||||
displayBuffer[1] = 'x';
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination,
|
||||
(uint8_t *) displayBuffer + 2,
|
||||
&global_sha3,
|
||||
chainConfig);
|
||||
compareOrCopy(strings.common.fullAddress, displayBuffer, called_from_swap);
|
||||
} else {
|
||||
strcpy(strings.common.fullAddress, "Contract");
|
||||
}
|
||||
}
|
||||
// Prepare amount to display
|
||||
if (genericUI) {
|
||||
amountToString(tmpContent.txContent.value.value,
|
||||
tmpContent.txContent.value.length,
|
||||
decimals,
|
||||
(char *) ticker,
|
||||
displayBuffer,
|
||||
sizeof(displayBuffer));
|
||||
compareOrCopy(strings.common.fullAmount, displayBuffer, called_from_swap);
|
||||
}
|
||||
// Compute maximum fee
|
||||
if (genericUI) {
|
||||
computeFees(displayBuffer, sizeof(displayBuffer));
|
||||
compareOrCopy(strings.common.maxFee, displayBuffer, called_from_swap);
|
||||
}
|
||||
}
|
||||
|
||||
if (dataPresent && !N_storage.dataAllowed) {
|
||||
PRINTF("Data field forbidden\n");
|
||||
reportFinalizeError(direct);
|
||||
if (!direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Prepare destination address to display
|
||||
if (genericUI) {
|
||||
if (tmpContent.txContent.destinationLength != 0) {
|
||||
displayBuffer[0] = '0';
|
||||
displayBuffer[1] = 'x';
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination, (uint8_t*)displayBuffer+2, &global_sha3, chainConfig);
|
||||
compareOrCopy(strings.common.fullAddress, displayBuffer, called_from_swap);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(strings.common.fullAddress, "Contract");
|
||||
}
|
||||
}
|
||||
// Prepare amount to display
|
||||
if (genericUI) {
|
||||
amountToString(tmpContent.txContent.value.value, tmpContent.txContent.value.length, decimals, (char*)ticker, displayBuffer, sizeof(displayBuffer));
|
||||
compareOrCopy(strings.common.fullAmount, displayBuffer, called_from_swap);
|
||||
}
|
||||
// Compute maximum fee
|
||||
if (genericUI) {
|
||||
computeFees(displayBuffer, sizeof(displayBuffer));
|
||||
compareOrCopy(strings.common.maxFee, displayBuffer, called_from_swap);
|
||||
}
|
||||
bool no_consent = false;
|
||||
|
||||
bool no_consent = false;
|
||||
|
||||
no_consent = called_from_swap;
|
||||
no_consent = called_from_swap;
|
||||
|
||||
#ifdef NO_CONSENT
|
||||
no_consent = true;
|
||||
#endif // NO_CONSENT
|
||||
no_consent = true;
|
||||
#endif // NO_CONSENT
|
||||
|
||||
if(no_consent){
|
||||
io_seproxyhal_touch_tx_ok(NULL);
|
||||
}
|
||||
else{
|
||||
|
||||
if (genericUI) {
|
||||
ux_flow_init(0,
|
||||
((dataPresent && !N_storage.contractDetails) ? ux_approval_tx_data_warning_flow : ux_approval_tx_flow),
|
||||
NULL);
|
||||
if (no_consent) {
|
||||
io_seproxyhal_touch_tx_ok(NULL);
|
||||
} else {
|
||||
if (genericUI) {
|
||||
ux_flow_init(
|
||||
0,
|
||||
((dataPresent && !N_storage.contractDetails) ? ux_approval_tx_data_warning_flow
|
||||
: ux_approval_tx_flow),
|
||||
NULL);
|
||||
} else {
|
||||
plugin_ui_start();
|
||||
}
|
||||
}
|
||||
else {
|
||||
plugin_ui_start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,34 +10,38 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
|
||||
uint32_t tx = 0;
|
||||
uint32_t v = getV(&tmpContent.txContent);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1, tmpCtx.transactionContext.bip32Path,
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1,
|
||||
tmpCtx.transactionContext.bip32Path,
|
||||
tmpCtx.transactionContext.pathLength,
|
||||
privateKeyData, NULL);
|
||||
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32,
|
||||
&privateKey);
|
||||
privateKeyData,
|
||||
NULL);
|
||||
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
|
||||
explicit_bzero(privateKeyData, sizeof(privateKeyData));
|
||||
unsigned int info = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
signatureLength =
|
||||
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
|
||||
tmpCtx.transactionContext.hash,
|
||||
sizeof(tmpCtx.transactionContext.hash), signature, sizeof(signature), &info);
|
||||
signatureLength = cx_ecdsa_sign(&privateKey,
|
||||
CX_RND_RFC6979 | CX_LAST,
|
||||
CX_SHA256,
|
||||
tmpCtx.transactionContext.hash,
|
||||
sizeof(tmpCtx.transactionContext.hash),
|
||||
signature,
|
||||
sizeof(signature),
|
||||
&info);
|
||||
explicit_bzero(&privateKey, sizeof(privateKey));
|
||||
// Parity is present in the sequence tag in the legacy API
|
||||
if (tmpContent.txContent.vLength == 0) {
|
||||
// Legacy API
|
||||
G_io_apdu_buffer[0] = 27;
|
||||
}
|
||||
else {
|
||||
// New API
|
||||
// Note that this is wrong for a large v, but the client can always recover
|
||||
G_io_apdu_buffer[0] = (v * 2) + 35;
|
||||
// Legacy API
|
||||
G_io_apdu_buffer[0] = 27;
|
||||
} else {
|
||||
// New API
|
||||
// Note that this is wrong for a large v, but the client can always recover
|
||||
G_io_apdu_buffer[0] = (v * 2) + 35;
|
||||
}
|
||||
if (info & CX_ECCINFO_PARITY_ODD) {
|
||||
G_io_apdu_buffer[0]++;
|
||||
G_io_apdu_buffer[0]++;
|
||||
}
|
||||
if (info & CX_ECCINFO_xGTn) {
|
||||
G_io_apdu_buffer[0] += 2;
|
||||
G_io_apdu_buffer[0] += 2;
|
||||
}
|
||||
format_signature_out(signature);
|
||||
tx = 65;
|
||||
@@ -45,13 +49,13 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
|
||||
if(called_from_swap){
|
||||
if (called_from_swap) {
|
||||
os_sched_exit(0);
|
||||
}
|
||||
reset_app_context();
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) {
|
||||
@@ -62,31 +66,31 @@ unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) {
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) {
|
||||
parserStatus_e txResult = USTREAM_FINISHED;
|
||||
txResult = continueTx(&txContext);
|
||||
switch (txResult) {
|
||||
case USTREAM_SUSPENDED:
|
||||
break;
|
||||
case USTREAM_FINISHED:
|
||||
break;
|
||||
case USTREAM_PROCESSING:
|
||||
io_seproxyhal_send_status(0x9000);
|
||||
ui_idle();
|
||||
break;
|
||||
case USTREAM_FAULT:
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
break;
|
||||
default:
|
||||
PRINTF("Unexpected parser status\n");
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
case USTREAM_SUSPENDED:
|
||||
break;
|
||||
case USTREAM_FINISHED:
|
||||
break;
|
||||
case USTREAM_PROCESSING:
|
||||
io_seproxyhal_send_status(0x9000);
|
||||
ui_idle();
|
||||
break;
|
||||
case USTREAM_FAULT:
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
break;
|
||||
default:
|
||||
PRINTF("Unexpected parser status\n");
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
}
|
||||
|
||||
if (txResult == USTREAM_FINISHED) {
|
||||
@@ -101,6 +105,5 @@ unsigned int io_seproxyhal_touch_data_cancel(const bagl_element_t *e) {
|
||||
io_seproxyhal_send_status(0x6985);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
return 0; // do not redraw the widget
|
||||
return 0; // do not redraw the widget
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "shared_context.h"
|
||||
#include "ui_callbacks.h"
|
||||
|
||||
// clang-format off
|
||||
UX_STEP_NOCB(
|
||||
ux_confirm_selector_flow_1_step,
|
||||
pnn,
|
||||
@@ -33,15 +34,16 @@ UX_STEP_CB(
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
// clang-format on
|
||||
|
||||
UX_FLOW(ux_confirm_selector_flow,
|
||||
&ux_confirm_selector_flow_1_step,
|
||||
&ux_confirm_selector_flow_2_step,
|
||||
&ux_confirm_selector_flow_3_step,
|
||||
&ux_confirm_selector_flow_4_step
|
||||
);
|
||||
UX_FLOW(ux_confirm_selector_flow,
|
||||
&ux_confirm_selector_flow_1_step,
|
||||
&ux_confirm_selector_flow_2_step,
|
||||
&ux_confirm_selector_flow_3_step,
|
||||
&ux_confirm_selector_flow_4_step);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// clang-format off
|
||||
UX_STEP_NOCB(
|
||||
ux_confirm_parameter_flow_1_step,
|
||||
pnn,
|
||||
@@ -73,15 +75,16 @@ UX_STEP_CB(
|
||||
&C_icon_crossmark,
|
||||
"Reject",
|
||||
});
|
||||
// clang-format on
|
||||
|
||||
UX_FLOW(ux_confirm_parameter_flow,
|
||||
&ux_confirm_parameter_flow_1_step,
|
||||
&ux_confirm_parameter_flow_2_step,
|
||||
&ux_confirm_parameter_flow_3_step,
|
||||
&ux_confirm_parameter_flow_4_step
|
||||
);
|
||||
&ux_confirm_parameter_flow_1_step,
|
||||
&ux_confirm_parameter_flow_2_step,
|
||||
&ux_confirm_parameter_flow_3_step,
|
||||
&ux_confirm_parameter_flow_4_step);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// clang-format off
|
||||
UX_STEP_NOCB(ux_approval_tx_1_step,
|
||||
pnn,
|
||||
{
|
||||
@@ -135,23 +138,21 @@ UX_STEP_NOCB(ux_approval_tx_data_warning_step,
|
||||
"Data",
|
||||
"Present",
|
||||
});
|
||||
|
||||
// clang-format on
|
||||
|
||||
UX_FLOW(ux_approval_tx_flow,
|
||||
&ux_approval_tx_1_step,
|
||||
&ux_approval_tx_2_step,
|
||||
&ux_approval_tx_3_step,
|
||||
&ux_approval_tx_4_step,
|
||||
&ux_approval_tx_5_step,
|
||||
&ux_approval_tx_6_step
|
||||
);
|
||||
&ux_approval_tx_1_step,
|
||||
&ux_approval_tx_2_step,
|
||||
&ux_approval_tx_3_step,
|
||||
&ux_approval_tx_4_step,
|
||||
&ux_approval_tx_5_step,
|
||||
&ux_approval_tx_6_step);
|
||||
|
||||
UX_FLOW(ux_approval_tx_data_warning_flow,
|
||||
&ux_approval_tx_1_step,
|
||||
&ux_approval_tx_data_warning_step,
|
||||
&ux_approval_tx_2_step,
|
||||
&ux_approval_tx_3_step,
|
||||
&ux_approval_tx_4_step,
|
||||
&ux_approval_tx_5_step,
|
||||
&ux_approval_tx_6_step
|
||||
);
|
||||
&ux_approval_tx_1_step,
|
||||
&ux_approval_tx_data_warning_step,
|
||||
&ux_approval_tx_2_step,
|
||||
&ux_approval_tx_3_step,
|
||||
&ux_approval_tx_4_step,
|
||||
&ux_approval_tx_5_step,
|
||||
&ux_approval_tx_6_step);
|
||||
Reference in New Issue
Block a user