1177 lines
41 KiB
C
1177 lines
41 KiB
C
/*******************************************************************************
|
|
* 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.
|
|
********************************************************************************/
|
|
|
|
#include "shared_context.h"
|
|
#include "apdu_constants.h"
|
|
#include "common_ui.h"
|
|
|
|
#include "os_io_seproxyhal.h"
|
|
|
|
#include "glyphs.h"
|
|
#include "utils.h"
|
|
|
|
#include "swap_lib_calls.h"
|
|
#include "handle_swap_sign_transaction.h"
|
|
#include "handle_get_printable_amount.h"
|
|
#include "handle_check_address.h"
|
|
#include "commands_712.h"
|
|
#include "challenge.h"
|
|
#include "domain_name.h"
|
|
|
|
#ifdef HAVE_STARKWARE
|
|
#include "stark_crypto.h"
|
|
#endif
|
|
|
|
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
|
|
|
|
void ui_idle(void);
|
|
|
|
uint32_t set_result_get_publicKey(void);
|
|
void finalizeParsing(bool);
|
|
|
|
tmpCtx_t tmpCtx;
|
|
txContext_t txContext;
|
|
tmpContent_t tmpContent;
|
|
dataContext_t dataContext;
|
|
strings_t strings;
|
|
cx_sha3_t global_sha3;
|
|
|
|
uint8_t appState;
|
|
uint16_t apdu_response_code;
|
|
bool G_called_from_swap;
|
|
pluginType_t pluginType;
|
|
#ifdef HAVE_STARKWARE
|
|
bool quantumSet;
|
|
#endif
|
|
|
|
#ifdef HAVE_ETH2
|
|
uint32_t eth2WithdrawalIndex;
|
|
#include "withdrawal_index.h"
|
|
#endif
|
|
|
|
#include "ux.h"
|
|
ux_state_t G_ux;
|
|
bolos_ux_params_t G_ux_params;
|
|
|
|
const internalStorage_t N_storage_real;
|
|
|
|
#ifdef HAVE_NBGL
|
|
caller_app_t *caller_app = NULL;
|
|
#endif
|
|
chain_config_t *chainConfig = NULL;
|
|
|
|
void reset_app_context() {
|
|
// PRINTF("!!RESET_APP_CONTEXT\n");
|
|
appState = APP_STATE_IDLE;
|
|
G_called_from_swap = false;
|
|
pluginType = OLD_INTERNAL;
|
|
#ifdef HAVE_STARKWARE
|
|
quantumSet = false;
|
|
#endif
|
|
#ifdef HAVE_ETH2
|
|
eth2WithdrawalIndex = 0;
|
|
#endif
|
|
memset((uint8_t *) &tmpCtx, 0, sizeof(tmpCtx));
|
|
memset((uint8_t *) &txContext, 0, sizeof(txContext));
|
|
memset((uint8_t *) &tmpContent, 0, sizeof(tmpContent));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
|
|
switch (channel & ~(IO_FLAGS)) {
|
|
case CHANNEL_KEYBOARD:
|
|
break;
|
|
|
|
// 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);
|
|
|
|
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);
|
|
}
|
|
|
|
default:
|
|
THROW(INVALID_PARAMETER);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
extraInfo_t *getKnownToken(uint8_t *contractAddress) {
|
|
union extraInfo_t *currentItem = NULL;
|
|
#ifdef HAVE_TOKENS_LIST
|
|
uint32_t numTokens = 0;
|
|
uint32_t i;
|
|
switch (chainConfig->kind) {
|
|
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;
|
|
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;
|
|
case CHAIN_KIND_RSK:
|
|
numTokens = NUM_TOKENS_RSK;
|
|
break;
|
|
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;
|
|
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;
|
|
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;
|
|
case CHAIN_KIND_TOMOCHAIN:
|
|
numTokens = NUM_TOKENS_TOMOCHAIN;
|
|
break;
|
|
case CHAIN_KIND_MOONRIVER:
|
|
numTokens = NUM_TOKENS_MOONRIVER;
|
|
break;
|
|
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_ENERGYWEBCHAIN:
|
|
numTokens = NUM_TOKENS_ENERGYWEBCHAIN;
|
|
break;
|
|
case CHAIN_KIND_WEBCHAIN:
|
|
numTokens = NUM_TOKENS_WEBCHAIN;
|
|
break;
|
|
case CHAIN_KIND_THUNDERCORE:
|
|
numTokens = NUM_TOKENS_THUNDERCORE;
|
|
break;
|
|
case CHAIN_KIND_FLARE:
|
|
numTokens = NUM_TOKENS_FLARE;
|
|
break;
|
|
case CHAIN_KIND_BSC:
|
|
numTokens = NUM_TOKENS_BSC;
|
|
break;
|
|
case CHAIN_KIND_SONGBIRD:
|
|
numTokens = NUM_TOKENS_SONGBIRD;
|
|
break;
|
|
case CHAIN_KIND_POLYGON:
|
|
numTokens = NUM_TOKENS_POLYGON;
|
|
break;
|
|
case CHAIN_KIND_SHYFT:
|
|
numTokens = NUM_TOKENS_SHYFT;
|
|
break;
|
|
case CHAIN_KIND_CONFLUX_ESPACE:
|
|
numTokens = NUM_TOKENS_CONFLUX_ESPACE;
|
|
break;
|
|
case CHAIN_KIND_MOONBEAM:
|
|
numTokens = NUM_TOKENS_MOONBEAM;
|
|
break;
|
|
case CHAIN_KIND_KARDIACHAIN:
|
|
numTokens = NUM_TOKENS_KARDIACHAIN;
|
|
break;
|
|
case CHAIN_KIND_BTTC:
|
|
numTokens = NUM_TOKENS_BTTC;
|
|
break;
|
|
case CHAIN_KIND_WETHIO:
|
|
numTokens = NUM_TOKENS_WETHIO;
|
|
break;
|
|
case CHAIN_KIND_OKC:
|
|
numTokens = NUM_TOKENS_OKC;
|
|
break;
|
|
case CHAIN_KIND_CUBE:
|
|
numTokens = NUM_TOKENS_CUBE;
|
|
break;
|
|
case CHAIN_KIND_SHIDEN:
|
|
numTokens = NUM_TOKENS_SHIDEN;
|
|
break;
|
|
case CHAIN_KIND_ASTAR:
|
|
numTokens = NUM_TOKENS_ASTAR;
|
|
break;
|
|
case CHAIN_KIND_XDCNETWORK:
|
|
numTokens = NUM_TOKENS_XDCNETWORK;
|
|
break;
|
|
case CHAIN_KIND_METER:
|
|
numTokens = NUM_TOKENS_METER;
|
|
break;
|
|
case CHAIN_KIND_MULTIVAC:
|
|
numTokens = NUM_TOKENS_MULTIVAC;
|
|
break;
|
|
case CHAIN_KIND_TECRA:
|
|
numTokens = NUM_TOKENS_TECRA;
|
|
break;
|
|
case CHAIN_KIND_APOTHEMNETWORK:
|
|
numTokens = NUM_TOKENS_APOTHEMNETWORK;
|
|
break;
|
|
case CHAIN_KIND_ID4GOOD:
|
|
numTokens = NUM_TOKENS_ID4GOOD;
|
|
break;
|
|
case CHAIN_KIND_OASYS:
|
|
numTokens = NUM_TOKENS_OASYS;
|
|
break;
|
|
}
|
|
for (i = 0; i < numTokens; i++) {
|
|
switch (chainConfig->kind) {
|
|
case CHAIN_KIND_AKROMA:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_AKROMA[i]);
|
|
break;
|
|
case CHAIN_KIND_ETHEREUM:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHEREUM[i]);
|
|
break;
|
|
case CHAIN_KIND_ETHEREUM_CLASSIC:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHEREUM_CLASSIC[i]);
|
|
break;
|
|
case CHAIN_KIND_PIRL:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_PIRL[i]);
|
|
break;
|
|
case CHAIN_KIND_POA:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_POA[i]);
|
|
break;
|
|
case CHAIN_KIND_ARTIS_SIGMA1:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ARTIS_SIGMA1[i]);
|
|
break;
|
|
case CHAIN_KIND_ARTIS_TAU1:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ARTIS_TAU1[i]);
|
|
break;
|
|
case CHAIN_KIND_RSK:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_RSK[i]);
|
|
break;
|
|
case CHAIN_KIND_EXPANSE:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_EXPANSE[i]);
|
|
break;
|
|
case CHAIN_KIND_UBIQ:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_UBIQ[i]);
|
|
break;
|
|
case CHAIN_KIND_WANCHAIN:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_WANCHAIN[i]);
|
|
break;
|
|
case CHAIN_KIND_KUSD:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_KUSD[i]);
|
|
break;
|
|
case CHAIN_KIND_MUSICOIN:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_MUSICOIN[i]);
|
|
break;
|
|
case CHAIN_KIND_CALLISTO:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_CALLISTO[i]);
|
|
break;
|
|
case CHAIN_KIND_ETHERSOCIAL:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHERSOCIAL[i]);
|
|
break;
|
|
case CHAIN_KIND_ELLAISM:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ELLAISM[i]);
|
|
break;
|
|
case CHAIN_KIND_ETHER1:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHER1[i]);
|
|
break;
|
|
case CHAIN_KIND_ETHERGEM:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHERGEM[i]);
|
|
break;
|
|
case CHAIN_KIND_ATHEIOS:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ATHEIOS[i]);
|
|
break;
|
|
case CHAIN_KIND_GOCHAIN:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_GOCHAIN[i]);
|
|
break;
|
|
case CHAIN_KIND_MIX:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_MIX[i]);
|
|
break;
|
|
case CHAIN_KIND_REOSC:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_REOSC[i]);
|
|
break;
|
|
case CHAIN_KIND_HPB:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_HPB[i]);
|
|
break;
|
|
case CHAIN_KIND_TOMOCHAIN:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_TOMOCHAIN[i]);
|
|
break;
|
|
case CHAIN_KIND_MOONRIVER:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_MOONRIVER[i]);
|
|
break;
|
|
case CHAIN_KIND_TOBALABA:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_TOBALABA[i]);
|
|
break;
|
|
case CHAIN_KIND_DEXON:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_DEXON[i]);
|
|
break;
|
|
case CHAIN_KIND_VOLTA:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_VOLTA[i]);
|
|
break;
|
|
case CHAIN_KIND_ENERGYWEBCHAIN:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ENERGYWEBCHAIN[i]);
|
|
break;
|
|
case CHAIN_KIND_WEBCHAIN:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_WEBCHAIN[i]);
|
|
break;
|
|
case CHAIN_KIND_THUNDERCORE:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_THUNDERCORE[i]);
|
|
break;
|
|
case CHAIN_KIND_FLARE:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_FLARE[i]);
|
|
break;
|
|
case CHAIN_KIND_BSC:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_BSC[i]);
|
|
break;
|
|
case CHAIN_KIND_SONGBIRD:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_SONGBIRD[i]);
|
|
break;
|
|
case CHAIN_KIND_POLYGON:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_POLYGON[i]);
|
|
break;
|
|
case CHAIN_KIND_SHYFT:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_SHYFT[i]);
|
|
break;
|
|
case CHAIN_KIND_CONFLUX_ESPACE:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_CONFLUX_ESPACE[i]);
|
|
break;
|
|
case CHAIN_KIND_MOONBEAM:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_MOONBEAM[i]);
|
|
break;
|
|
case CHAIN_KIND_BTTC:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_BTTC[i]);
|
|
break;
|
|
case CHAIN_KIND_KARDIACHAIN:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_KARDIACHAIN[i]);
|
|
break;
|
|
case CHAIN_KIND_WETHIO:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_WETHIO[i]);
|
|
break;
|
|
case CHAIN_KIND_OKC:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_OKC[i]);
|
|
break;
|
|
case CHAIN_KIND_CUBE:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_CUBE[i]);
|
|
break;
|
|
case CHAIN_KIND_SHIDEN:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_SHIDEN[i]);
|
|
break;
|
|
case CHAIN_KIND_ASTAR:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ASTAR[i]);
|
|
break;
|
|
case CHAIN_KIND_XDCNETWORK:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_XDCNETWORK[i]);
|
|
break;
|
|
case CHAIN_KIND_METER:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_METER[i]);
|
|
break;
|
|
case CHAIN_KIND_MULTIVAC:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_MULTIVAC[i]);
|
|
break;
|
|
case CHAIN_KIND_TECRA:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_TECRA[i]);
|
|
break;
|
|
case CHAIN_KIND_APOTHEMNETWORK:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_APOTHEMNETWORK[i]);
|
|
break;
|
|
case CHAIN_KIND_ID4GOOD:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_ID4GOOD[i]);
|
|
break;
|
|
case CHAIN_KIND_OASYS:
|
|
currentToken = (tokenDefinition_t *) PIC(&TOKENS_OASYS[i]);
|
|
break;
|
|
}
|
|
if (memcmp(currentToken->address, tmpContent.txContent.destination, ADDRESS_LENGTH) == 0) {
|
|
return currentToken;
|
|
}
|
|
}
|
|
#endif
|
|
// Works for ERC-20 & NFT tokens since both structs in the union have the
|
|
// contract address aligned
|
|
for (uint8_t i = 0; i < MAX_ITEMS; i++) {
|
|
currentItem = (union extraInfo_t *) &tmpCtx.transactionContext.extraInfo[i].token;
|
|
if (tmpCtx.transactionContext.tokenSet[i] &&
|
|
(memcmp(currentItem->token.address, contractAddress, ADDRESS_LENGTH) == 0)) {
|
|
PRINTF("Token found at index %d\n", i);
|
|
return currentItem;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifndef HAVE_WALLET_ID_SDK
|
|
|
|
unsigned int const U_os_perso_seed_cookie[] = {
|
|
0xda7aba5e,
|
|
0xc1a551c5,
|
|
};
|
|
|
|
void handleGetWalletId(volatile unsigned int *tx) {
|
|
unsigned char t[64];
|
|
cx_ecfp_256_private_key_t priv;
|
|
cx_ecfp_256_public_key_t pub;
|
|
// seed => priv key
|
|
os_perso_derive_node_bip32(CX_CURVE_256K1, U_os_perso_seed_cookie, 2, t, NULL);
|
|
// priv key => pubkey
|
|
cx_ecdsa_init_private_key(CX_CURVE_256K1, t, 32, &priv);
|
|
cx_ecfp_generate_pair(CX_CURVE_256K1, &pub, &priv, 1);
|
|
// pubkey -> sha512
|
|
cx_hash_sha512(pub.W, sizeof(pub.W), t, sizeof(t));
|
|
// ! cookie !
|
|
memmove(G_io_apdu_buffer, t, 64);
|
|
*tx = 64;
|
|
THROW(0x9000);
|
|
}
|
|
|
|
#endif // HAVE_WALLET_ID_SDK
|
|
|
|
const uint8_t *parseBip32(const uint8_t *dataBuffer, uint8_t *dataLength, bip32_path_t *bip32) {
|
|
if (*dataLength < 1) {
|
|
PRINTF("Invalid data\n");
|
|
return NULL;
|
|
}
|
|
|
|
bip32->length = *dataBuffer;
|
|
|
|
if (bip32->length < 0x1 || bip32->length > MAX_BIP32_PATH) {
|
|
PRINTF("Invalid bip32\n");
|
|
return NULL;
|
|
}
|
|
|
|
dataBuffer++;
|
|
(*dataLength)--;
|
|
|
|
if (*dataLength < sizeof(uint32_t) * (bip32->length)) {
|
|
PRINTF("Invalid data\n");
|
|
return NULL;
|
|
}
|
|
|
|
for (uint8_t i = 0; i < bip32->length; i++) {
|
|
bip32->path[i] = U4BE(dataBuffer, 0);
|
|
dataBuffer += sizeof(uint32_t);
|
|
*dataLength -= sizeof(uint32_t);
|
|
}
|
|
|
|
return dataBuffer;
|
|
}
|
|
|
|
void handleApdu(unsigned int *flags, unsigned int *tx) {
|
|
unsigned short sw = 0;
|
|
|
|
BEGIN_TRY {
|
|
TRY {
|
|
#ifndef HAVE_WALLET_ID_SDK
|
|
|
|
if ((G_io_apdu_buffer[OFFSET_CLA] == COMMON_CLA) &&
|
|
(G_io_apdu_buffer[OFFSET_INS] == COMMON_INS_GET_WALLET_ID)) {
|
|
handleGetWalletId(tx);
|
|
return;
|
|
}
|
|
|
|
#endif // HAVE_WALLET_ID_SDK
|
|
|
|
#ifdef HAVE_STARKWARE
|
|
|
|
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;
|
|
}
|
|
|
|
#endif
|
|
|
|
if (G_io_apdu_buffer[OFFSET_CLA] != CLA) {
|
|
THROW(0x6E00);
|
|
}
|
|
|
|
switch (G_io_apdu_buffer[OFFSET_INS]) {
|
|
case INS_GET_PUBLIC_KEY:
|
|
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_ITEMS);
|
|
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;
|
|
|
|
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;
|
|
|
|
#ifdef HAVE_NFT_SUPPORT
|
|
case INS_PROVIDE_NFT_INFORMATION:
|
|
handleProvideNFTInformation(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;
|
|
#endif // HAVE_NFT_SUPPORT
|
|
|
|
case INS_SET_EXTERNAL_PLUGIN:
|
|
handleSetExternalPlugin(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 INS_SET_PLUGIN:
|
|
handleSetPlugin(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 INS_PERFORM_PRIVACY_OPERATION:
|
|
handlePerformPrivacyOperation(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 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;
|
|
|
|
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;
|
|
|
|
case INS_SIGN_PERSONAL_MESSAGE:
|
|
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_ITEMS);
|
|
*flags |= IO_ASYNCH_REPLY;
|
|
if (!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])) {
|
|
reset_app_context();
|
|
}
|
|
break;
|
|
|
|
case INS_SIGN_EIP_712_MESSAGE:
|
|
switch (G_io_apdu_buffer[OFFSET_P2]) {
|
|
case P2_EIP712_LEGACY_IMPLEM:
|
|
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_ITEMS);
|
|
handleSignEIP712Message_v0(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;
|
|
#ifdef HAVE_EIP712_FULL_SUPPORT
|
|
case P2_EIP712_FULL_IMPLEM:
|
|
*flags |= IO_ASYNCH_REPLY;
|
|
handle_eip712_sign(G_io_apdu_buffer);
|
|
break;
|
|
#endif // HAVE_EIP712_FULL_SUPPORT
|
|
default:
|
|
THROW(APDU_RESPONSE_INVALID_P1_P2);
|
|
}
|
|
break;
|
|
|
|
#ifdef HAVE_ETH2
|
|
|
|
case INS_GET_ETH2_PUBLIC_KEY:
|
|
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_ITEMS);
|
|
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;
|
|
|
|
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;
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_EIP712_FULL_SUPPORT
|
|
case INS_EIP712_STRUCT_DEF:
|
|
*flags |= IO_ASYNCH_REPLY;
|
|
handle_eip712_struct_def(G_io_apdu_buffer);
|
|
break;
|
|
|
|
case INS_EIP712_STRUCT_IMPL:
|
|
*flags |= IO_ASYNCH_REPLY;
|
|
handle_eip712_struct_impl(G_io_apdu_buffer);
|
|
break;
|
|
|
|
case INS_EIP712_FILTERING:
|
|
*flags |= IO_ASYNCH_REPLY;
|
|
handle_eip712_filtering(G_io_apdu_buffer);
|
|
break;
|
|
#endif // HAVE_EIP712_FULL_SUPPORT
|
|
|
|
#ifdef HAVE_DOMAIN_NAME
|
|
case INS_ENS_GET_CHALLENGE:
|
|
handle_get_challenge();
|
|
break;
|
|
|
|
case INS_ENS_PROVIDE_INFO:
|
|
handle_provide_domain_name(G_io_apdu_buffer[OFFSET_P1],
|
|
G_io_apdu_buffer[OFFSET_P2],
|
|
G_io_apdu_buffer + OFFSET_CDATA,
|
|
G_io_apdu_buffer[OFFSET_LC]);
|
|
break;
|
|
#endif // HAVE_DOMAIN_NAME
|
|
|
|
#if 0
|
|
case 0xFF: // return to dashboard
|
|
goto return_to_dashboard;
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
FINALLY {
|
|
}
|
|
}
|
|
END_TRY;
|
|
}
|
|
|
|
void app_main(void) {
|
|
unsigned int rx = 0;
|
|
unsigned int tx = 0;
|
|
unsigned int flags = 0;
|
|
|
|
// 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 (;;) {
|
|
unsigned short sw = 0;
|
|
|
|
BEGIN_TRY {
|
|
TRY {
|
|
rx = tx;
|
|
tx = 0; // ensure no race in catch_other if io_exchange throws
|
|
// an error
|
|
rx = io_exchange(CHANNEL_APDU | flags, rx);
|
|
flags = 0;
|
|
|
|
// no apdu received, well, reset the session, and reset the
|
|
// bootloader configuration
|
|
if (rx == 0) {
|
|
THROW(ERR_APDU_EMPTY);
|
|
}
|
|
if (rx > OFFSET_LC && rx != (G_io_apdu_buffer[OFFSET_LC] + 5)) {
|
|
THROW(ERR_APDU_SIZE_MISMATCH);
|
|
}
|
|
|
|
handleApdu(&flags, &tx);
|
|
}
|
|
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;
|
|
}
|
|
if (e != 0x9000) {
|
|
flags &= ~IO_ASYNCH_REPLY;
|
|
}
|
|
// Unexpected exception => report
|
|
G_io_apdu_buffer[tx] = sw >> 8;
|
|
G_io_apdu_buffer[tx + 1] = sw;
|
|
tx += 2;
|
|
}
|
|
FINALLY {
|
|
}
|
|
}
|
|
END_TRY;
|
|
}
|
|
|
|
// return_to_dashboard:
|
|
return;
|
|
}
|
|
|
|
// override point, but nothing more to do
|
|
#ifdef HAVE_BAGL
|
|
void io_seproxyhal_display(const bagl_element_t *element) {
|
|
io_seproxyhal_display_default((bagl_element_t *) element);
|
|
}
|
|
#endif
|
|
|
|
unsigned char io_event(__attribute__((unused)) 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]) {
|
|
case SEPROXYHAL_TAG_FINGER_EVENT:
|
|
UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
|
|
break;
|
|
#ifdef HAVE_BAGL
|
|
case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT:
|
|
UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
|
|
break;
|
|
#endif // HAVE_BAGL
|
|
|
|
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);
|
|
}
|
|
__attribute__((fallthrough));
|
|
default:
|
|
UX_DEFAULT_EVENT();
|
|
break;
|
|
|
|
case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
|
|
#ifdef HAVE_BAGL
|
|
UX_DISPLAYED_EVENT({});
|
|
#endif // HAVE_BAGL
|
|
#ifdef HAVE_NBGL
|
|
UX_DEFAULT_EVENT();
|
|
#endif // HAVE_NBGL
|
|
break;
|
|
|
|
case SEPROXYHAL_TAG_TICKER_EVENT:
|
|
UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {});
|
|
break;
|
|
}
|
|
|
|
// close the event if not done previously (by a display or whatever)
|
|
if (!io_seproxyhal_spi_is_status_sent()) {
|
|
io_seproxyhal_general_status();
|
|
}
|
|
|
|
// command has been processed, DO NOT reset the current APDU transport
|
|
return 1;
|
|
}
|
|
|
|
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(libargs_t *args) {
|
|
chain_config_t config;
|
|
if (args) {
|
|
if (args->chain_config != NULL) {
|
|
chainConfig = args->chain_config;
|
|
}
|
|
#ifdef HAVE_NBGL
|
|
if ((caller_app = args->caller_app) != NULL) {
|
|
if (chainConfig != NULL) {
|
|
caller_app->type = CALLER_TYPE_CLONE;
|
|
} else {
|
|
caller_app->type = CALLER_TYPE_PLUGIN;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (chainConfig == NULL) {
|
|
init_coin_config(&config);
|
|
chainConfig = &config;
|
|
}
|
|
|
|
reset_app_context();
|
|
tmpCtx.transactionContext.currentItemIndex = 0;
|
|
|
|
for (;;) {
|
|
UX_INIT();
|
|
|
|
BEGIN_TRY {
|
|
TRY {
|
|
io_seproxyhal_init();
|
|
|
|
#ifdef HAVE_BLE
|
|
// grab the current plane mode setting
|
|
G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
|
|
#endif // HAVE_BLE
|
|
|
|
if (!N_storage.initialized) {
|
|
internalStorage_t storage;
|
|
#ifdef HAVE_ALLOW_DATA
|
|
storage.dataAllowed = true;
|
|
#else
|
|
storage.dataAllowed = false;
|
|
#endif
|
|
storage.contractDetails = false;
|
|
storage.displayNonce = false;
|
|
#ifdef HAVE_EIP712_FULL_SUPPORT
|
|
storage.verbose_eip712 = false;
|
|
#endif
|
|
#ifdef HAVE_DOMAIN_NAME
|
|
storage.verbose_domain_name = false;
|
|
#endif
|
|
storage.initialized = true;
|
|
nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t));
|
|
}
|
|
|
|
USB_power(0);
|
|
USB_power(1);
|
|
|
|
ui_idle();
|
|
|
|
#ifdef HAVE_BLE
|
|
BLE_power(0, NULL);
|
|
BLE_power(1, NULL);
|
|
#endif // HAVE_BLE
|
|
|
|
#ifdef HAVE_DOMAIN_NAME
|
|
// to prevent it from having a fixed value at boot
|
|
roll_challenge();
|
|
#endif // HAVE_DOMAIN_NAME
|
|
|
|
app_main();
|
|
}
|
|
CATCH(EXCEPTION_IO_RESET) {
|
|
// reset IO and UX before continuing
|
|
CLOSE_TRY;
|
|
continue;
|
|
}
|
|
CATCH_ALL {
|
|
CLOSE_TRY;
|
|
break;
|
|
}
|
|
FINALLY {
|
|
}
|
|
}
|
|
END_TRY;
|
|
}
|
|
app_exit();
|
|
}
|
|
|
|
static void library_main_helper(libargs_t *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;
|
|
}
|
|
}
|
|
|
|
void library_main(libargs_t *args) {
|
|
chain_config_t coin_config;
|
|
if (args->chain_config == NULL) {
|
|
init_coin_config(&coin_config);
|
|
args->chain_config = &coin_config;
|
|
}
|
|
volatile 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;
|
|
}
|
|
}
|
|
END_TRY;
|
|
}
|
|
}
|
|
|
|
__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] = (unsigned int) "Ethereum";
|
|
libcall_params[1] = 0x100;
|
|
libcall_params[2] = RUN_APPLICATION;
|
|
libcall_params[3] = (unsigned int) &local_chainConfig;
|
|
#ifdef HAVE_NBGL
|
|
const char app_name[] = APPNAME;
|
|
caller_app_t capp;
|
|
nbgl_icon_details_t icon_details;
|
|
uint8_t bitmap[sizeof(ICONBITMAP)];
|
|
|
|
memcpy(&icon_details, &ICONGLYPH, sizeof(ICONGLYPH));
|
|
memcpy(&bitmap, &ICONBITMAP, sizeof(bitmap));
|
|
icon_details.bitmap = (const uint8_t *) bitmap;
|
|
capp.name = app_name;
|
|
capp.icon = &icon_details;
|
|
libcall_params[4] = (unsigned int) &capp;
|
|
#else
|
|
libcall_params[4] = NULL;
|
|
#endif // HAVE_NBGL
|
|
|
|
if (arg0) {
|
|
// call as a library
|
|
libcall_params[2] = ((unsigned int *) arg0)[1];
|
|
libcall_params[4] = ((unsigned int *) arg0)[3]; // library arguments
|
|
os_lib_call((unsigned int *) &libcall_params);
|
|
((unsigned int *) arg0)[0] = libcall_params[1];
|
|
os_lib_end();
|
|
} else {
|
|
// launch coin application
|
|
libcall_params[1] = 0x100; // use the Init call, as we won't exit
|
|
os_lib_call((unsigned int *) &libcall_params);
|
|
}
|
|
}
|
|
FINALLY {
|
|
}
|
|
}
|
|
END_TRY;
|
|
// no return
|
|
#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);
|
|
return 0;
|
|
}
|
|
|
|
libargs_t *args = (libargs_t *) arg0;
|
|
if (args->id != 0x100) {
|
|
app_exit();
|
|
return 0;
|
|
}
|
|
switch (args->command) {
|
|
case RUN_APPLICATION:
|
|
// called as ethereum from altcoin or plugin
|
|
coin_main(args);
|
|
break;
|
|
default:
|
|
// called as ethereum or altcoin library
|
|
library_main(args);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|