Skip to content

Commit 65031ce

Browse files
Merge pull request #668 from LedgerHQ/fix/apa/token_swap_with_calldata
[hotfix] Token swap with calldata
2 parents fb2f67f + d862fda commit 65031ce

File tree

6 files changed

+104
-58
lines changed

6 files changed

+104
-58
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## [1.12.2](https://github.com/ledgerhq/app-ethereum/compare/1.12.1...1.12.2) - 2024-10-24
9+
10+
### Fixed
11+
12+
- Token swap with calldata
13+
814
## [1.12.1](https://github.com/ledgerhq/app-ethereum/compare/1.12.0...1.12.1) - 2024-10-02
915

1016
### Fixed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ include ./makefile_conf/chain/$(CHAIN).mk
3737

3838
APPVERSION_M = 1
3939
APPVERSION_N = 12
40-
APPVERSION_P = 1
40+
APPVERSION_P = 2
4141
APPVERSION = $(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
4242

4343
# Application source files

src/eth_plugin_handler.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,34 +140,38 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress,
140140
case ERC721:
141141
#endif // HAVE_NFT_SUPPORT
142142
case EXTERNAL:
143+
PRINTF("eth_plugin_perform_init_default\n");
143144
eth_plugin_perform_init_default(contractAddress, init);
144145
contractAddress = NULL;
145146
break;
146147
case OLD_INTERNAL:
148+
PRINTF("eth_plugin_perform_init_old_internal\n");
147149
if (eth_plugin_perform_init_old_internal(contractAddress, init)) {
148150
contractAddress = NULL;
149151
}
150152
break;
153+
case SWAP_WITH_CALLDATA:
154+
PRINTF("contractAddress == %.*H\n", 20, contractAddress);
155+
PRINTF("Fallback on swap_with_calldata plugin\n");
156+
contractAddress = NULL;
157+
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
158+
break;
151159
default:
152160
PRINTF("Unsupported pluginType %d\n", pluginType);
153161
os_sched_exit(0);
154162
break;
155163
}
156164

157-
if (G_called_from_swap && (contractAddress != NULL)) {
158-
PRINTF("contractAddress == %.*H\n", 20, contractAddress);
159-
PRINTF("selector == %.*H\n", 20, contractAddress);
160-
PRINTF("Fallback on swap_with_calldata plugin\n");
161-
set_swap_with_calldata_plugin_type();
162-
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
163-
contractAddress = NULL;
164-
}
165-
166165
eth_plugin_result_t status = ETH_PLUGIN_RESULT_UNAVAILABLE;
167166

168167
if (contractAddress != NULL) {
169168
PRINTF("No plugin available for %.*H\n", 20, contractAddress);
170-
return status;
169+
if (G_called_from_swap) {
170+
PRINTF("Not supported in swap mode\n");
171+
return ETH_PLUGIN_RESULT_ERROR;
172+
} else {
173+
return status;
174+
}
171175
}
172176

173177
PRINTF("eth_plugin_init\n");

src/handle_swap_sign_transaction.c

Lines changed: 73 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "shared_context.h"
77
#include "common_utils.h"
88
#include "network.h"
9+
#include "cmd_setPlugin.h"
910
#ifdef HAVE_NBGL
1011
#include "nbgl_use_case.h"
1112
#endif // HAVE_NBGL
@@ -37,10 +38,14 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
3738
// We need this "trick" as the input data position can overlap with app-ethereum globals
3839
txStringProperties_t stack_data;
3940
uint8_t destination_address_extra_data[CX_SHA256_SIZE + 1];
41+
uint8_t swap_crosschain_hash[sizeof(G_swap_crosschain_hash)];
42+
swap_mode_t swap_mode;
4043

41-
memset(&stack_data, 0, sizeof(stack_data));
42-
memset(destination_address_extra_data, 0, sizeof(destination_address_extra_data));
44+
explicit_bzero(&stack_data, sizeof(stack_data));
45+
explicit_bzero(destination_address_extra_data, sizeof(destination_address_extra_data));
46+
explicit_bzero(swap_crosschain_hash, sizeof(swap_crosschain_hash));
4347

48+
// Set destination address
4449
strlcpy(stack_data.toAddress,
4550
sign_transaction_params->destination_address,
4651
sizeof(stack_data.toAddress));
@@ -49,81 +54,100 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
4954
(sign_transaction_params->fee_amount_length > 8)) {
5055
return false;
5156
}
57+
PRINTF("Expecting destination_address %s\n", stack_data.toAddress);
5258

5359
if (sign_transaction_params->destination_address_extra_id != NULL) {
5460
memcpy(destination_address_extra_data,
5561
sign_transaction_params->destination_address_extra_id,
5662
sizeof(destination_address_extra_data));
5763
}
5864

59-
char ticker[MAX_TICKER_LEN];
60-
uint8_t decimals;
65+
// if destination_address_extra_id is given, we use the first byte to determine if we use the
66+
// normal swap protocol, or the one for cross-chain swaps
67+
switch (destination_address_extra_data[0]) {
68+
case EXTRA_ID_TYPE_NATIVE:
69+
// we don't use the payin_extra_id field in this mode
70+
swap_mode = SWAP_MODE_STANDARD;
71+
PRINTF("Standard swap\n");
72+
break;
73+
case EXTRA_ID_TYPE_EVM_CALLDATA:
74+
swap_mode = SWAP_MODE_CROSSCHAIN_PENDING_CHECK;
75+
76+
memcpy(swap_crosschain_hash,
77+
destination_address_extra_data + 1,
78+
sizeof(swap_crosschain_hash));
79+
80+
PRINTF("Crosschain swap with hash: %.*H\n", CX_SHA256_SIZE, swap_crosschain_hash);
81+
break;
82+
default:
83+
// We can't return errors from here, we remember that we have an issue to report later
84+
PRINTF("Invalid or unknown swap protocol\n");
85+
swap_mode = SWAP_MODE_ERROR;
86+
}
87+
88+
char asset_ticker[MAX_TICKER_LEN];
89+
uint8_t asset_decimals;
6190
uint64_t chain_id = 0;
6291

6392
if (!parse_swap_config(sign_transaction_params->coin_configuration,
6493
sign_transaction_params->coin_configuration_length,
65-
ticker,
66-
&decimals,
94+
asset_ticker,
95+
&asset_decimals,
6796
&chain_id)) {
6897
PRINTF("Error while parsing config\n");
6998
return false;
7099
}
71-
if (!amountToString(sign_transaction_params->amount,
72-
sign_transaction_params->amount_length,
73-
decimals,
74-
ticker,
75-
stack_data.fullAmount,
76-
sizeof(stack_data.fullAmount))) {
77-
return false;
78-
}
79100

80101
// fallback mechanism in the absence of chain ID in swap config
81102
if (chain_id == 0) {
82103
chain_id = config->chainId;
83104
}
84-
// If the amount is a fee, its value is nominated in ETH even if we're doing an ERC20 swap
85-
strlcpy(ticker, get_displayable_ticker(&chain_id, config), sizeof(ticker));
86-
decimals = WEI_TO_ETHER;
105+
PRINTF("chain_id = %d\n", (uint32_t) chain_id);
106+
107+
// If the amount is a fee, its value is nominated in NATIVE even if we're doing an ERC20 swap
108+
const char* native_ticker = get_displayable_ticker(&chain_id, config);
109+
uint8_t native_decimals = WEI_TO_ETHER;
87110
if (!amountToString(sign_transaction_params->fee_amount,
88111
sign_transaction_params->fee_amount_length,
89-
decimals,
90-
ticker,
112+
native_decimals,
113+
native_ticker,
91114
stack_data.maxFee,
92115
sizeof(stack_data.maxFee))) {
93116
return false;
94117
}
118+
PRINTF("Expecting fees %s\n", stack_data.maxFee);
119+
120+
if (swap_mode == SWAP_MODE_CROSSCHAIN_PENDING_CHECK &&
121+
strcmp(native_ticker, asset_ticker) != 0) {
122+
// Special case: crosschain swap of non native assets (tokens)
123+
uint8_t zero_amount = 0;
124+
if (!amountToString(&zero_amount,
125+
1,
126+
native_decimals,
127+
native_ticker,
128+
stack_data.fullAmount,
129+
sizeof(stack_data.fullAmount))) {
130+
return false;
131+
}
132+
} else {
133+
if (!amountToString(sign_transaction_params->amount,
134+
sign_transaction_params->amount_length,
135+
asset_decimals,
136+
asset_ticker,
137+
stack_data.fullAmount,
138+
sizeof(stack_data.fullAmount))) {
139+
return false;
140+
}
141+
}
142+
PRINTF("Expecting amount %s\n", stack_data.fullAmount);
95143

96144
// Full reset the global variables
97145
os_explicit_zero_BSS_segment();
98146
// Keep the address at which we'll reply the signing status
99147
G_swap_sign_return_value_address = &sign_transaction_params->result;
100148
// Commit the values read from exchange to the clean global space
101-
102-
// if destination_address_extra_id is given, we use the first byte to determine if we use the
103-
// normal swap protocol, or the one for cross-chain swaps
104-
switch (destination_address_extra_data[0]) {
105-
case EXTRA_ID_TYPE_NATIVE:
106-
G_swap_mode = SWAP_MODE_STANDARD;
107-
PRINTF("Standard swap\n");
108-
109-
// we don't use the payin_extra_id field in this mode
110-
explicit_bzero(G_swap_crosschain_hash, sizeof(G_swap_crosschain_hash));
111-
break;
112-
case EXTRA_ID_TYPE_EVM_CALLDATA:
113-
G_swap_mode = SWAP_MODE_CROSSCHAIN_PENDING_CHECK;
114-
115-
memcpy(G_swap_crosschain_hash,
116-
destination_address_extra_data + 1,
117-
sizeof(G_swap_crosschain_hash));
118-
119-
PRINTF("Crosschain swap with hash: %.*H\n", CX_SHA256_SIZE, G_swap_crosschain_hash);
120-
break;
121-
default:
122-
// We can't return errors from here, we remember that we have an issue to report later
123-
PRINTF("Invalid or unknown swap protocol\n");
124-
G_swap_mode = SWAP_MODE_ERROR;
125-
}
126-
149+
G_swap_mode = swap_mode;
150+
memcpy(G_swap_crosschain_hash, swap_crosschain_hash, sizeof(G_swap_crosschain_hash));
127151
memcpy(&strings.common, &stack_data, sizeof(stack_data));
128152
return true;
129153
}
@@ -138,6 +162,10 @@ void __attribute__((noreturn)) handle_swap_sign_transaction(const chain_config_t
138162
reset_app_context();
139163
G_called_from_swap = true;
140164
G_swap_response_ready = false;
165+
// If we are in crosschain context, automatically register the CROSSCHAIN plugin
166+
if (G_swap_mode == SWAP_MODE_CROSSCHAIN_PENDING_CHECK) {
167+
set_swap_with_calldata_plugin_type();
168+
}
141169

142170
common_app_init();
143171

src_features/signTx/cmd_signTx.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,14 @@ uint16_t handleSign(uint8_t p1,
8383
case USTREAM_PROCESSING:
8484
return APDU_RESPONSE_OK;
8585
case USTREAM_FAULT:
86-
return APDU_RESPONSE_INVALID_DATA;
86+
if (G_called_from_swap) {
87+
// We have encountered an error while trying to sign a SWAP type transaction
88+
// Return dedicated error code and flag an early exit back to Exchange
89+
G_swap_response_ready = true;
90+
return APDU_RESPONSE_MODE_CHECK_FAILED;
91+
} else {
92+
return APDU_RESPONSE_INVALID_DATA;
93+
}
8794
default:
8895
PRINTF("Unexpected parser status\n");
8996
return APDU_RESPONSE_INVALID_DATA;

src_features/signTx/logic_signTx.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ customStatus_e customProcessor(txContext_t *context) {
5757
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_UNAVAILABLE;
5858
// If contract debugging mode is activated, do not go through the plugin activation
5959
// as they wouldn't be displayed if the plugin consumes all data but fallbacks
60-
if (!N_storage.contractDetails) {
60+
// Still go through plugin activation in Swap context
61+
if (!N_storage.contractDetails || G_called_from_swap) {
6162
eth_plugin_prepare_init(&pluginInit,
6263
context->workBuffer,
6364
context->currentFieldLength);

0 commit comments

Comments
 (0)