Skip to content

Commit 87c7b98

Browse files
Merge pull request #527 from LedgerHQ/feat/apa/eip712_address_substitution
EIP-712 address substitution
2 parents adbe34c + faa2d3a commit 87c7b98

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+279
-49
lines changed

client/CHANGELOG.md

Lines changed: 10 additions & 0 deletions

client/src/ledger_app_clients/ethereum/client.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,25 @@ def personal_sign(self, path: str, msg: bytes):
231231
with self._send(chunk):
232232
pass
233233
return self._send(chunks[-1])
234+
235+
def provide_token_metadata(self,
236+
ticker: str,
237+
addr: bytes,
238+
decimals: int,
239+
chain_id: int,
240+
sig: Optional[bytes] = None):
241+
if sig is None:
242+
# Temporarily get a command with an empty signature to extract the payload and
243+
# compute the signature on it
244+
tmp = self._cmd_builder.provide_erc20_token_information(ticker,
245+
addr,
246+
decimals,
247+
chain_id,
248+
bytes())
249+
# skip APDU header & empty sig
250+
sig = sign_data(Key.CAL, tmp[6:])
251+
return self._send(self._cmd_builder.provide_erc20_token_information(ticker,
252+
addr,
253+
decimals,
254+
chain_id,
255+
sig))

client/src/ledger_app_clients/ethereum/command_builder.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class InsType(IntEnum):
1313
GET_PUBLIC_ADDR = 0x02
1414
SIGN = 0x04
1515
PERSONAL_SIGN = 0x08
16+
PROVIDE_ERC20_TOKEN_INFORMATION = 0x0a
1617
PROVIDE_NFT_INFORMATION = 0x14
1718
SET_PLUGIN = 0x16
1819
EIP712_SEND_STRUCT_DEF = 0x1a
@@ -310,3 +311,21 @@ def personal_sign(self, path: str, msg: bytes):
310311
payload = payload[chunk_size:]
311312
p1 = P1Type.SIGN_SUBSQT_CHUNK
312313
return chunks
314+
315+
def provide_erc20_token_information(self,
316+
ticker: str,
317+
addr: bytes,
318+
decimals: int,
319+
chain_id: int,
320+
sig: bytes) -> bytes:
321+
payload = bytearray()
322+
payload.append(len(ticker))
323+
payload += ticker.encode()
324+
payload += addr
325+
payload += struct.pack(">I", decimals)
326+
payload += struct.pack(">I", chain_id)
327+
payload += sig
328+
return self._serialize(InsType.PROVIDE_ERC20_TOKEN_INFORMATION,
329+
0x00,
330+
0x00,
331+
payload)

client/src/ledger_app_clients/ethereum/eip712/InputData.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,12 +337,11 @@ def next_timeout(_signum: int, _frame):
337337

338338

339339
def enable_autonext():
340-
seconds = 1/4
341340
if app_client._client.firmware.device == 'stax': # Stax Speculos is slow
342-
interval = seconds * 3
341+
delay = 1.5
343342
else:
344-
interval = seconds
345-
signal.setitimer(signal.ITIMER_REAL, seconds, interval)
343+
delay = 1/4
344+
signal.setitimer(signal.ITIMER_REAL, delay, delay)
346345

347346

348347
def disable_autonext():

src_features/signMessageEIP712/ui_logic.c

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "typed_data.h"
1717
#include "commands_712.h"
1818
#include "common_ui.h"
19+
#include "domain_name.h"
1920

2021
static t_ui_context *ui_ctx = NULL;
2122

@@ -184,6 +185,46 @@ static void ui_712_format_str(const uint8_t *const data, uint8_t length) {
184185
}
185186
}
186187

188+
/**
189+
* Find a substitute token ticker for a given address
190+
*
191+
* @param[in] addr the given address
192+
* @return the ticker name if found, \ref NULL otherwise
193+
*/
194+
static const char *get_address_token_ticker(const uint8_t *addr) {
195+
tokenDefinition_t *token;
196+
197+
// Loop over the received token informations
198+
for (uint8_t token_idx = 0; token_idx < MAX_ITEMS; ++token_idx) {
199+
if (tmpCtx.transactionContext.tokenSet[token_idx] == 1) {
200+
token = &tmpCtx.transactionContext.extraInfo[token_idx].token;
201+
if (memcmp(token->address, addr, ADDRESS_LENGTH) == 0) {
202+
return token->ticker;
203+
}
204+
}
205+
}
206+
return NULL;
207+
}
208+
209+
/**
210+
* Find a substitute (token ticker or domain name) for a given address
211+
*
212+
* @param[in] addr the given address
213+
* @return the substitute if found, \ref NULL otherwise
214+
*/
215+
static const char *get_address_substitute(const uint8_t *addr) {
216+
const char *str = NULL;
217+
218+
str = get_address_token_ticker(addr);
219+
if (str == NULL) {
220+
if (has_domain_name(&eip712_context->chain_id, addr)) {
221+
// No handling of the verbose domains setting
222+
str = g_domain_name;
223+
}
224+
}
225+
return str;
226+
}
227+
187228
/**
188229
* Format a given data as a string representation of an address
189230
*
@@ -196,13 +237,20 @@ static bool ui_712_format_addr(const uint8_t *const data, uint8_t length) {
196237
apdu_response_code = APDU_RESPONSE_INVALID_DATA;
197238
return false;
198239
}
240+
199241
if (ui_712_field_shown()) {
200-
if (!getEthDisplayableAddress((uint8_t *) data,
201-
strings.tmp.tmp,
202-
sizeof(strings.tmp.tmp),
203-
&global_sha3,
204-
chainConfig->chainId)) {
205-
THROW(APDU_RESPONSE_ERROR_NO_INFO);
242+
const char *sub;
243+
244+
if (!N_storage.verbose_eip712 && ((sub = get_address_substitute(data)) != NULL)) {
245+
ui_712_set_value(sub, strlen(sub));
246+
} else {
247+
if (!getEthDisplayableAddress((uint8_t *) data,
248+
strings.tmp.tmp,
249+
sizeof(strings.tmp.tmp),
250+
&global_sha3,
251+
chainConfig->chainId)) {
252+
THROW(APDU_RESPONSE_ERROR_NO_INFO);
253+
}
206254
}
207255
}
208256
return true;

tests/ragger/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from pathlib import Path
2+
3+
ROOT_SNAPSHOT_PATH = Path(__file__).parent
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"domain": {
3+
"chainId": 1,
4+
"name": "Token test",
5+
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
6+
"version": "1"
7+
},
8+
"message": {
9+
"from": "0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa",
10+
"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
11+
"amount": "117",
12+
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
13+
},
14+
"primaryType": "Transfer",
15+
"types": {
16+
"EIP712Domain": [
17+
{ "name": "name", "type": "string" },
18+
{ "name": "version", "type": "string" },
19+
{ "name": "chainId", "type": "uint256" },
20+
{ "name": "verifyingContract", "type": "address" }
21+
],
22+
"Transfer": [
23+
{ "name": "from", "type": "address" },
24+
{ "name": "to", "type": "address" },
25+
{ "name": "amount", "type": "uint256" },
26+
{ "name": "token", "type": "address" }
27+
]
28+
}
29+
}
472 Bytes
414 Bytes
338 Bytes

0 commit comments

Comments
 (0)