Files
app-ethereum/src/main.c

882 lines
30 KiB
C
Raw Normal View History

2016-06-01 21:41:29 +02:00
/*******************************************************************************
2020-12-01 16:20:13 +01:00
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
2016-06-01 21:41:29 +02:00
2020-06-27 13:24:04 +02:00
#include "shared_context.h"
#include "apdu_constants.h"
#include "ui_callbacks.h"
#include "ui_flow.h"
2020-06-27 13:24:04 +02:00
#include "os_io_seproxyhal.h"
2020-06-27 13:24:04 +02:00
#include "glyphs.h"
#include "utils.h"
2020-06-29 15:43:02 +02:00
#include "swap_lib_calls.h"
#include "handle_swap_sign_transaction.h"
#include "handle_get_printable_amount.h"
#include "handle_check_address.h"
2020-06-27 13:24:04 +02:00
#ifdef HAVE_STARKWARE
#include "stark_crypto.h"
#endif
2020-06-27 13:24:04 +02:00
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
2020-06-27 13:24:04 +02:00
void ui_idle(void);
2020-06-27 13:24:04 +02:00
uint32_t set_result_get_publicKey(void);
void finalizeParsing(bool);
2020-06-27 13:24:04 +02:00
tmpCtx_t tmpCtx;
txContext_t txContext;
tmpContent_t tmpContent;
dataContext_t dataContext;
strings_t strings;
2020-06-29 15:43:02 +02:00
cx_sha3_t global_sha3;
2020-06-27 13:24:04 +02:00
uint8_t appState;
bool dataPresent;
2020-06-29 15:43:02 +02:00
bool called_from_swap;
2020-06-27 13:24:04 +02:00
#ifdef HAVE_STARKWARE
bool quantumSet;
#endif
2021-03-24 16:32:08 +01:00
2020-10-27 11:16:50 +01:00
#ifdef HAVE_ETH2
2021-03-24 16:32:08 +01:00
uint32_t eth2WithdrawalIndex;
#include "withdrawal_index.h"
2020-10-27 11:16:50 +01:00
#endif
2020-06-27 13:24:04 +02:00
#include "ux.h"
ux_state_t G_ux;
bolos_ux_params_t G_ux_params;
2020-06-27 13:24:04 +02:00
const internalStorage_t N_storage_real;
2020-06-27 13:24:04 +02:00
chain_config_t *chainConfig;
2020-06-27 13:24:04 +02:00
void reset_app_context() {
2020-12-01 16:20:13 +01:00
// PRINTF("!!RESET_APP_CONTEXT\n");
appState = APP_STATE_IDLE;
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
called_from_swap = false;
2020-06-29 15:43:02 +02:00
#ifdef HAVE_STARKWARE
2020-12-01 16:20:13 +01:00
quantumSet = false;
2020-10-27 11:16:50 +01:00
#endif
#ifdef HAVE_ETH2
2020-12-01 16:20:13 +01:00
eth2WithdrawalIndex = 0;
2020-06-29 15:43:02 +02:00
#endif
2020-12-01 16:20:13 +01:00
memset((uint8_t *) &txContext, 0, sizeof(txContext));
memset((uint8_t *) &tmpContent, 0, sizeof(tmpContent));
2020-06-27 13:24:04 +02:00
}
2018-07-31 19:59:59 +02:00
void ui_idle(void) {
// reserve a display stack slot if none yet
2020-12-01 16:20:13 +01:00
if (G_ux.stack_count == 0) {
ux_stack_push();
}
2019-03-18 14:03:54 +01:00
ux_flow_init(0, ux_idle_flow, NULL);
2017-01-22 18:26:27 +01:00
}
unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e) {
2016-06-01 21:41:29 +02:00
// Go back to the dashboard
os_sched_exit(0);
2020-12-01 16:20:13 +01:00
return 0; // do not redraw the widget
2016-06-01 21:41:29 +02:00
}
#if defined(TARGET_NANOS)
2018-07-27 21:02:24 +02:00
unsigned int ui_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) {
2020-12-01 16:20:13 +01:00
switch (button_mask) {
case BUTTON_EVT_RELEASED | BUTTON_LEFT: // CANCEL
io_seproxyhal_touch_address_cancel(NULL);
2018-07-27 21:02:24 +02:00
break;
2020-12-01 16:20:13 +01:00
case BUTTON_EVT_RELEASED | BUTTON_RIGHT: { // OK
io_seproxyhal_touch_address_ok(NULL);
break;
2018-07-27 21:02:24 +02:00
}
}
return 0;
}
2020-12-01 16:20:13 +01:00
#endif // #if defined(TARGET_NANOS)
2018-07-31 19:59:59 +02:00
void io_seproxyhal_send_status(uint32_t sw) {
G_io_apdu_buffer[0] = ((sw >> 8) & 0xff);
G_io_apdu_buffer[1] = (sw & 0xff);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
}
2020-12-01 16:20:13 +01:00
void format_signature_out(const uint8_t *signature) {
memset(G_io_apdu_buffer + 1, 0x00, 64);
uint8_t offset = 1;
uint8_t xoffset = 4; // point to r value
// copy r
uint8_t xlength = signature[xoffset - 1];
if (xlength == 33) {
xlength = 32;
xoffset++;
}
memmove(G_io_apdu_buffer + offset + 32 - xlength, signature + xoffset, xlength);
offset += 32;
xoffset += xlength + 2; // move over rvalue and TagLEn
// copy s value
xlength = signature[xoffset - 1];
if (xlength == 33) {
xlength = 32;
xoffset++;
}
memmove(G_io_apdu_buffer + offset + 32 - xlength, signature + xoffset, xlength);
}
2016-06-01 21:41:29 +02:00
unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
switch (channel & ~(IO_FLAGS)) {
2020-12-01 16:20:13 +01:00
case CHANNEL_KEYBOARD:
break;
2016-06-01 21:41:29 +02:00
2020-12-01 16:20:13 +01:00
// multiplexed io exchange over a SPI channel and TLV encapsulated protocol
case CHANNEL_SPI:
if (tx_len) {
io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);
2016-06-01 21:41:29 +02:00
2020-12-01 16:20:13 +01:00
if (channel & IO_RESET_AFTER_REPLIED) {
reset();
}
return 0; // nothing received from the master so far (it's a tx
// transaction)
} else {
return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0);
2016-06-01 21:41:29 +02:00
}
2020-12-01 16:20:13 +01:00
default:
THROW(INVALID_PARAMETER);
2016-06-01 21:41:29 +02:00
}
return 0;
}
2020-12-01 16:20:13 +01:00
tokenDefinition_t *getKnownToken(uint8_t *contractAddress) {
2018-07-31 19:59:59 +02:00
tokenDefinition_t *currentToken = NULL;
2019-03-18 14:03:54 +01:00
#ifdef HAVE_TOKENS_LIST
2018-07-31 19:59:59 +02:00
uint32_t numTokens = 0;
uint32_t i;
2020-12-01 16:20:13 +01:00
switch (chainConfig->kind) {
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_AKROMA:
numTokens = NUM_TOKENS_AKROMA;
break;
case CHAIN_KIND_ETHEREUM:
numTokens = NUM_TOKENS_ETHEREUM;
break;
case CHAIN_KIND_ETHEREUM_CLASSIC:
numTokens = NUM_TOKENS_ETHEREUM_CLASSIC;
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_PIRL:
numTokens = NUM_TOKENS_PIRL;
break;
case CHAIN_KIND_POA:
numTokens = NUM_TOKENS_POA;
break;
case CHAIN_KIND_ARTIS_SIGMA1:
numTokens = NUM_TOKENS_ARTIS_SIGMA1;
break;
case CHAIN_KIND_ARTIS_TAU1:
numTokens = NUM_TOKENS_ARTIS_TAU1;
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_RSK:
numTokens = NUM_TOKENS_RSK;
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_EXPANSE:
numTokens = NUM_TOKENS_EXPANSE;
break;
case CHAIN_KIND_UBIQ:
numTokens = NUM_TOKENS_UBIQ;
break;
case CHAIN_KIND_WANCHAIN:
numTokens = NUM_TOKENS_WANCHAIN;
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_KUSD:
numTokens = NUM_TOKENS_KUSD;
break;
case CHAIN_KIND_MUSICOIN:
numTokens = NUM_TOKENS_MUSICOIN;
break;
case CHAIN_KIND_CALLISTO:
numTokens = NUM_TOKENS_CALLISTO;
break;
case CHAIN_KIND_ETHERSOCIAL:
numTokens = NUM_TOKENS_ETHERSOCIAL;
break;
case CHAIN_KIND_ELLAISM:
numTokens = NUM_TOKENS_ELLAISM;
break;
2018-08-05 02:19:44 -04:00
case CHAIN_KIND_ETHER1:
numTokens = NUM_TOKENS_ETHER1;
break;
case CHAIN_KIND_ETHERGEM:
numTokens = NUM_TOKENS_ETHERGEM;
break;
case CHAIN_KIND_ATHEIOS:
numTokens = NUM_TOKENS_ATHEIOS;
break;
case CHAIN_KIND_GOCHAIN:
numTokens = NUM_TOKENS_GOCHAIN;
break;
case CHAIN_KIND_MIX:
numTokens = NUM_TOKENS_MIX;
break;
case CHAIN_KIND_REOSC:
numTokens = NUM_TOKENS_REOSC;
break;
case CHAIN_KIND_HPB:
numTokens = NUM_TOKENS_HPB;
break;
2019-02-06 08:03:49 +00:00
case CHAIN_KIND_TOMOCHAIN:
numTokens = NUM_TOKENS_TOMOCHAIN;
break;
2019-01-31 17:38:12 +01:00
case CHAIN_KIND_TOBALABA:
numTokens = NUM_TOKENS_TOBALABA;
break;
case CHAIN_KIND_DEXON:
numTokens = NUM_TOKENS_DEXON;
break;
case CHAIN_KIND_VOLTA:
numTokens = NUM_TOKENS_VOLTA;
break;
case CHAIN_KIND_EWC:
numTokens = NUM_TOKENS_EWC;
break;
case CHAIN_KIND_WEBCHAIN:
numTokens = NUM_TOKENS_WEBCHAIN;
break;
case CHAIN_KIND_THUNDERCORE:
numTokens = NUM_TOKENS_THUNDERCORE;
break;
2018-07-31 19:59:59 +02:00
}
2020-12-01 16:20:13 +01:00
for (i = 0; i < numTokens; i++) {
switch (chainConfig->kind) {
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_AKROMA:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_AKROMA[i]);
2018-07-31 19:59:59 +02:00
break;
case CHAIN_KIND_ETHEREUM:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHEREUM[i]);
2018-07-31 19:59:59 +02:00
break;
case CHAIN_KIND_ETHEREUM_CLASSIC:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHEREUM_CLASSIC[i]);
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_PIRL:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_PIRL[i]);
2018-07-31 19:59:59 +02:00
break;
case CHAIN_KIND_POA:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_POA[i]);
break;
case CHAIN_KIND_ARTIS_SIGMA1:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ARTIS_SIGMA1[i]);
break;
case CHAIN_KIND_ARTIS_TAU1:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ARTIS_TAU1[i]);
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_RSK:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_RSK[i]);
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_EXPANSE:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_EXPANSE[i]);
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_UBIQ:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_UBIQ[i]);
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_WANCHAIN:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_WANCHAIN[i]);
break;
2018-07-31 19:59:59 +02:00
case CHAIN_KIND_KUSD:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_KUSD[i]);
2018-07-31 19:59:59 +02:00
break;
case CHAIN_KIND_MUSICOIN:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_MUSICOIN[i]);
break;
case CHAIN_KIND_CALLISTO:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_CALLISTO[i]);
break;
case CHAIN_KIND_ETHERSOCIAL:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHERSOCIAL[i]);
break;
case CHAIN_KIND_ELLAISM:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ELLAISM[i]);
break;
2018-08-05 02:19:44 -04:00
case CHAIN_KIND_ETHER1:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHER1[i]);
2018-08-05 02:19:44 -04:00
break;
case CHAIN_KIND_ETHERGEM:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHERGEM[i]);
break;
case CHAIN_KIND_ATHEIOS:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ATHEIOS[i]);
break;
case CHAIN_KIND_GOCHAIN:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_GOCHAIN[i]);
break;
case CHAIN_KIND_MIX:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_MIX[i]);
break;
case CHAIN_KIND_REOSC:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_REOSC[i]);
break;
case CHAIN_KIND_HPB:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_HPB[i]);
break;
2019-02-06 08:03:49 +00:00
case CHAIN_KIND_TOMOCHAIN:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_TOMOCHAIN[i]);
2019-02-06 08:03:49 +00:00
break;
2019-01-31 17:38:12 +01:00
case CHAIN_KIND_TOBALABA:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_TOBALABA[i]);
2019-01-31 17:38:12 +01:00
break;
case CHAIN_KIND_DEXON:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_DEXON[i]);
break;
case CHAIN_KIND_VOLTA:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_VOLTA[i]);
break;
case CHAIN_KIND_EWC:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_EWC[i]);
break;
case CHAIN_KIND_WEBCHAIN:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_WEBCHAIN[i]);
break;
case CHAIN_KIND_THUNDERCORE:
2020-12-01 16:20:13 +01:00
currentToken = (tokenDefinition_t *) PIC(&TOKENS_THUNDERCORE[i]);
break
2019-03-18 14:03:54 +01:00
}
2020-11-24 10:23:45 +01:00
if (memcmp(currentToken->address, tmpContent.txContent.destination, 20) == 0) {
2018-07-31 19:59:59 +02:00
return currentToken;
}
}
2019-02-05 14:50:36 +01:00
#endif
2020-12-01 16:20:13 +01:00
for (size_t i = 0; i < MAX_TOKEN; i++) {
currentToken = &tmpCtx.transactionContext.tokens[i];
if (tmpCtx.transactionContext.tokenSet[i] &&
(memcmp(currentToken->address, contractAddress, 20) == 0)) {
PRINTF("Token found at index %d\n", i);
return currentToken;
}
}
2020-06-27 13:24:04 +02:00
return NULL;
}
2020-06-27 13:24:04 +02:00
void handleApdu(unsigned int *flags, unsigned int *tx) {
2020-12-01 16:20:13 +01:00
unsigned short sw = 0;
2020-12-01 16:20:13 +01:00
BEGIN_TRY {
TRY {
2020-06-27 13:24:04 +02:00
#ifdef HAVE_STARKWARE
2020-12-01 16:20:13 +01:00
if (G_io_apdu_buffer[OFFSET_CLA] == STARKWARE_CLA) {
switch (G_io_apdu_buffer[OFFSET_INS]) {
case STARKWARE_INS_GET_PUBLIC_KEY:
handleStarkwareGetPublicKey(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case STARKWARE_INS_SIGN_MESSAGE:
handleStarkwareSignMessage(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case STARKWARE_INS_PROVIDE_QUANTUM:
handleStarkwareProvideQuantum(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case STARKWARE_INS_UNSAFE_SIGN:
handleStarkwareUnsafeSign(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
default:
THROW(0x6D00);
break;
}
CLOSE_TRY;
return;
}
2020-06-29 15:43:02 +02:00
#endif
2020-12-01 16:20:13 +01:00
if (G_io_apdu_buffer[OFFSET_CLA] != CLA) {
THROW(0x6E00);
}
2018-07-27 21:02:24 +02:00
2020-12-01 16:20:13 +01:00
switch (G_io_apdu_buffer[OFFSET_INS]) {
case INS_GET_PUBLIC_KEY:
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
handleGetPublicKey(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
2018-07-27 21:02:24 +02:00
2020-12-01 16:20:13 +01:00
case INS_PROVIDE_ERC20_TOKEN_INFORMATION:
handleProvideErc20TokenInformation(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
2019-02-05 14:50:36 +01:00
2020-12-01 16:20:13 +01:00
case INS_SIGN:
handleSign(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
2018-07-27 21:02:24 +02:00
2020-12-01 16:20:13 +01:00
case INS_GET_APP_CONFIGURATION:
handleGetAppConfiguration(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
2018-07-27 21:02:24 +02:00
2020-12-01 16:20:13 +01:00
case INS_SIGN_PERSONAL_MESSAGE:
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
handleSignPersonalMessage(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
2018-07-27 21:02:24 +02:00
2020-12-01 16:20:13 +01:00
case INS_SIGN_EIP_712_MESSAGE:
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
handleSignEIP712Message(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
2020-09-26 15:49:36 +02:00
2020-10-27 11:16:50 +01:00
#ifdef HAVE_ETH2
2020-12-01 16:20:13 +01:00
case INS_GET_ETH2_PUBLIC_KEY:
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
handleGetEth2PublicKey(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
2020-10-27 11:16:50 +01:00
2020-12-01 16:20:13 +01:00
case INS_SET_ETH2_WITHDRAWAL_INDEX:
handleSetEth2WithdrawalIndex(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
2020-10-27 11:16:50 +01:00
#endif
2018-07-27 21:02:24 +02:00
#if 0
case 0xFF: // return to dashboard
goto return_to_dashboard;
#endif
2018-07-27 21:02:24 +02:00
2020-12-01 16:20:13 +01:00
default:
THROW(0x6D00);
break;
}
}
CATCH(EXCEPTION_IO_RESET) {
THROW(EXCEPTION_IO_RESET);
}
CATCH_OTHER(e) {
switch (e & 0xF000) {
case 0x6000:
// Wipe the transaction context and report the exception
sw = e;
reset_app_context();
break;
case 0x9000:
// All is well
sw = e;
break;
default:
// Internal error
sw = 0x6800 | (e & 0x7FF);
reset_app_context();
break;
}
// Unexpected exception => report
G_io_apdu_buffer[*tx] = sw >> 8;
G_io_apdu_buffer[*tx + 1] = sw;
*tx += 2;
2018-07-27 21:02:24 +02:00
}
2020-12-01 16:20:13 +01:00
FINALLY {
}
}
END_TRY;
}
2020-06-29 15:43:02 +02:00
void app_main(void) {
2020-06-27 13:24:04 +02:00
unsigned int rx = 0;
unsigned int tx = 0;
unsigned int flags = 0;
2016-06-01 21:41:29 +02:00
// DESIGN NOTE: the bootloader ignores the way APDU are fetched. The only
// goal is to retrieve APDU.
// When APDU are to be fetched from multiple IOs, like NFC+USB+BLE, make
// sure the io_event is called with a
// switch event, before the apdu is replied to the bootloader. This avoid
// APDU injection faults.
for (;;) {
2020-06-27 13:24:04 +02:00
unsigned short sw = 0;
2016-06-01 21:41:29 +02:00
BEGIN_TRY {
TRY {
rx = tx;
2020-12-01 16:20:13 +01:00
tx = 0; // ensure no race in catch_other if io_exchange throws
// an error
2016-06-01 21:41:29 +02:00
rx = io_exchange(CHANNEL_APDU | flags, rx);
flags = 0;
2016-06-01 21:41:29 +02:00
// no apdu received, well, reset the session, and reset the
// bootloader configuration
if (rx == 0) {
THROW(0x6982);
}
PRINTF("New APDU received:\n%.*H\n", rx, G_io_apdu_buffer);
handleApdu(&flags, &tx);
2016-06-01 21:41:29 +02:00
}
CATCH(EXCEPTION_IO_RESET) {
2020-06-29 15:43:02 +02:00
THROW(EXCEPTION_IO_RESET);
}
2016-06-01 21:41:29 +02:00
CATCH_OTHER(e) {
switch (e & 0xF000) {
2020-12-01 16:20:13 +01:00
case 0x6000:
// Wipe the transaction context and report the exception
sw = e;
reset_app_context();
break;
case 0x9000:
// All is well
sw = e;
break;
default:
// Internal error
sw = 0x6800 | (e & 0x7FF);
reset_app_context();
break;
2016-06-01 21:41:29 +02:00
}
2018-07-31 19:59:59 +02:00
if (e != 0x9000) {
flags &= ~IO_ASYNCH_REPLY;
}
2016-06-01 21:41:29 +02:00
// Unexpected exception => report
G_io_apdu_buffer[tx] = sw >> 8;
G_io_apdu_buffer[tx + 1] = sw;
tx += 2;
}
FINALLY {
}
}
END_TRY;
}
2020-12-01 16:20:13 +01:00
// return_to_dashboard:
2016-06-01 21:41:29 +02:00
return;
}
2017-01-22 18:26:27 +01:00
// override point, but nothing more to do
2016-06-01 21:41:29 +02:00
void io_seproxyhal_display(const bagl_element_t *element) {
2020-12-01 16:20:13 +01:00
io_seproxyhal_display_default((bagl_element_t *) element);
2016-06-01 21:41:29 +02:00
}
unsigned char io_event(unsigned char channel) {
// nothing done with the event, throw an error on the transport layer if
// needed
// can't have more than one tag in the reply, not supported yet.
switch (G_io_seproxyhal_spi_buffer[0]) {
2020-12-01 16:20:13 +01:00
case SEPROXYHAL_TAG_FINGER_EVENT:
UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
break;
2020-12-01 16:20:13 +01:00
case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT:
UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
break;
2016-06-01 21:41:29 +02:00
2020-12-01 16:20:13 +01:00
case SEPROXYHAL_TAG_STATUS_EVENT:
if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID &&
!(U4BE(G_io_seproxyhal_spi_buffer, 3) &
SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
THROW(EXCEPTION_IO_RESET);
}
// no break is intentional
default:
UX_DEFAULT_EVENT();
break;
2020-12-01 16:20:13 +01:00
case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
UX_DISPLAYED_EVENT({});
break;
2016-06-01 21:41:29 +02:00
2020-06-27 13:24:04 +02:00
#if 0
2017-01-22 18:26:27 +01:00
case SEPROXYHAL_TAG_TICKER_EVENT:
UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer,
2018-07-27 21:02:24 +02:00
{
2017-01-22 18:26:27 +01:00
});
2016-06-01 21:41:29 +02:00
break;
2020-06-29 15:43:02 +02:00
#endif
2016-06-01 21:41:29 +02:00
}
// close the event if not done previously (by a display or whatever)
if (!io_seproxyhal_spi_is_status_sent()) {
io_seproxyhal_general_status();
}
2016-06-01 21:41:29 +02:00
// command has been processed, DO NOT reset the current APDU transport
return 1;
}
2020-06-29 15:43:02 +02:00
void app_exit() {
BEGIN_TRY_L(exit) {
TRY_L(exit) {
os_sched_exit(-1);
}
FINALLY_L(exit) {
}
}
END_TRY_L(exit);
}
void init_coin_config(chain_config_t *coin_config) {
memset(coin_config, 0, sizeof(chain_config_t));
strcpy(coin_config->coinName, CHAINID_COINNAME " ");
coin_config->chainId = CHAIN_ID;
coin_config->kind = CHAIN_KIND;
}
void coin_main(chain_config_t *coin_config) {
chain_config_t config;
if (coin_config == NULL) {
init_coin_config(&config);
chainConfig = &config;
} else {
chainConfig = coin_config;
}
reset_app_context();
2020-06-27 13:24:04 +02:00
tmpCtx.transactionContext.currentTokenIndex = 0;
2016-06-01 21:41:29 +02:00
for (;;) {
UX_INIT();
BEGIN_TRY {
TRY {
io_seproxyhal_init();
#ifdef TARGET_NANOX
// grab the current plane mode setting
G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
2020-12-01 16:20:13 +01:00
#endif // TARGET_NANOX
if (N_storage.initialized != 0x01) {
2020-06-29 15:43:02 +02:00
internalStorage_t storage;
storage.dataAllowed = 0x00;
storage.contractDetails = 0x00;
storage.initialized = 0x01;
2020-12-01 16:20:13 +01:00
nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t));
}
2018-07-27 21:02:24 +02:00
USB_power(0);
USB_power(1);
2016-06-01 21:41:29 +02:00
2019-03-18 14:03:54 +01:00
ui_idle();
#ifdef HAVE_BLE
BLE_power(0, NULL);
BLE_power(1, "Nano X");
2020-12-01 16:20:13 +01:00
#endif // HAVE_BLE
2020-06-29 15:43:02 +02:00
app_main();
}
CATCH(EXCEPTION_IO_RESET) {
2020-06-29 15:43:02 +02:00
// reset IO and UX before continuing
CLOSE_TRY;
continue;
}
CATCH_ALL {
2020-06-29 15:43:02 +02:00
CLOSE_TRY;
break;
}
FINALLY {
}
2016-06-01 21:41:29 +02:00
}
END_TRY;
2016-06-01 21:41:29 +02:00
}
2020-06-29 15:43:02 +02:00
app_exit();
}
struct libargs_s {
unsigned int id;
unsigned int command;
chain_config_t *chain_config;
union {
check_address_parameters_t *check_address;
create_transaction_parameters_t *create_transaction;
get_printable_amount_parameters_t *get_printable_amount;
};
};
static void library_main_helper(struct libargs_s *args) {
check_api_level(CX_COMPAT_APILEVEL);
PRINTF("Inside a library \n");
switch (args->command) {
case CHECK_ADDRESS:
// ensure result is zero if an exception is thrown
args->check_address->result = 0;
args->check_address->result =
handle_check_address(args->check_address, args->chain_config);
break;
case SIGN_TRANSACTION:
if (copy_transaction_parameters(args->create_transaction, args->chain_config)) {
// never returns
handle_swap_sign_transaction(args->chain_config);
}
break;
case GET_PRINTABLE_AMOUNT:
// ensure result is zero if an exception is thrown (compatibility breaking, disabled
// until LL is ready)
// args->get_printable_amount->result = 0;
// args->get_printable_amount->result =
handle_get_printable_amount(args->get_printable_amount, args->chain_config);
break;
default:
break;
}
2020-06-29 15:43:02 +02:00
}
void library_main(struct libargs_s *args) {
2020-06-29 15:43:02 +02:00
chain_config_t coin_config;
if (args->chain_config == NULL) {
init_coin_config(&coin_config);
args->chain_config = &coin_config;
}
bool end = false;
/* This loop ensures that library_main_helper and os_lib_end are called
* within a try context, even if an exception is thrown */
while (1) {
BEGIN_TRY {
TRY {
if (!end) {
library_main_helper(args);
}
os_lib_end();
}
FINALLY {
end = true;
2020-06-29 15:43:02 +02:00
}
2020-12-01 16:20:13 +01:00
}
END_TRY;
2020-06-29 15:43:02 +02:00
}
}
__attribute__((section(".boot"))) int main(int arg0) {
#ifdef USE_LIB_ETHEREUM
BEGIN_TRY {
TRY {
unsigned int libcall_params[5];
chain_config_t local_chainConfig;
init_coin_config(&local_chainConfig);
PRINTF("Hello from Eth-clone\n");
check_api_level(CX_COMPAT_APILEVEL);
// delegate to Ethereum app/lib
libcall_params[0] = "Ethereum";
libcall_params[1] = 0x100;
libcall_params[2] = RUN_APPLICATION;
libcall_params[3] = &local_chainConfig;
libcall_params[4] = 0;
if (arg0) {
// call as a library
2020-12-01 16:20:13 +01:00
libcall_params[2] = ((unsigned int *) arg0)[1];
libcall_params[4] = ((unsigned int *) arg0)[3]; // library arguments
2020-06-29 15:43:02 +02:00
os_lib_call(&libcall_params);
2020-12-01 16:20:13 +01:00
((unsigned int *) arg0)[0] = libcall_params[1];
2020-06-29 15:43:02 +02:00
os_lib_end();
2020-12-01 16:20:13 +01:00
} else {
2020-06-29 15:43:02 +02:00
// launch coin application
2020-12-01 16:20:13 +01:00
libcall_params[1] = 0x100; // use the Init call, as we won't exit
2020-06-29 15:43:02 +02:00
os_lib_call(&libcall_params);
}
}
2020-12-01 16:20:13 +01:00
FINALLY {
}
2020-06-29 15:43:02 +02:00
}
END_TRY;
2020-12-01 16:20:13 +01:00
// no return
2020-06-29 15:43:02 +02:00
#else
// exit critical section
__asm volatile("cpsie i");
// ensure exception will work as planned
os_boot();
if (!arg0) {
// called from dashboard as standalone eth app
coin_main(NULL);
2020-06-29 15:43:02 +02:00
return 0;
}
struct libargs_s *args = (struct libargs_s *) arg0;
if (args->id != 0x100) {
2020-06-29 15:43:02 +02:00
app_exit();
return 0;
}
switch (args->command) {
2020-06-29 15:43:02 +02:00
case RUN_APPLICATION:
// coin application launched from dashboard
if (args->chain_config == NULL)
2020-06-29 15:43:02 +02:00
app_exit();
else
coin_main(args->chain_config);
2020-12-01 16:20:13 +01:00
break;
2020-06-29 15:43:02 +02:00
default:
// called as bitcoin or altcoin library
library_main(args);
2020-06-29 15:43:02 +02:00
}
2018-07-27 21:02:24 +02:00
#endif
return 0;
2016-06-01 21:41:29 +02:00
}