swap_copy_transaction_parameters()
ledger-secure-sdk/lib_standard_app/swap_entrypoints.h
/* This handle is called when the user has validated on screen the transaction
* proposal sent by the partner and started the FROM Coin application to sign
* the payment transaction.
*
* This handler needs to save in the heap the details of what has been validated
* in Exchange. These elements will be checked against the received transaction
* upon its reception from the Ledger Live.
*
* return false on error, true otherwise
*/
bool swap_copy_transaction_parameters(create_transaction_parameters_t *sign_transaction_params);
ledger-secure-sdk/lib_standard_app/swap_lib_calls.h
typedef struct create_transaction_parameters_s {
// INPUTS //
// Additional data when dealing with tokens
// Content is coin application specific
uint8_t *coin_configuration;
uint8_t coin_configuration_length;
// The amount validated on the screen by the user
uint8_t *amount;
uint8_t amount_length;
// The fees amount validated on the screen by the user
uint8_t *fee_amount;
uint8_t fee_amount_length;
// The partner address that will receive the funds
char *destination_address;
char *destination_address_extra_id;
// OUTPUT //
// /!\ This parameter is handled by the lib_standard_app, DO NOT interact
// with it in the Coin application
//
// After reception and signature or refusal of the transaction, the Coin
// application will return to Exchange. This boolean is used to inform the
// Exchange application of the result.
// Set to 1 if the transaction was successfully signed, 0 otherwise.
uint8_t result;
} create_transaction_parameters_t;
Example of handle implementation in Boilerplate
app-boilerplate/src/swap/handle_swap_sign_transaction.c
typedef struct swap_validated_s {
bool initialized;
uint64_t amount;
uint64_t fee;
char recipient[ADDRESS_LEN * 2 + 1];
uint8_t decimals;
char ticker[MAX_TICKER_SIZE];
} swap_validated_t;
/* Global variable used to store swap validation status */
static swap_validated_t G_swap_validated;
static bool is_token_swap(void) {
return (strcmp(G_swap_validated.ticker, "BOL") != 0 ||
G_swap_validated.decimals != EXPONENT_SMALLEST_UNIT);
}
bool swap_copy_transaction_parameters(create_transaction_parameters_t* params) {
PRINTF("Inside swap_copy_transaction_parameters\n");
if (params->destination_address == NULL) {
PRINTF("Destination address expected\n");
return false;
}
if (strlen(params->destination_address) != (ADDRESS_LEN * 2)) {
PRINTF("Destination address wrong length\n");
return false;
}
if (params->amount == NULL) {
PRINTF("Amount expected\n");
return false;
}
// first copy parameters to stack, and then to global data.
// We need this "trick" as the input data position can overlap with app globals
// and also because we want to memset the whole bss segment as it is not done
// when an app is called as a lib.
// This is necessary as many part of the code expect bss variables to
// initialized at 0.
swap_validated_t swap_validated;
explicit_bzero(&swap_validated, sizeof(swap_validated));
// Save recipient as an uppercase string
for (int i = 0; i < ADDRESS_LEN * 2; i++) {
if (params->destination_address[i] >= 'a' && params->destination_address[i] <= 'z') {
swap_validated.recipient[i] = params->destination_address[i] - 'a' + 'A';
} else {
swap_validated.recipient[i] = params->destination_address[i];
}
}
PRINTF("Validated recipient: %s\n", swap_validated.recipient);
// Parse config and save decimals and ticker
// If there is no coin_configuration, consider that we are doing a SOL swap
if (params->coin_configuration == NULL) {
memcpy(swap_validated.ticker, "BOL", sizeof("BOL"));
swap_validated.decimals = EXPONENT_SMALLEST_UNIT;
} else {
if (!swap_parse_config(params->coin_configuration,
params->coin_configuration_length,
swap_validated.ticker,
sizeof(swap_validated.ticker),
&swap_validated.decimals)) {
PRINTF("Fail to parse coin_configuration\n");
return false;
}
}
PRINTF("Validated ticker: %s, decimals: %d\n", swap_validated.ticker, swap_validated.decimals);
// Save amount
if (!swap_str_to_u64(params->amount, params->amount_length, &swap_validated.amount)) {
PRINTF("Failed to convert amount to uint64_t\n");
return false;
}
// Can't print u64
PRINTF("Validated amount: %.*H\n", sizeof(swap_validated.amount), &swap_validated.amount);
// Save fee
if (!swap_str_to_u64(params->fee_amount, params->fee_amount_length, &swap_validated.fee)) {
PRINTF("Failed to convert fee to uint64_t\n");
return false;
}
PRINTF("Validated fee: %.*H\n", sizeof(swap_validated.fee), &swap_validated.fee);
swap_validated.initialized = true;
// Full reset the global variables
os_explicit_zero_BSS_segment();
// Commit from stack to global data, params becomes tainted but we won't access it anymore
memcpy(&G_swap_validated, &swap_validated, sizeof(swap_validated));
return true;
}