Add setting to display detailed fees
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user