Skip to content

Commit 786f2c1

Browse files
Update swap utils to handle network config
1 parent fc11363 commit 786f2c1

File tree

4 files changed

+213
-66
lines changed

4 files changed

+213
-66
lines changed

src/eth_swap_utils.c

Lines changed: 178 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,46 +23,182 @@
2323
#include "utils.h"
2424
#include "swap_error_code_helpers.h"
2525
#include "feature_signTx.h"
26+
#include "network.h"
2627

28+
// Global flag indicating whether swap parameters have been verified
2729
bool G_swap_checked;
2830

29-
bool parse_swap_config(const uint8_t *config,
30-
uint8_t config_len,
31-
char *ticker,
32-
uint8_t *decimals,
33-
uint64_t *chain_id) {
34-
uint8_t ticker_len, offset = 0;
31+
/**
32+
* Helper function to parse a token info (ticker + decimals) from config buffer
33+
*
34+
* @param config Pointer to the current position in config buffer
35+
* @param config_len Total length of the config buffer
36+
* @param info Output structure to store parsed token info
37+
* @param offset Pointer to current offset (updated after parsing)
38+
* @return true if parsing succeeds, false otherwise
39+
*/
40+
static bool parse_token_info(const uint8_t *config,
41+
uint8_t config_len,
42+
swap_info_t *info,
43+
uint8_t *offset) {
44+
uint8_t ticker_len;
3545

36-
if ((config == NULL) || (config_len == 0) || (ticker == NULL) || (decimals == NULL)) {
46+
// Check if we have enough data for ticker length
47+
if (*offset >= config_len) {
48+
PRINTF("Not enough data for ticker length\n");
3749
return false;
3850
}
39-
ticker_len = config[offset];
40-
offset += sizeof(ticker_len);
41-
if ((ticker_len == 0) || (ticker_len > (MAX_TICKER_LEN - 2)) ||
42-
((config_len - offset) < (ticker_len))) {
51+
52+
// Read ticker length
53+
ticker_len = config[*offset];
54+
(*offset)++;
55+
56+
// Validate ticker length
57+
if ((ticker_len == 0) || (ticker_len > (MAX_TICKER_LEN - 2))) {
58+
PRINTF("Ticker length is invalid (%d)\n", ticker_len);
4359
return false;
4460
}
45-
memcpy(ticker, config + offset, ticker_len);
46-
offset += ticker_len;
47-
ticker[ticker_len] = '\0';
4861

49-
if ((config_len - offset) < 1) {
62+
// Check if we have enough data for ticker
63+
if ((*offset + ticker_len) > config_len) {
64+
PRINTF("Not enough data for ticker\n");
5065
return false;
5166
}
52-
*decimals = config[offset];
53-
offset += sizeof(*decimals);
5467

55-
// the chain ID was adder later to the CAL swap subconfig
56-
// so it is optional for retro-compatibility (as it might not be present)
57-
if ((chain_id != NULL) && ((config_len - offset) >= sizeof(*chain_id))) {
58-
PRINTF("Chain ID from the swap subconfig = 0x%.*h\n", sizeof(*chain_id), &config[offset]);
59-
*chain_id = u64_from_BE(config + offset, sizeof(*chain_id));
68+
// Copy ticker and add null terminator
69+
memcpy(info->ticker, config + *offset, ticker_len);
70+
info->ticker[ticker_len] = '\0';
71+
*offset += ticker_len;
72+
73+
// Check if we have enough data for decimals
74+
if (*offset >= config_len) {
75+
PRINTF("Not enough data for decimals\n");
76+
return false;
6077
}
78+
79+
// Read decimals
80+
info->decimals = config[*offset];
81+
(*offset)++;
82+
6183
return true;
6284
}
6385

64-
/* Local implementation of strncasecmp, workaround of the segfaulting base implem on return value
65-
* Remove once strncasecmp is fixed
86+
/**
87+
* Parse swap configuration from CAL (Crypto Asset Library)
88+
*
89+
* @param config Buffer containing the configuration to parse
90+
* @param config_len Length of the configuration buffer
91+
* @param context Output structure to store all parsed swap information
92+
* @return true if parsing succeeds, false otherwise
93+
*
94+
* @note Configuration buffer format (app-specific):
95+
* @code
96+
* +---------+--------------------+----------+--------------------------+
97+
* | Offset | Field | Size | Description |
98+
* +---------+--------------------+----------+--------------------------+
99+
* | 0 | asset_ticker_len | 1 byte | Length of asset_ticker |
100+
* | 1 | asset_ticker | n bytes | Asset symbol |
101+
* | 1+n | asset_decimals | 1 byte | Asset decimal places |
102+
* | 2+n | chain_id | 8 bytes | Chain ID (BE) |
103+
* | 2+n+8 | network_ticker_len | 1 byte | Length of network_ticker |
104+
* | 2+n+9 | network_ticker | m bytes | Network symbol |
105+
* | 2+n+9+m | network_decimals | 1 byte | Network decimal places |
106+
* +---------+--------------------+----------+--------------------------+
107+
* @endcode
108+
*
109+
* @note The chain ID and network fields are optional (backward compatibility)
110+
*/
111+
bool parse_swap_config(const uint8_t *config, uint8_t config_len, swap_context_t *context) {
112+
uint8_t offset = 0;
113+
uint8_t chainid_len = sizeof(context->chain_id);
114+
115+
// Validate input parameters
116+
if ((config == NULL) || (config_len == 0) || (context == NULL)) {
117+
PRINTF("Invalid input parameters to parse_swap_config\n");
118+
return false;
119+
}
120+
121+
// Initialize defaults
122+
context->asset_info.ticker[0] = '\0';
123+
context->network_info.ticker[0] = '\0';
124+
context->network_info.decimals = WEI_TO_ETHER; // Default to ETH decimals
125+
context->chain_id = 0;
126+
127+
// Parse asset token info
128+
if (!parse_token_info(config, config_len, &context->asset_info, &offset)) {
129+
PRINTF("Failed to parse asset info\n");
130+
return false;
131+
}
132+
133+
// Parse chain ID (optional)
134+
if ((config_len - offset) < chainid_len) {
135+
PRINTF("No chain ID is present\n");
136+
return true;
137+
}
138+
// Read chain ID (big-endian)
139+
PRINTF("Chain ID from the swap subconfig = 0x%.*h\n", chainid_len, &config[offset]);
140+
context->chain_id = u64_from_BE(config + offset, chainid_len);
141+
offset += chainid_len;
142+
143+
// Parse network token info (optional, for retrocompatibility)
144+
if (offset >= config_len) {
145+
PRINTF("No network info is present\n");
146+
return true;
147+
}
148+
149+
if (!parse_token_info(config, config_len, &context->network_info, &offset)) {
150+
PRINTF("Failed to parse network info\n");
151+
return false;
152+
}
153+
154+
return true;
155+
}
156+
157+
/**
158+
* Parse swap configuration from CAL (Crypto Asset Library)
159+
*
160+
* @param is_fee Indicates if the amount is a fee
161+
* @param context Output structure to store all parsed swap information
162+
* @param config Chain configuration for fallback mechanisms
163+
* @param ticker Output pointer to store the resolved ticker
164+
* @param decimals Output pointer to store the resolved decimals (can be NULL)
165+
*/
166+
void parse_network_config(bool is_fee,
167+
swap_context_t *context,
168+
chain_config_t *config,
169+
char **ticker,
170+
uint8_t *decimals) {
171+
// If the amount is a fee, the ticker should be the chain's native currency
172+
if (is_fee) {
173+
if (context->network_info.ticker[0] == '\0') {
174+
// fallback mechanism in the absence of network ticker in swap config
175+
if (context->chain_id == 0) {
176+
// fallback mechanism in the absence of chain ID in swap config
177+
context->chain_id = config->chainId;
178+
}
179+
PRINTF("chain_id = %d\n", (uint32_t) context->chain_id);
180+
*ticker = (char *) get_displayable_ticker(&context->chain_id, config, false);
181+
} else {
182+
*ticker = context->network_info.ticker;
183+
}
184+
if (decimals != NULL) {
185+
*decimals = context->network_info.decimals;
186+
}
187+
} else {
188+
*ticker = context->asset_info.ticker;
189+
if (decimals != NULL) {
190+
*decimals = context->asset_info.decimals;
191+
}
192+
}
193+
}
194+
195+
/**
196+
* Local implementation of strcasecmp, workaround for the segfaulting base implementation
197+
* on return value. Remove once strcasecmp is fixed.
198+
*
199+
* @param str1 First string to compare
200+
* @param str2 Second string to compare
201+
* @return 0 if strings are equal (case-insensitive), difference otherwise
66202
*/
67203
static int strcasecmp_workaround(const char *str1, const char *str2) {
68204
unsigned char c1, c2;
@@ -79,6 +215,12 @@ static int strcasecmp_workaround(const char *str1, const char *str2) {
79215
return 0;
80216
}
81217

218+
/**
219+
* Verify that the destination address matches the previously validated one
220+
*
221+
* @param destination Destination address to verify
222+
* @return true if destination matches, false otherwise (exits app on failure)
223+
*/
82224
bool swap_check_destination(const char *destination) {
83225
if (destination == NULL) {
84226
return false;
@@ -99,6 +241,12 @@ bool swap_check_destination(const char *destination) {
99241
return true;
100242
}
101243

244+
/**
245+
* Verify that the amount matches the previously validated one
246+
*
247+
* @param amount Amount to verify
248+
* @return true if amount matches, false otherwise (exits app on failure)
249+
*/
102250
bool swap_check_amount(const char *amount) {
103251
if (amount == NULL) {
104252
return false;
@@ -119,6 +267,12 @@ bool swap_check_amount(const char *amount) {
119267
return true;
120268
}
121269

270+
/**
271+
* Verify that the fee matches the previously validated one
272+
*
273+
* @param fee Fee to verify
274+
* @return true if fee matches, false otherwise (exits app on failure)
275+
*/
122276
bool swap_check_fee(const char *fee) {
123277
if (fee == NULL) {
124278
return false;

src/eth_swap_utils.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@
2525

2626
extern bool G_swap_checked;
2727

28+
typedef struct {
29+
char ticker[MAX_TICKER_LEN];
30+
uint8_t decimals;
31+
} swap_info_t;
32+
33+
typedef struct {
34+
swap_info_t asset_info;
35+
swap_info_t network_info;
36+
uint64_t chain_id;
37+
} swap_context_t;
38+
2839
typedef struct eth_libargs_s {
2940
unsigned int id;
3041
unsigned int command;
@@ -37,11 +48,13 @@ typedef struct eth_libargs_s {
3748
};
3849
} eth_libargs_t;
3950

40-
bool parse_swap_config(const uint8_t *config,
41-
uint8_t config_len,
42-
char *ticker,
43-
uint8_t *decimals,
44-
uint64_t *chain_id);
51+
bool parse_swap_config(const uint8_t *config, uint8_t config_len, swap_context_t *context);
52+
void parse_network_config(bool is_fee,
53+
swap_context_t *context,
54+
chain_config_t *config,
55+
char **ticker,
56+
uint8_t *decimals);
57+
4558
bool swap_check_destination(const char *destination);
4659
bool swap_check_amount(const char *amount);
4760
bool swap_check_fee(const char *fee);

src/handle_get_printable_amount.c

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
#include "os.h"
22
#include "eth_swap_utils.h"
3-
#include "network.h"
43
#include "apdu_constants.h"
54

65
uint16_t handle_get_printable_amount(get_printable_amount_parameters_t* params,
76
chain_config_t* config) {
8-
char ticker[MAX_TICKER_LEN];
9-
uint8_t decimals;
10-
uint64_t chain_id = 0;
7+
swap_context_t context = {0};
8+
char* ticker = NULL;
9+
uint8_t decimals = 0;
1110

1211
memset(params->printable_amount, 0, sizeof(params->printable_amount));
1312
if (params->amount_length > 32) {
@@ -17,21 +16,12 @@ uint16_t handle_get_printable_amount(get_printable_amount_parameters_t* params,
1716

1817
if (!parse_swap_config(params->coin_configuration,
1918
params->coin_configuration_length,
20-
ticker,
21-
&decimals,
22-
&chain_id)) {
19+
&context)) {
2320
PRINTF("Error while parsing config\n");
2421
return SWO_INCORRECT_DATA;
2522
}
2623
// If the amount is a fee, the ticker should be the chain's native currency
27-
if (params->is_fee) {
28-
// fallback mechanism in the absence of chain ID in swap config
29-
if (chain_id == 0) {
30-
chain_id = config->chainId;
31-
}
32-
strlcpy(ticker, get_displayable_ticker(&chain_id, config, false), sizeof(ticker));
33-
decimals = WEI_TO_ETHER;
34-
}
24+
parse_network_config(params->is_fee, &context, config, &ticker, &decimals);
3525

3626
if (!amountToString(params->amount,
3727
params->amount_length,

src/handle_swap_sign_transaction.c

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "eth_swap_utils.h"
22
#include "shared_context.h"
3-
#include "network.h"
43
#include "cmd_setPlugin.h"
54
#include "nbgl_use_case.h"
65
#include "mem.h"
@@ -70,55 +69,46 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
7069
swap_mode = SWAP_MODE_ERROR;
7170
}
7271

73-
char asset_ticker[MAX_TICKER_LEN];
74-
uint8_t asset_decimals;
75-
uint64_t chain_id = 0;
72+
swap_context_t context = {0};
73+
char* ticker = NULL;
7674

7775
if (!parse_swap_config(sign_transaction_params->coin_configuration,
7876
sign_transaction_params->coin_configuration_length,
79-
asset_ticker,
80-
&asset_decimals,
81-
&chain_id)) {
77+
&context)) {
8278
PRINTF("Error while parsing config\n");
8379
return false;
8480
}
8581

86-
// fallback mechanism in the absence of chain ID in swap config
87-
if (chain_id == 0) {
88-
chain_id = config->chainId;
89-
}
90-
PRINTF("chain_id = %d\n", (uint32_t) chain_id);
91-
9282
// If the amount is a fee, its value is nominated in NATIVE even if we're doing an ERC20 swap
93-
const char* native_ticker = get_displayable_ticker(&chain_id, config, false);
94-
uint8_t native_decimals = WEI_TO_ETHER;
83+
parse_network_config(true, &context, (chain_config_t*) config, &ticker, NULL);
84+
9585
if (!amountToString(sign_transaction_params->fee_amount,
9686
sign_transaction_params->fee_amount_length,
97-
native_decimals,
98-
native_ticker,
87+
context.network_info.decimals,
88+
ticker,
9989
stack_data.maxFee,
10090
sizeof(stack_data.maxFee))) {
10191
return false;
10292
}
10393
PRINTF("Expecting fees %s\n", stack_data.maxFee);
10494

10595
if (swap_mode == SWAP_MODE_CROSSCHAIN_PENDING_CHECK &&
106-
strcmp(native_ticker, asset_ticker) != 0) {
96+
strcmp(ticker, context.asset_info.ticker) != 0) {
10797
// Special case: crosschain swap of non native assets (tokens)
10898
uint8_t zero_amount = 0;
10999
if (!amountToString(&zero_amount,
110100
1,
111-
native_decimals,
112-
native_ticker,
101+
context.network_info.decimals,
102+
ticker,
113103
stack_data.fullAmount,
114104
sizeof(stack_data.fullAmount))) {
115105
return false;
116106
}
117107
} else {
118108
if (!amountToString(sign_transaction_params->amount,
119109
sign_transaction_params->amount_length,
120-
asset_decimals,
121-
asset_ticker,
110+
context.asset_info.decimals,
111+
context.asset_info.ticker,
122112
stack_data.fullAmount,
123113
sizeof(stack_data.fullAmount))) {
124114
return false;

0 commit comments

Comments
 (0)