Add setting to display detailed fees

This commit is contained in:
pscott
2021-06-11 11:37:16 +02:00
parent bb6f65ad75
commit 0bff1de52c
9 changed files with 169 additions and 60 deletions

View File

@@ -61,6 +61,7 @@ void handle_swap_sign_transaction(chain_config_t* config) {
storage.contractDetails = 0x00;
storage.initialized = 0x01;
storage.displayNonce = 0x00;
storage.contractDetails = 0x00;
nvm_write((void*) &N_storage, (void*) &storage, sizeof(internalStorage_t));
}

View File

@@ -49,7 +49,6 @@ strings_t strings;
cx_sha3_t global_sha3;
uint8_t appState;
bool dataPresent;
bool called_from_swap;
bool externalPluginIsSet;
#ifdef HAVE_STARKWARE
@@ -779,6 +778,7 @@ void coin_main(chain_config_t *coin_config) {
#endif
storage.contractDetails = 0x00;
storage.displayNonce = 0x00;
storage.displayFeeDetails = 0x00;
storage.initialized = 0x01;
nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t));
}

View File

@@ -30,6 +30,7 @@ typedef struct internalStorage_t {
unsigned char dataAllowed;
unsigned char contractDetails;
unsigned char displayNonce;
unsigned char displayFeeDetails;
uint8_t initialized;
} internalStorage_t;
@@ -165,7 +166,8 @@ typedef enum {
typedef struct txStringProperties_t {
char fullAddress[43];
char fullAmount[50];
char maxFee[50];
char maxFee[50]; // Used as BaseFee when detailing fees
char priorityFee[50];
char nonce[8]; // 10M tx per account ought to be enough for everybody
char chainID[8]; // 10M different chainID ought to be enough for people to find a unique
// chainID for their token / chain.
@@ -195,7 +197,6 @@ extern cx_sha3_t global_sha3;
extern const internalStorage_t N_storage_real;
extern bool called_from_swap;
extern bool dataPresent;
extern bool externalPluginIsSet;
extern uint8_t appState;
#ifdef HAVE_STARKWARE

View File

@@ -5,6 +5,7 @@ void display_settings(const ux_flow_step_t* const start_step);
void switch_settings_contract_data(void);
void switch_settings_display_data(void);
void switch_settings_display_nonce(void);
void switch_settings_display_fee_details(void);
//////////////////////////////////////////////////////////////////////
// clang-format off
@@ -78,6 +79,15 @@ UX_STEP_CB(
.text = strings.common.fullAddress + 26
});
UX_STEP_CB(
ux_settings_flow_4_step,
bnnn_paging,
switch_settings_display_fee_details(),
{
.title = "Fee Details",
.text = strings.common.fullAddress + 40
});
#else
UX_STEP_CB(
@@ -113,10 +123,21 @@ UX_STEP_CB(
strings.common.fullAddress + 26
});
UX_STEP_CB(
ux_settings_flow_4_step,
bnnn,
switch_settings_display_fee_details(),
{
"Fee Details",
"Display fee details",
"when possible",
strings.common.fullAddress + 40
});
#endif
UX_STEP_CB(
ux_settings_flow_4_step,
ux_settings_flow_5_step,
pb,
ui_idle(),
{
@@ -129,7 +150,8 @@ UX_FLOW(ux_settings_flow,
&ux_settings_flow_1_step,
&ux_settings_flow_2_step,
&ux_settings_flow_3_step,
&ux_settings_flow_4_step);
&ux_settings_flow_4_step,
&ux_settings_flow_5_step);
void display_settings(const ux_flow_step_t* const start_step) {
strcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed"));
@@ -137,6 +159,8 @@ void display_settings(const ux_flow_step_t* const start_step) {
(N_storage.contractDetails ? "Displayed" : "NOT Displayed"));
strcpy(strings.common.fullAddress + 26,
(N_storage.displayNonce ? "Displayed" : "NOT Displayed"));
strcpy(strings.common.fullAddress + 40,
(N_storage.displayFeeDetails ? "Displayed" : "NOT Displayed"));
ux_flow_init(0, ux_settings_flow, start_step);
}
@@ -157,3 +181,9 @@ void switch_settings_display_nonce() {
nvm_write((void*) &N_storage.displayNonce, (void*) &value, sizeof(uint8_t));
display_settings(&ux_settings_flow_3_step);
}
void switch_settings_display_fee_details() {
uint8_t value = (N_storage.displayFeeDetails ? 0 : 1);
nvm_write((void*) &N_storage.displayFeeDetails, (void*) &value, sizeof(uint8_t));
display_settings(&ux_settings_flow_4_step);
}

View File

@@ -179,14 +179,12 @@ static void processMaxPriorityFeePerGas(txContext_t *context) {
THROW(EXCEPTION);
}
if (context->currentFieldPos < context->currentFieldLength) {
uint8_t tmp[100];
uint32_t copySize =
MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
// copyTxData(context, NULL, copySize);
copyTxData(context, &tmp, copySize);
copyTxData(context, context->content->maxPriorityFeePerGas.value + context->currentFieldPos, copySize);
}
if (context->currentFieldPos == context->currentFieldLength) {
// context->content->nonce.length = context->currentFieldLength;
context->content->maxPriorityFeePerGas.length = context->currentFieldLength;
context->currentField++;
context->processingField = false;
}
@@ -286,6 +284,26 @@ static void processData(txContext_t *context) {
PRINTF("Invalid type for RLP_DATA\n");
THROW(EXCEPTION);
}
if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize =
MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
// If there is no data, set dataPresent to false.
if (copySize == 1 && *context->workBuffer == 0x00) {
context->content->dataPresent = false;
}
copyTxData(context, NULL, copySize);
}
if (context->currentFieldPos == context->currentFieldLength) {
context->currentField++;
context->processingField = false;
}
}
static void processAndDiscard(txContext_t *context) {
if (context->currentFieldIsList) {
PRINTF("Invalid type for Discarded field\n");
THROW(EXCEPTION);
}
if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize =
MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
@@ -319,7 +337,6 @@ static void processV(txContext_t *context) {
}
static bool processEIP1559Tx(txContext_t *context) {
PRINTF("1559\n");
switch (context->currentField) {
case EIP1559_RLP_CONTENT: {
processContent(context);
@@ -375,7 +392,7 @@ static bool processEIP1559Tx(txContext_t *context) {
}
case EIP1559_RLP_SENDER_R:
case EIP1559_RLP_SENDER_S:
processData(context);
processAndDiscard(context);
break;
default:
PRINTF("Invalid RLP decoder context\n");
@@ -417,14 +434,15 @@ static bool processEIP2930Tx(txContext_t *context) {
case EIP2930_RLP_YPARITY:
processV(context);
break;
case EIP2930_RLP_DATA:
processData(context);
break;
case EIP2930_RLP_ACCESS_LIST:
processAccessList(context);
break;
case EIP2930_RLP_DATA:
case EIP2930_RLP_SENDER_R:
case EIP2930_RLP_SENDER_S:
processData(context);
PRINTF("DONE\n");
processAndDiscard(context);
break;
default:
PRINTF("Invalid RLP decoder context\n");
@@ -461,9 +479,11 @@ static bool processLegacyTx(txContext_t *context) {
processValue(context);
break;
case LEGACY_RLP_DATA:
processData(context);
break;
case LEGACY_RLP_R:
case LEGACY_RLP_S:
processData(context);
processAndDiscard(context);
break;
case LEGACY_RLP_V:
processV(context);

View File

@@ -83,8 +83,8 @@ typedef enum rlpEIP2930TxField_e {
typedef enum rlpEIP1559TxField_e {
EIP1559_RLP_NONE = RLP_NONE,
EIP1559_RLP_TYPE, // For wanchain
EIP1559_RLP_CONTENT,
EIP1559_RLP_TYPE, // For wanchain
EIP1559_RLP_CHAINID,
EIP1559_RLP_NONCE,
EIP1559_RLP_MAX_PRIORITY_FEE_PER_GAS,
@@ -125,8 +125,9 @@ typedef struct txInt256_t {
} txInt256_t;
typedef struct txContent_t {
txInt256_t gasprice;
txInt256_t startgas;
txInt256_t gasprice; // Used as MaxFeePerGas when dealing with EIP1559 transactions.
txInt256_t startgas; // Also known as `gasLimit`.
txInt256_t maxPriorityFeePerGas;
txInt256_t value;
txInt256_t nonce;
txInt256_t chainID;
@@ -134,6 +135,7 @@ typedef struct txContent_t {
uint8_t destinationLength;
uint8_t v[4];
uint8_t vLength;
bool dataPresent;
} txContent_t;
typedef struct txContext_t {

View File

@@ -38,7 +38,7 @@ void handleSign(uint8_t p1,
workBuffer += 4;
dataLength -= 4;
}
dataPresent = false;
tmpContent.txContent.dataPresent = false;
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_UNAVAILABLE;
// EIP 2718: TransactionType might be present before the TransactionPayload.
@@ -89,7 +89,6 @@ void handleSign(uint8_t p1,
THROW(0x6A80);
}
PRINTF("FINALIZE\n");
if (txResult == USTREAM_FINISHED) {
finalizeParsing(false);
}

View File

@@ -32,7 +32,7 @@ customStatus_e customProcessor(txContext_t *context) {
(context->txType == EIP2930 && context->currentField == EIP2930_RLP_DATA) ||
(context->txType == EIP1559 && context->currentField == EIP1559_RLP_DATA)) &&
(context->currentFieldLength != 0)) {
dataPresent = true;
context->content->dataPresent = true;
// If handling a new contract rather than a function call, abort immediately
if (tmpContent.txContent.destinationLength == 0) {
return CUSTOM_NOT_HANDLED;
@@ -194,27 +194,31 @@ void reportFinalizeError(bool direct) {
}
}
void computeFees(char *displayBuffer, uint32_t displayBufferSize) {
uint256_t gasPrice, startGas, uint256;
void computeFees(const txInt256_t *BEgasPrice, const txInt256_t *BEgasLimit, uint256_t *output) {
uint256_t gasPrice = {0};
uint256_t gasLimit = {0};
PRINTF("Gas price %.*H\n",
BEgasPrice->length,
BEgasPrice->value);
PRINTF("Gas limit %.*H\n",
BEgasLimit->length,
BEgasLimit->value);
convertUint256BE(BEgasPrice->value,
BEgasPrice->length,
&gasPrice);
convertUint256BE(BEgasLimit->value,
BEgasLimit->length,
&gasLimit);
mul256(&gasPrice, &gasLimit, output);
}
void feesToString(const uint256_t *rawFee, char *displayBuffer, uint32_t displayBufferSize) {
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);
tostring256(rawFee, 10, (char *) (G_io_apdu_buffer + 100), 100);
i = 0;
while (G_io_apdu_buffer[100 + i]) {
i++;
@@ -236,6 +240,38 @@ void computeFees(char *displayBuffer, uint32_t displayBufferSize) {
i++;
}
displayBuffer[tickerOffset + i] = '\0';
PRINTF("Displayed fees: %s\n", displayBuffer);
}
// Compute the fees, transform it to a string, prepend a ticker to it and copy everything to `displayBuffer`.
void prepareFees(const txInt256_t *BEGasPrice, const txInt256_t *BEGasLimit, char *displayBuffer, uint32_t displayBufferSize) {
uint256_t rawFee = {0};
computeFees(BEGasPrice, BEGasLimit, &rawFee);
feesToString(&rawFee, displayBuffer, displayBufferSize);
}
void prepareAndCopyDetailedFees(char *displayBuffer, uint32_t displayBufferSize) {
uint256_t rawPriorityFee = {0};
uint256_t rawMaxFee = {0};
uint256_t rawBaseFee = {0};
// Compute the priorityFee and the maxFee.
computeFees(&tmpContent.txContent.maxPriorityFeePerGas, &tmpContent.txContent.startgas, &rawPriorityFee);
computeFees(&tmpContent.txContent.gasprice, &tmpContent.txContent.startgas, &rawMaxFee);
// Substract priorityFee from maxFee -> this is the baseFee
minus256(&rawMaxFee, &rawPriorityFee, &rawBaseFee);
// Transform priorityFee to string (with a ticker).
PRINTF("Computing priority fee\n");
feesToString(&rawPriorityFee, displayBuffer, displayBufferSize);
// Copy it to destination.
compareOrCopy(strings.common.priorityFee, displayBuffer, called_from_swap);
PRINTF("Computing base fee\n");
// Transform priorityFee to string (with a ticker).
feesToString(&rawBaseFee, displayBuffer, displayBufferSize);
// Copy it to destination.
compareOrCopy(strings.common.maxFee, displayBuffer, called_from_swap);
}
void finalizeParsing(bool direct) {
@@ -279,7 +315,6 @@ void finalizeParsing(bool direct) {
32);
// Finalize the plugin handling
PRINTF("1\n");
if (dataContext.tokenContext.pluginStatus >= ETH_PLUGIN_RESULT_SUCCESSFUL) {
genericUI = false;
eth_plugin_prepare_finalize(&pluginFinalize);
@@ -322,7 +357,7 @@ void finalizeParsing(bool direct) {
// Handle the right interface
switch (pluginFinalize.uiType) {
case ETH_UI_TYPE_GENERIC:
dataPresent = false;
tmpContent.txContent.dataPresent = false;
// Add the number of screens + the number of additional screens to get the total
// number of screens needed.
dataContext.tokenContext.pluginUiMaxItems =
@@ -330,7 +365,7 @@ void finalizeParsing(bool direct) {
break;
case ETH_UI_TYPE_AMOUNT_ADDRESS:
genericUI = true;
dataPresent = false;
tmpContent.txContent.dataPresent = false;
if ((pluginFinalize.amount == NULL) || (pluginFinalize.address == NULL)) {
PRINTF("Incorrect amount/address set by plugin\n");
reportFinalizeError(direct);
@@ -359,8 +394,7 @@ void finalizeParsing(bool direct) {
}
}
PRINTF("2\n");
if (dataPresent && !N_storage.dataAllowed) {
if (tmpContent.txContent.dataPresent && !N_storage.dataAllowed) {
reportFinalizeError(direct);
if (!direct) {
return;
@@ -401,8 +435,12 @@ void finalizeParsing(bool direct) {
}
// Compute maximum fee
if (genericUI) {
computeFees(displayBuffer, sizeof(displayBuffer));
compareOrCopy(strings.common.maxFee, displayBuffer, called_from_swap);
if (N_storage.displayFeeDetails) {
prepareAndCopyDetailedFees(displayBuffer, sizeof(displayBuffer));
} else {
prepareFees(&tmpContent.txContent.gasprice, &tmpContent.txContent.startgas, displayBuffer, sizeof(displayBuffer));
compareOrCopy(strings.common.maxFee, displayBuffer, called_from_swap);
}
}
// Prepare chainID field
@@ -429,7 +467,6 @@ void finalizeParsing(bool direct) {
return;
}
}
PRINTF("3\n");
bool no_consent;
@@ -443,7 +480,7 @@ void finalizeParsing(bool direct) {
io_seproxyhal_touch_tx_ok(NULL);
} else {
if (genericUI) {
ux_approve_tx(dataPresent);
ux_approve_tx(tmpContent.txContent.dataPresent);
} else {
plugin_ui_start();
}

View File

@@ -108,6 +108,20 @@ UX_STEP_NOCB(
.title = "Address",
.text = strings.common.fullAddress,
});
UX_STEP_NOCB(
ux_approval_base_fee_step,
bnnn_paging,
{
.title = "Base Fee",
.text = strings.common.maxFee,
});
UX_STEP_NOCB(
ux_approval_priority_fee_step,
bnnn_paging,
{
.title = "Priority Fee",
.text = strings.common.priorityFee,
});
UX_STEP_NOCB(
ux_approval_fees_step,
bnnn_paging,
@@ -157,18 +171,18 @@ UX_STEP_NOCB(ux_approval_data_warning_step,
});
// clang-format on
const ux_flow_step_t *ux_approval_tx_flow_[10];
const ux_flow_step_t *ux_approval_tx_flow[12];
void ux_approve_tx(bool dataPresent) {
int step = 0;
ux_approval_tx_flow_[step++] = &ux_approval_review_step;
if (dataPresent && !N_storage.contractDetails) {
ux_approval_tx_flow_[step++] = &ux_approval_data_warning_step;
ux_approval_tx_flow[step++] = &ux_approval_review_step;
if (tmpContent.txContent.dataPresent && !N_storage.contractDetails) {
ux_approval_tx_flow[step++] = &ux_approval_data_warning_step;
}
ux_approval_tx_flow_[step++] = &ux_approval_amount_step;
ux_approval_tx_flow_[step++] = &ux_approval_address_step;
ux_approval_tx_flow[step++] = &ux_approval_amount_step;
ux_approval_tx_flow[step++] = &ux_approval_address_step;
if (N_storage.displayNonce) {
ux_approval_tx_flow_[step++] = &ux_approval_nonce_step;
ux_approval_tx_flow[step++] = &ux_approval_nonce_step;
}
uint32_t id;
@@ -182,12 +196,17 @@ void ux_approve_tx(bool dataPresent) {
THROW(0x6501);
}
if (id != ETHEREUM_MAINNET_CHAINID) {
ux_approval_tx_flow_[step++] = &ux_approval_chainid_step;
ux_approval_tx_flow[step++] = &ux_approval_chainid_step;
}
ux_approval_tx_flow_[step++] = &ux_approval_fees_step;
ux_approval_tx_flow_[step++] = &ux_approval_accept_step;
ux_approval_tx_flow_[step++] = &ux_approval_reject_step;
ux_approval_tx_flow_[step++] = FLOW_END_STEP;
if (txContext.txType == EIP1559 && N_storage.displayFeeDetails) {
ux_approval_tx_flow[step++] = &ux_approval_base_fee_step;
ux_approval_tx_flow[step++] = &ux_approval_priority_fee_step;
} else {
ux_approval_tx_flow[step++] = &ux_approval_fees_step;
}
ux_approval_tx_flow[step++] = &ux_approval_accept_step;
ux_approval_tx_flow[step++] = &ux_approval_reject_step;
ux_approval_tx_flow[step++] = FLOW_END_STEP;
ux_flow_init(0, ux_approval_tx_flow_, NULL);
ux_flow_init(0, ux_approval_tx_flow, NULL);
}