Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Swap feature to Solana application #44

Merged
merged 13 commits into from
Apr 18, 2023
2 changes: 1 addition & 1 deletion .github/workflows/ci-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
path: scan-build

python_tests_nano:
name: NanoS Ragger tests
name: Ragger tests
needs: build_application
runs-on: ubuntu-latest
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ jobs:
# Use Config file when the github action supports it
builtin: clear,rare
check_filenames: true
skip: ./libsol,./tests
skip: ./libsol/printer_test.c,./tests/Cargo.lock
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ endif

include $(BOLOS_SDK)/Makefile.defines

APP_LOAD_PARAMS = --curve ed25519
ifeq ($(TARGET_NAME), TARGET_NANOX)
APP_LOAD_PARAMS += --appFlags 0x200 # APPLICATION_FLAG_BOLOS_SETTINGS
APP_LOAD_PARAMS = --curve ed25519
ifeq ($(TARGET_NAME), TARGET_NANOS)
APP_LOAD_PARAMS += --appFlags 0x800 # APPLICATION_FLAG_LIBRARY
else
APP_LOAD_PARAMS += --appFlags 0x000
APP_LOAD_PARAMS += --appFlags 0xa00 # APPLICATION_FLAG_LIBRARY + APPLICATION_FLAG_BOLOS_SETTINGS
endif
APP_LOAD_PARAMS += --path "44'/501'"
APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS)
Expand Down
1 change: 1 addition & 0 deletions doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 1.3.0

- Add SIGN SOLANA OFF-CHAIN MESSAGE
- Add compatibility with the Exchange Application to SWAP, FUND, or SELL SOL tokens

## About

Expand Down
2 changes: 1 addition & 1 deletion libsol/message_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <assert.h>
#include <stdio.h>

// Disable clang format for this file to keep clear buffer formating
// Disable clang format for this file to keep clear buffer formatting
/* clang-format off */

void test_process_message_body_ok() {
Expand Down
2 changes: 1 addition & 1 deletion src/apdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,4 @@ int apdu_handle_message(const uint8_t* apdu_message,
apdu_command->state = ApduStatePayloadComplete;

return 0;
}
}
4 changes: 2 additions & 2 deletions src/getPubkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ UX_STEP_NOCB(ux_display_public_flow_5_step,
});
UX_STEP_CB(ux_display_public_flow_6_step,
pb,
sendResponse(set_result_get_pubkey(), true),
sendResponse(set_result_get_pubkey(), true, true),
{
&C_icon_validate_14,
"Approve",
});
UX_STEP_CB(ux_display_public_flow_7_step,
pb,
sendResponse(0, false),
sendResponse(0, false, true),
{
&C_icon_crossmark,
"Reject",
Expand Down
5 changes: 4 additions & 1 deletion src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ typedef enum InstructionCode {
InsSignOffchainMessage = 0x07
} InstructionCode;

extern volatile bool G_called_from_swap;
extern volatile bool G_swap_response_ready;

// display stepped screens
extern unsigned int ux_step;
extern unsigned int ux_step_count;
Expand Down Expand Up @@ -84,4 +87,4 @@ typedef struct internalStorage_t {

extern const internalStorage_t N_storage_real;
#define N_storage (*(volatile internalStorage_t*) PIC(&N_storage_real))
#endif
#endif
109 changes: 101 additions & 8 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,16 @@
#include "apdu.h"
#include "menu.h"

// Swap feature
#include "swap_lib_calls.h"
#include "handle_swap_sign_transaction.h"
#include "handle_get_printable_amount.h"
#include "handle_check_address.h"

ApduCommand G_command;
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
volatile bool G_called_from_swap;
volatile bool G_swap_response_ready;

static void reset_main_globals(void) {
MEMCLEAR(G_command);
fbeutin-ledger marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -41,8 +49,10 @@ void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx, int rx)

const int ret = apdu_handle_message(G_io_apdu_buffer, rx, &G_command);
if (ret != 0) {
MEMCLEAR(G_command);
THROW(ret);
}

if (G_command.state == ApduStatePayloadInProgress) {
THROW(ApduReplySuccess);
}
Expand Down Expand Up @@ -96,7 +106,6 @@ void app_main(void) {
// APDU injection faults.
for (;;) {
volatile unsigned short sw = 0;

BEGIN_TRY {
TRY {
rx = tx;
Expand All @@ -105,6 +114,12 @@ void app_main(void) {
rx = io_exchange(CHANNEL_APDU | flags, rx);
flags = 0;

if (G_called_from_swap && G_swap_response_ready) {
PRINTF("Quitting app started in swap mode\n");
// Quit app, we are in limited mode and our work is done
os_sched_exit(0);
}

// no apdu received, well, reset the session, and reset the
// bootloader configuration
if (rx == 0) {
Expand Down Expand Up @@ -260,13 +275,8 @@ void nv_app_state_init() {
}
}

__attribute__((section(".boot"))) int main(void) {
// exit critical section
__asm volatile("cpsie i");

// ensure exception will work as planned
os_boot();

void coin_main(void) {
G_called_from_swap = false;
for (;;) {
UX_INIT();

Expand Down Expand Up @@ -307,5 +317,88 @@ __attribute__((section(".boot"))) int main(void) {
END_TRY;
}
app_exit();
}

static void start_app_from_lib(void) {
G_called_from_swap = true;
G_swap_response_ready = false;
UX_INIT();
io_seproxyhal_init();
nv_app_state_init();
USB_power(0);
USB_power(1);
#ifdef HAVE_BLE
// Erase globals that may inherit values from exchange
MEMCLEAR(G_io_asynch_ux_callback);
// grab the current plane mode setting
G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
BLE_power(0, NULL);
BLE_power(1, "Nano X");
#endif // HAVE_BLE
app_main();
}

static void library_main_helper(libargs_t *args) {
check_api_level(CX_COMPAT_APILEVEL);
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);
lpascal-ledger marked this conversation as resolved.
Show resolved Hide resolved
break;
case SIGN_TRANSACTION:
if (copy_transaction_parameters(args->create_transaction)) {
// never returns
start_app_from_lib();
}
break;
case GET_PRINTABLE_AMOUNT:
handle_get_printable_amount(args->get_printable_amount);
break;
default:
break;
}
}

static void library_main(libargs_t *args) {
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) {
// exit critical section
__asm volatile("cpsie i");

// ensure exception will work as planned
os_boot();

if (arg0 == 0) {
// called from dashboard as standalone app
coin_main();
} else {
// Called as library from another app
libargs_t *args = (libargs_t *) arg0;
if (args->id == 0x100) {
library_main(args);
} else {
app_exit();
}
}

return 0;
}
77 changes: 63 additions & 14 deletions src/signMessage.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "globals.h"
#include "apdu.h"

#include "handle_swap_sign_transaction.h"

static uint8_t set_result_sign_message() {
uint8_t signature[SIGNATURE_LENGTH];
cx_ecfp_private_key_t privateKey;
Expand Down Expand Up @@ -43,22 +45,18 @@ static uint8_t set_result_sign_message() {
return SIGNATURE_LENGTH;
}

static void send_result_sign_message(void) {
sendResponse(set_result_sign_message(), true);
}

//////////////////////////////////////////////////////////////////////

UX_STEP_CB(ux_approve_step,
pb,
send_result_sign_message(),
sendResponse(set_result_sign_message(), true, true),
{
&C_icon_validate_14,
"Approve",
});
UX_STEP_CB(ux_reject_step,
pb,
sendResponse(0, false),
sendResponse(0, false, true),
{
&C_icon_crossmark,
"Reject",
Expand Down Expand Up @@ -167,22 +165,73 @@ void handle_sign_message_parse_message(volatile unsigned int *tx) {
}
}

static bool check_swap_validity(const SummaryItemKind_t kinds[MAX_TRANSACTION_SUMMARY_ITEMS],
agrojean-ledger marked this conversation as resolved.
Show resolved Hide resolved
size_t num_summary_steps) {
bool amount_ok = false;
bool recipient_ok = false;
if (num_summary_steps != 2) {
PRINTF("2 steps expected for transaction in swap context, not %u\n", num_summary_steps);
return false;
}
for (size_t i = 0; i < num_summary_steps; ++i) {
transaction_summary_display_item(i, DisplayFlagNone | DisplayFlagLongPubkeys);
switch (kinds[i]) {
case SummaryItemAmount:
amount_ok =
check_swap_amount(G_transaction_summary_title, G_transaction_summary_text);
break;
case SummaryItemPubkey:
recipient_ok =
check_swap_recipient(G_transaction_summary_title, G_transaction_summary_text);
break;
default:
PRINTF("Refused kind '%u'\n", kinds[i]);
return false;
}
}
return amount_ok && recipient_ok;
}

void handle_sign_message_ui(volatile unsigned int *flags) {
// Display the transaction summary
SummaryItemKind_t summary_step_kinds[MAX_TRANSACTION_SUMMARY_ITEMS];
size_t num_summary_steps = 0;
if (transaction_summary_finalize(summary_step_kinds, &num_summary_steps) == 0) {
size_t num_flow_steps = 0;
// If we are in swap context, do not redisplay the message data
fbeutin-ledger marked this conversation as resolved.
Show resolved Hide resolved
// Instead, ensure they are identitical with what was previously displayed
if (G_called_from_swap) {
if (G_swap_response_ready) {
fbeutin-ledger marked this conversation as resolved.
Show resolved Hide resolved
// Safety against trying to make the app sign multiple TX
// This code should never be triggered as the app is supposed to exit after
// sending the signed transaction
PRINTF("Safety against double signing triggered\n");
os_sched_exit(-1);
} else {
// We will quit the app after this transaction, whether it succeeds or fails
PRINTF("Swap response is ready, the app will quit after the next send\n");
G_swap_response_ready = true;
}
if (check_swap_validity(summary_step_kinds, num_summary_steps)) {
PRINTF("Valid swap transaction signed\n");
sendResponse(set_result_sign_message(), true, false);
} else {
PRINTF("Refused signing incorrect Swap transaction\n");
THROW(ApduReplySolanaSummaryFinalizeFailed);
}
} else {
MEMCLEAR(flow_steps);
size_t num_flow_steps = 0;

for (size_t i = 0; i < num_summary_steps; i++) {
flow_steps[num_flow_steps++] = &ux_summary_step;
}
for (size_t i = 0; i < num_summary_steps; i++) {
flow_steps[num_flow_steps++] = &ux_summary_step;
}

flow_steps[num_flow_steps++] = &ux_approve_step;
flow_steps[num_flow_steps++] = &ux_reject_step;
flow_steps[num_flow_steps++] = FLOW_END_STEP;
flow_steps[num_flow_steps++] = &ux_approve_step;
flow_steps[num_flow_steps++] = &ux_reject_step;
flow_steps[num_flow_steps++] = FLOW_END_STEP;

ux_flow_init(0, flow_steps, NULL);
ux_flow_init(0, flow_steps, NULL);
}
} else {
THROW(ApduReplySolanaSummaryFinalizeFailed);
}
Expand Down
4 changes: 2 additions & 2 deletions src/signOffchainMessage.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@ UX_STEP_NOCB(ux_sign_msg_text_step,
});
UX_STEP_CB(ux_sign_msg_approve_step,
pb,
sendResponse(set_result_sign_message(), true),
sendResponse(set_result_sign_message(), true, true),
{
&C_icon_validate_14,
"Approve",
});
UX_STEP_CB(ux_sign_msg_reject_step,
pb,
sendResponse(0, false),
sendResponse(0, false, true),
{
&C_icon_crossmark,
"Reject",
Expand Down
Loading