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
2729bool 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 */
67203static 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+ */
82224bool 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+ */
102250bool 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+ */
122276bool swap_check_fee (const char * fee ) {
123277 if (fee == NULL ) {
124278 return false;
0 commit comments