Add Swap feature

This commit is contained in:
TamtamHero
2020-06-29 15:43:02 +02:00
parent 2027fecffa
commit 9d4dfbe1bf
31 changed files with 650 additions and 312 deletions

View File

@@ -56,12 +56,12 @@ typedef enum chain_kind_e {
} chain_kind_t;
typedef struct chain_config_s {
const char* coinName; // ticker
char coinName[10]; // ticker
uint32_t chainId;
chain_kind_t kind;
#ifdef TARGET_BLUE
const char* header_text;
unsigned int color_header;
char header_text[13];
unsigned int color_dashboard;
#endif // TARGET_BLUE

View File

@@ -0,0 +1,70 @@
#include "handle_check_address.h"
#include "os.h"
#include "shared_context.h"
#include "ethUtils.h"
#include "string.h"
#define ZERO(x) os_memset(x, 0, sizeof(x))
void handle_check_address(check_address_parameters_t* params, chain_config_t* chain_config) {
PRINTF("Params on the address %d\n",(unsigned int)params);
PRINTF("Address to check %s\n",params->address_to_check);
PRINTF("Inside handle_check_address\n");
params->result = 0;
if (params->address_to_check == 0) {
PRINTF("Address to check == 0\n");
return;
}
uint8_t i;
uint8_t *bip32_path_ptr = params->address_parameters;
uint8_t bip32PathLength = *(bip32_path_ptr++);
cx_sha3_t local_sha3;
// Common memory is used for locals that are not used concurrently
union group1
{
uint32_t bip32Path[MAX_BIP32_PATH];
cx_ecfp_private_key_t privateKey;
char address[51];
} locals_union1;
union group2
{
uint8_t privateKeyData[32];
cx_ecfp_public_key_t publicKey;
} locals_union2;
if ((bip32PathLength < 0x01) ||
(bip32PathLength > MAX_BIP32_PATH) ||
(bip32PathLength*4 != params->address_parameters_length - 1)) {
PRINTF("Invalid path\n");
return;
}
for (i = 0; i < bip32PathLength; i++) {
locals_union1.bip32Path[i] = U4BE(bip32_path_ptr, 0);
bip32_path_ptr += 4;
}
os_perso_derive_node_bip32(CX_CURVE_256K1, locals_union1.bip32Path, bip32PathLength, locals_union2.privateKeyData, NULL);
ZERO(&locals_union1);
cx_ecfp_init_private_key(CX_CURVE_256K1, locals_union2.privateKeyData, 32, &locals_union1.privateKey);
ZERO(&locals_union2);
cx_ecfp_generate_pair(CX_CURVE_256K1, &locals_union2.publicKey, &locals_union1.privateKey, 1);
ZERO(&locals_union1);
getEthAddressStringFromKey(&locals_union2.publicKey, (uint8_t*)locals_union1.address, &local_sha3, chain_config);
ZERO(&locals_union2);
uint8_t offset_0x = 0;
if(memcmp(params->address_to_check, "0x", 2) == 0){
offset_0x = 2;
}
if ((strlen(locals_union1.address) != strlen(params->address_to_check + offset_0x)) ||
os_memcmp(locals_union1.address, params->address_to_check + offset_0x, strlen(locals_union1.address)) != 0) {
os_memcpy(params->address_to_check, locals_union1.address, 45);
PRINTF("Addresses doesn't match\n");
return;
}
PRINTF("Addresses match\n");
params->result = 1;
}

View File

@@ -0,0 +1,9 @@
#ifndef _HANDLE_CHECK_ADDRESS_H_
#define _HANDLE_CHECK_ADDRESS_H_
#include "swap_lib_calls.h"
#include "chainConfig.h"
void handle_check_address(check_address_parameters_t* check_address_params, chain_config_t* chain_config);
#endif // _HANDLE_CHECK_ADDRESS_H_

View File

@@ -0,0 +1,33 @@
#include "handle_get_printable_amount.h"
#include "shared_context.h"
#include "ethUtils.h"
#include "utils.h"
#include "uint256.h"
#include "string.h"
#include <stdint.h>
void handle_get_printable_amount( get_printable_amount_parameters_t* params, chain_config_t *config) {
uint8_t decimals;
char ticker[MAX_TICKER_LEN];
os_memset(params->printable_amount, 0, sizeof(params->printable_amount));
if (params->amount_length > 32) {
PRINTF("Amount is too big, 32 bytes max but buffer has %u bytes", params->amount_length);
os_lib_end();
}
if(!parse_swap_config(params->coin_configuration, params->coin_configuration_length, ticker, &decimals)){
PRINTF("Error while parsing config\n");
os_lib_end();
}
// If the amount is a fee, its value is nominated in ETH even if we're doing an ERC20 swap
if(params->is_fee){
uint8_t ticker_len = strnlen(config->coinName, sizeof(config->coinName));
memcpy(ticker, config->coinName, ticker_len);
ticker[ticker_len] = ' ';
ticker[ticker_len+1] = '\0';
decimals = WEI_TO_ETHER;
}
amountToString(params->amount, params->amount_length, decimals, ticker, params->printable_amount, sizeof(params->printable_amount));
}

View File

@@ -0,0 +1,9 @@
#ifndef _HANDLE_GET_PRINTABLE_AMOUNT_H_
#define _HANDLE_GET_PRINTABLE_AMOUNT_H_
#include "swap_lib_calls.h"
#include "chainConfig.h"
void handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params, chain_config_t *config);
#endif // _HANDLE_GET_PRINTABLE_AMOUNT_H_

View File

@@ -0,0 +1,67 @@
#include "handle_swap_sign_transaction.h"
#include "usbd_core.h"
#include "ux.h"
#include "shared_context.h"
#include "utils.h"
void copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params, chain_config_t *config) {
// first copy parameters to stack, and then to global data.
// We need this "trick" as the input data position can overlap with app-ethereum globals
txStringProperties_t stack_data;
memset(&stack_data, 0, sizeof(stack_data));
strncpy(stack_data.fullAddress, sign_transaction_params->destination_address, sizeof(stack_data.fullAddress));
if ((stack_data.fullAddress[sizeof(stack_data.fullAddress) - 1] != '\0') ||
(sign_transaction_params->amount_length > 8) ||
(sign_transaction_params->fee_amount_length > 8)) {
os_lib_end();
}
uint8_t decimals;
char ticker[MAX_TICKER_LEN];
if(!parse_swap_config(sign_transaction_params->coin_configuration, sign_transaction_params->coin_configuration_length, ticker, &decimals)){
PRINTF("Error while parsing config\n");
os_lib_end();
}
amountToString(sign_transaction_params->amount, sign_transaction_params->amount_length, decimals, ticker, stack_data.fullAmount, sizeof(stack_data.fullAmount));
// If the amount is a fee, its value is nominated in ETH even if we're doing an ERC20 swap
strcpy(ticker, config->coinName);
decimals = WEI_TO_ETHER;
amountToString(sign_transaction_params->fee_amount, sign_transaction_params->fee_amount_length, decimals, ticker, stack_data.maxFee, sizeof(stack_data.maxFee));
memcpy(&strings.common, &stack_data, sizeof(stack_data));
}
void handle_swap_sign_transaction(create_transaction_parameters_t* sign_transaction_params, chain_config_t *config) {
copy_transaction_parameters(sign_transaction_params, config);
chainConfig = config;
reset_app_context();
called_from_swap = true;
io_seproxyhal_init();
if (N_storage.initialized != 0x01) {
internalStorage_t storage;
storage.dataAllowed = 0x00;
storage.contractDetails = 0x00;
storage.initialized = 0x01;
nvm_write((void*)&N_storage, (void*)&storage, sizeof(internalStorage_t));
}
dataAllowed = N_storage.dataAllowed;
contractDetails = N_storage.contractDetails;
UX_INIT();
USB_power(0);
USB_power(1);
//ui_idle();
PRINTF("USB power ON/OFF\n");
#ifdef TARGET_NANOX
// grab the current plane mode setting
G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
#endif // TARGET_NANOX
#ifdef HAVE_BLE
BLE_power(0, NULL);
BLE_power(1, "Nano X");
#endif // HAVE_BLE
app_main();
}

View File

@@ -0,0 +1,9 @@
#ifndef _HANDLE_SWAP_SIGN_TRANSACTION_H_
#define _HANDLE_SWAP_SIGN_TRANSACTION_H_
#include "swap_lib_calls.h"
#include "chainConfig.h"
void handle_swap_sign_transaction(create_transaction_parameters_t* get_printable_amount_params, chain_config_t *config);
#endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_

View File

@@ -30,6 +30,11 @@
#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"
#ifdef HAVE_STARKWARE
#include "stark_crypto.h"
#endif
@@ -46,8 +51,7 @@ txContext_t txContext;
tmpContent_t tmpContent;
dataContext_t dataContext;
strings_t strings;
cx_sha3_t sha3;
cx_sha3_t global_sha3;
uint8_t dataAllowed;
uint8_t contractDetails;
@@ -57,6 +61,7 @@ char addressSummary[32];
#endif
bool dataPresent;
contract_call_t contractProvisioned;
bool called_from_swap;
#ifdef HAVE_STARKWARE
bool quantumSet;
#endif
@@ -83,13 +88,14 @@ static const char const CONTRACT_ADDRESS[] = "New contract";
chain_config_t *chainConfig;
void reset_app_context() {
PRINTF("!!RESET_APP_CONTEXT\n");
//PRINTF("!!RESET_APP_CONTEXT\n");
appState = APP_STATE_IDLE;
os_memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
contractProvisioned = CONTRACT_NONE;
#ifdef HAVE_STARKWARE
called_from_swap = false;
#ifdef HAVE_STARKWARE
quantumSet = false;
#endif
#endif
os_memset((uint8_t*)&txContext, 0, sizeof(txContext));
os_memset((uint8_t*)&tmpContent, 0, sizeof(tmpContent));
}
@@ -506,10 +512,10 @@ void handleApdu(unsigned int *flags, unsigned int *tx) {
break;
}
CLOSE_TRY;
return;
return;
}
#endif
#endif
if (G_io_apdu_buffer[OFFSET_CLA] != CLA) {
THROW(0x6E00);
@@ -579,7 +585,7 @@ void handleApdu(unsigned int *flags, unsigned int *tx) {
END_TRY;
}
void sample_main(void) {
void app_main(void) {
unsigned int rx = 0;
unsigned int tx = 0;
unsigned int flags = 0;
@@ -611,7 +617,7 @@ void sample_main(void) {
handleApdu(&flags, &tx);
}
CATCH(EXCEPTION_IO_RESET) {
THROW(EXCEPTION_IO_RESET);
THROW(EXCEPTION_IO_RESET);
}
CATCH_OTHER(e) {
switch (e & 0xF000) {
@@ -686,7 +692,7 @@ unsigned char io_event(unsigned char channel) {
{
});
break;
#endif
#endif
}
// close the event if not done previously (by a display or whatever)
@@ -698,7 +704,7 @@ unsigned char io_event(unsigned char channel) {
return 1;
}
void app_exit(void) {
void app_exit() {
BEGIN_TRY_L(exit) {
TRY_L(exit) {
@@ -711,65 +717,13 @@ void app_exit(void) {
END_TRY_L(exit);
}
chain_config_t const C_chain_config = {
.coinName = CHAINID_COINNAME " ",
.chainId = CHAIN_ID,
.kind = CHAIN_KIND,
#ifdef TARGET_BLUE
.color_header = COLOR_APP,
.color_dashboard = COLOR_APP_LIGHT,
.header_text = CHAINID_UPCASE,
#endif // TARGET_BLUE
};
__attribute__((section(".boot"))) int main(int arg0) {
#ifdef USE_LIB_ETHEREUM
chain_config_t local_chainConfig;
os_memmove(&local_chainConfig, &C_chain_config, sizeof(chain_config_t));
unsigned int libcall_params[3];
unsigned char coinName[sizeof(CHAINID_COINNAME)];
strcpy(coinName, CHAINID_COINNAME);
#ifdef TARGET_BLUE
unsigned char coinNameUP[sizeof(CHAINID_UPCASE)];
strcpy(coinNameUP, CHAINID_UPCASE);
local_chainConfig.header_text = coinNameUP;
#endif // TARGET_BLUE
local_chainConfig.coinName = coinName;
BEGIN_TRY {
TRY {
// ensure syscall will accept us
check_api_level(CX_COMPAT_APILEVEL);
// delegate to Ethereum app/lib
libcall_params[0] = "Ethereum";
libcall_params[1] = 0x100; // use the Init call, as we won't exit
libcall_params[2] = &local_chainConfig;
os_lib_call(&libcall_params);
}
FINALLY {
app_exit();
}
}
END_TRY;
#else
// exit critical section
__asm volatile("cpsie i");
if (arg0) {
if (((unsigned int *)arg0)[0] != 0x100) {
os_lib_throw(INVALID_PARAMETER);
}
chainConfig = (chain_config_t *)((unsigned int *)arg0)[1];
}
else {
chainConfig = (chain_config_t *)PIC(&C_chain_config);
}
void coin_main_with_config(chain_config_t *config) {
chainConfig = config;
reset_app_context();
tmpCtx.transactionContext.currentTokenIndex = 0;
// ensure exception will work as planned
os_boot();
for (;;) {
UX_INIT();
@@ -783,11 +737,11 @@ __attribute__((section(".boot"))) int main(int arg0) {
#endif // TARGET_NANOX
if (N_storage.initialized != 0x01) {
internalStorage_t storage;
storage.dataAllowed = 0x00;
storage.contractDetails = 0x00;
storage.initialized = 0x01;
nvm_write((void*)&N_storage, (void*)&storage, sizeof(internalStorage_t));
internalStorage_t storage;
storage.dataAllowed = 0x00;
storage.contractDetails = 0x00;
storage.initialized = 0x01;
nvm_write((void*)&N_storage, (void*)&storage, sizeof(internalStorage_t));
}
dataAllowed = N_storage.dataAllowed;
contractDetails = N_storage.contractDetails;
@@ -801,28 +755,156 @@ __attribute__((section(".boot"))) int main(int arg0) {
BLE_power(0, NULL);
BLE_power(1, "Nano X");
#endif // HAVE_BLE
#if defined(TARGET_BLUE)
#if defined(TARGET_BLUE)
// setup the status bar colors (remembered after wards, even more if another app does not resetup after app switch)
UX_SET_STATUS_BAR_COLOR(0xFFFFFF, chainConfig->color_header);
#endif // #if defined(TARGET_BLUE)
#endif // #if defined(TARGET_BLUE)
sample_main();
app_main();
}
CATCH(EXCEPTION_IO_RESET) {
// reset IO and UX before continuing
CLOSE_TRY;
continue;
// reset IO and UX before continuing
CLOSE_TRY;
continue;
}
CATCH_ALL {
CLOSE_TRY;
break;
CLOSE_TRY;
break;
}
FINALLY {
}
}
END_TRY;
}
app_exit();
app_exit();
}
void init_coin_config(chain_config_t *coin_config) {
os_memset(coin_config, 0, sizeof(chain_config_t));
strcpy(coin_config->coinName, CHAINID_COINNAME " ");
coin_config->chainId = CHAIN_ID;
coin_config->kind = CHAIN_KIND;
#ifdef TARGET_BLUE
coin_config.color_header = COLOR_APP;
coin_config.color_dashboard = COLOR_APP_LIGHT;
strcpy(coin_config->header_text, CHAINID_UPCASE);
#endif // TARGET_BLUE
}
void coin_main() {
chain_config_t coin_config;
init_coin_config(&coin_config);
coin_main_with_config(&coin_config);
}
void library_main_with_config(chain_config_t *config, unsigned int command, unsigned int* call_parameters) {
BEGIN_TRY {
TRY {
check_api_level(CX_COMPAT_APILEVEL);
PRINTF("Inside a library \n");
switch (command) {
case CHECK_ADDRESS:
handle_check_address((check_address_parameters_t*)call_parameters, config);
break;
case SIGN_TRANSACTION:
handle_swap_sign_transaction((create_transaction_parameters_t*)call_parameters, config);
break;
case GET_PRINTABLE_AMOUNT:
handle_get_printable_amount((get_printable_amount_parameters_t*)call_parameters, config);
break;
}
os_lib_end();
}
FINALLY {}
}
END_TRY;
}
void library_main(unsigned int call_id, unsigned int* call_parameters) {
chain_config_t coin_config;
init_coin_config(&coin_config);
library_main_with_config(&coin_config, call_id, call_parameters);
}
__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
libcall_params[2] = ((unsigned int *)arg0)[1];
libcall_params[4] = ((unsigned int *)arg0)[3]; // library arguments
os_lib_call(&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(&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();
return 0;
}
if (((unsigned int *)arg0)[0] != 0x100) {
app_exit();
return 0;
}
unsigned int command = ((unsigned int *)arg0)[1];
chain_config_t * chain_config = ((unsigned int *)arg0)[2];
switch (command) {
case RUN_APPLICATION:
// coin application launched from dashboard
if (chain_config == NULL)
app_exit();
else
coin_main_with_config(chain_config);
break;
default:
if (chain_config == NULL)
// Called as standalone eth library
library_main(command, ((unsigned int *)arg0)[3]);// called as bitcoin library
else
// Called as a library from an altcoin
library_main_with_config(chain_config, command, ((unsigned int *)arg0)[3]);// called as coin library
break;
}
#endif
return 0;
}

View File

@@ -125,11 +125,11 @@ typedef enum {
#endif
} contract_call_t;
typedef struct strData_t {
typedef struct txStringProperties_t {
char fullAddress[43];
char fullAmount[50];
char maxFee[50];
} strData_t;
} txStringProperties_t;
typedef struct strDataTmp_t {
char tmp[100];
@@ -137,7 +137,7 @@ typedef struct strDataTmp_t {
} strDataTmp_t;
typedef union {
strData_t common;
txStringProperties_t common;
strDataTmp_t tmp;
} strings_t;
@@ -148,7 +148,7 @@ extern txContext_t txContext;
extern tmpContent_t tmpContent;
extern dataContext_t dataContext;
extern strings_t strings;
extern cx_sha3_t sha3;
extern cx_sha3_t global_sha3;
extern const internalStorage_t N_storage_real;
#ifdef TARGET_BLUE
@@ -156,6 +156,9 @@ extern bagl_element_t tmp_element;
extern char addressSummary[32];
#endif
extern bool called_from_swap;
extern uint8_t dataAllowed;
extern uint8_t contractDetails;
extern bool dataPresent;
extern uint8_t appState;
extern contract_call_t contractProvisioned;

52
src/swap_lib_calls.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef SWAP_LIB_CALLS
#define SWAP_LIB_CALLS
#include "stdbool.h"
#define RUN_APPLICATION 1
#define SIGN_TRANSACTION 2
#define CHECK_ADDRESS 3
#define GET_PRINTABLE_AMOUNT 4
// structure that should be send to specific coin application to get address
typedef struct check_address_parameters_s {
// IN
unsigned char* coin_configuration;
unsigned char coin_configuration_length;
// serialized path, segwit, version prefix, hash used, dictionary etc.
// fields and serialization format depends on spesific coin app
unsigned char* address_parameters;
unsigned char address_parameters_length;
char *address_to_check;
char *extra_id_to_check;
// OUT
int result;
} check_address_parameters_t;
// structure that should be send to specific coin application to get printable amount
typedef struct get_printable_amount_parameters_s {
// IN
unsigned char* coin_configuration;
unsigned char coin_configuration_length;
unsigned char* amount;
unsigned char amount_length;
bool is_fee;
// OUT
char printable_amount[30];
} get_printable_amount_parameters_t;
typedef struct create_transaction_parameters_s {
unsigned char* coin_configuration;
unsigned char coin_configuration_length;
unsigned char* amount;
unsigned char amount_length;
unsigned char* fee_amount;
unsigned char fee_amount_length;
char *destination_address;
char *destination_address_extra_id;
} create_transaction_parameters_t;
#endif

View File

@@ -20,12 +20,14 @@
#include <stdint.h>
#define MAX_TICKER_LEN 12 // 10 characters + ' ' + '\0'
typedef struct tokenDefinition_t {
#ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR
uint8_t contractName[20];
#endif
uint8_t address[20];
uint8_t ticker[12]; // 10 characters + ' \0'
uint8_t ticker[MAX_TICKER_LEN];
uint8_t decimals;
} tokenDefinition_t;

View File

@@ -39,13 +39,13 @@ UX_FLOW_DEF_VALID(
&C_icon_dashboard_x,
"Quit",
});
const ux_flow_step_t * const ux_idle_flow [] = {
UX_FLOW(ux_idle_flow,
&ux_idle_flow_1_step,
&ux_idle_flow_2_step,
&ux_idle_flow_3_step,
&ux_idle_flow_4_step,
FLOW_END_STEP,
};
FLOW_LOOP
);
#if defined(TARGET_NANOS)

View File

@@ -19,7 +19,9 @@
#include <string.h>
#include "ethUstream.h"
#include "ethUtils.h"
#include "uint256.h"
#include "tokens.h"
static const unsigned char hex_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
@@ -75,4 +77,40 @@ uint32_t getV(txContent_t *txContent) {
THROW(EXCEPTION);
}
return v;
}
void amountToString(uint8_t* amount, uint8_t amount_size, uint8_t decimals, char* ticker, char* out_buffer, uint8_t out_buffer_size){
uint256_t amount_256;
char tmp_buffer[100];
convertUint256BE(amount, amount_size, &amount_256);
tostring256(&amount_256, 10, tmp_buffer, 100);
uint8_t amount_len = strnlen(tmp_buffer, sizeof(tmp_buffer));
uint8_t ticker_len = strnlen(ticker, MAX_TICKER_LEN);
memcpy(out_buffer, ticker, MIN(out_buffer_size, ticker_len));
adjustDecimals(tmp_buffer, amount_len, out_buffer + ticker_len, out_buffer_size - ticker_len -1, decimals);
out_buffer[out_buffer_size-1] = '\0';
}
bool parse_swap_config(uint8_t* config, uint8_t config_len, char* ticker, uint8_t* decimals){
uint8_t ticker_len, offset = 0;
if (config_len == 0){
return false;
}
ticker_len = config[offset++];
if(ticker_len == 0 || ticker_len > MAX_TICKER_LEN - 2 || config_len - offset < ticker_len){
return false;
}
memcpy(ticker, config+offset, ticker_len);
offset += ticker_len;
ticker[ticker_len] = ' ';
ticker[ticker_len+1] = '\0';
if(config_len - offset < 1){
return false;
}
*decimals = config[offset];
return true;
}

View File

@@ -30,4 +30,8 @@ int local_strchr(char *string, char ch);
uint32_t getV(txContent_t *txContent);
void amountToString(uint8_t* amount, uint8_t amount_len, uint8_t decimals, char* ticker, char* out_buffer, uint8_t out_buffer_size);
bool parse_swap_config(uint8_t* config, uint8_t config_len, char* ticker, uint8_t* decimals);
#endif /* _UTILS_H_ */