Merge pull request #183 from LedgerHQ/bigger_chainid

Improve display for big chainIDs
This commit is contained in:
pscott
2021-09-03 15:24:22 +02:00
committed by GitHub
107 changed files with 1360 additions and 845 deletions

View File

@@ -124,13 +124,17 @@ jobs:
- name: Build/Install build js deps
run: |
cd tests && yarn install
- name: Create tmp folder for artifacts
run: |
mkdir tests/elfs
- name: Download app binaries
uses: actions/download-artifact@v2
with:
path: tests/elfs
- name: Gather elfs
run: |
cp `find . -name "*.elf"` ./tests/elfs
cd tests/elfs
cp `find . -name "*.elf"` .
- name: Run zemu tests
run: |
cd tests && yarn test

3
.gitignore vendored
View File

@@ -14,6 +14,7 @@ obj/
tests/node_modules
tests/lib
tests/yarn-error.log
tests/elfs/*
tests/snapshots/tmp/*
.vscode

View File

@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.9.3](https://github.com/ledgerhq/app-ethereum/compare/1.9.2...1.9.3) - 2021-9-03
### Added
- Added better display for bigger chainIDs.
- Added support for Songbird.
- Added support for Celo.
### Changed
- Small refactor of `getEthDisplayableAddress` helper
- Improve Zemu tests to get parallelization
- Increased plugin interface to version 2
- Remove support for Theta and Flare
## [1.9.2](https://github.com/ledgerhq/app-ethereum/compare/1.9.0...1.9.2) - 2021-8-11
### Added

View File

@@ -30,7 +30,7 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'"
APPVERSION_M=1
APPVERSION_N=9
APPVERSION_P=2
APPVERSION_P=3
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
APP_LOAD_FLAGS= --appFlags 0x240 --dep Ethereum:$(APPVERSION)
@@ -203,17 +203,17 @@ else ifeq ($(CHAIN),flare_coston)
APP_LOAD_PARAMS += --path "44'/554'" --path "44'/60'"
DEFINES += CHAINID_UPCASE=\"FLARE\" CHAINID_COINNAME=\"FLR\" CHAIN_KIND=CHAIN_KIND_FLARE CHAIN_ID=16
APPNAME = "Flare Coston"
else ifeq ($(CHAIN),theta)
APP_LOAD_PARAMS += --path "44'/500'"
DEFINES += CHAINID_UPCASE=\"THETA\" CHAINID_COINNAME=\"THETA\" CHAIN_KIND=CHAIN_KIND_THETA CHAIN_ID=500
APPNAME = "Theta"
else ifeq ($(CHAIN),bsc)
APP_LOAD_PARAMS += --path "44'/60'"
DEFINES += CHAINID_UPCASE=\"BSC\" CHAINID_COINNAME=\"BNB\" CHAIN_KIND=CHAIN_KIND_BSC CHAIN_ID=56
APPNAME = "Binance Smart Chain"
else ifeq ($(CHAIN),songbird)
APP_LOAD_PARAMS += --path "44'/554'" --path "44'/60'"
DEFINES += CHAINID_UPCASE=\"SONGBIRD\" CHAINID_COINNAME=\"SGB\" CHAIN_KIND=CHAIN_KIND_SONGBIRD CHAIN_ID=19
APPNAME = "Songbird"
else
ifeq ($(filter clean,$(MAKECMDGOALS)),)
$(error Unsupported CHAIN - use ethereum, ropsten, ethereum_classic, expanse, poa, artis_sigma1, artis_tau1, rsk, rsk_testnet, ubiq, wanchain, kusd, musicoin, pirl, akroma, atheios, callisto, ethersocial, ellaism, ether1, ethergem, gochain, mix, reosc, hpb, tomochain, tobalaba, dexon, volta, ewc, webchain, thundercore, flare, flare_coston, theta)
$(error Unsupported CHAIN - use ethereum, ropsten, ethereum_classic, expanse, poa, artis_sigma1, artis_tau1, rsk, rsk_testnet, ubiq, wanchain, kusd, musicoin, pirl, akroma, atheios, callisto, ethersocial, ellaism, ether1, ethergem, gochain, mix, reosc, hpb, tomochain, tobalaba, dexon, volta, ewc, webchain, thundercore, bsc, songbird)
endif
endif
@@ -384,4 +384,4 @@ include $(BOLOS_SDK)/Makefile.rules
dep/%.d: %.c Makefile
listvariants:
@echo VARIANTS CHAIN ethereum ropsten ethereum_classic expanse poa rsk rsk_testnet ubiq wanchain pirl akroma atheios callisto ethersocial ether1 gochain musicoin ethergem mix ellaism reosc hpb tomochain dexon volta ewc thundercore flare flare_coston theta bsc
@echo VARIANTS CHAIN ethereum ropsten ethereum_classic expanse poa rsk rsk_testnet ubiq wanchain pirl akroma atheios callisto ethersocial ether1 gochain musicoin ethergem mix ellaism reosc hpb tomochain dexon volta ewc thundercore bsc songbird

View File

@@ -17,8 +17,15 @@ Testing is done via the open-source framework [zemu](https://github.com/Zondax/z
## Running tests
First [install yarn](https://classic.yarnpkg.com/en/docs/install/#debian-stable).
Open `tests/build_local_test_elfs.sh` and add your BOLOS SDKs path to `NANOS_SDK` and `NANOX_SDK`.
This helper script will build the applications required by the test suite and move them at the right place.
```
cd test
./build_local_test_elfs.sh
```
Then you can install the project by simply running:
```
cd ..
make test
```
This will run `make install_tests` and `make run_tests`

View File

@@ -520,7 +520,7 @@ The following standard Status Words are returned for all APDUs - some specific S
|===============================================================================================
| *SW* | *Description*
| 6501 | TransactionType not supported
| 6502 | Output buffer too small for snprintf input
| 6502 | Output buffer too small for chainId conversion
| 6503 | Plugin error
| 6504 | Failed to convert from int256
| 6700 | Incorrect length

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 B

BIN
icons/songbird.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -54,13 +54,13 @@ typedef enum chain_kind_e {
CHAIN_KIND_WEBCHAIN,
CHAIN_KIND_THUNDERCORE,
CHAIN_KIND_FLARE,
CHAIN_KIND_THETA,
CHAIN_KIND_BSC
CHAIN_KIND_BSC,
CHAIN_KIND_SONGBIRD
} chain_kind_t;
typedef struct chain_config_s {
char coinName[10]; // ticker
uint32_t chainId;
uint64_t chainId;
chain_kind_t kind;
} chain_config_t;

View File

@@ -153,7 +153,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
case ETH_PLUGIN_INIT_CONTRACT:
PRINTF("-- PLUGIN INIT CONTRACT --\n");
((ethPluginInitContract_t *) parameter)->interfaceVersion =
ETH_PLUGIN_INTERFACE_VERSION_1;
ETH_PLUGIN_INTERFACE_VERSION_LATEST;
((ethPluginInitContract_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethPluginInitContract_t *) parameter)->pluginSharedRW = &pluginRW;
((ethPluginInitContract_t *) parameter)->pluginSharedRO = &pluginRO;

View File

@@ -12,6 +12,7 @@
// Interface version. To be updated everytime we introduce breaking changes to the plugin interface.
typedef enum {
ETH_PLUGIN_INTERFACE_VERSION_1 = 1, // Version 1
ETH_PLUGIN_INTERFACE_VERSION_LATEST = 2,
} eth_plugin_interface_version_t;
typedef enum {

View File

@@ -61,7 +61,7 @@ int handle_check_address(check_address_parameters_t* params, chain_config_t* cha
getEthAddressStringFromKey(&locals_union2.publicKey,
locals_union1.address,
&local_sha3,
chain_config);
chain_config->chainId);
ZERO(locals_union2);
uint8_t offset_0x = 0;

View File

@@ -250,12 +250,12 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) {
case CHAIN_KIND_FLARE:
numTokens = NUM_TOKENS_FLARE;
break;
case CHAIN_KIND_THETA:
numTokens = NUM_TOKENS_THETA;
break;
case CHAIN_KIND_BSC:
numTokens = NUM_TOKENS_BSC;
break;
case CHAIN_KIND_SONGBIRD:
numTokens = NUM_TOKENS_SONGBIRD;
break;
}
for (i = 0; i < numTokens; i++) {
switch (chainConfig->kind) {
@@ -352,12 +352,12 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) {
case CHAIN_KIND_FLARE:
currentToken = (tokenDefinition_t *) PIC(&TOKENS_FLARE[i]);
break;
case CHAIN_KIND_THETA:
currentToken = (tokenDefinition_t *) PIC(&TOKENS_THETA[i]);
break;
case CHAIN_KIND_BSC:
currentToken = (tokenDefinition_t *) PIC(&TOKENS_BSC[i]);
break;
case CHAIN_KIND_SONGBIRD:
currentToken = (tokenDefinition_t *) PIC(&TOKENS_SONGBIRD[i]);
break;
}
if (memcmp(currentToken->address, tmpContent.txContent.destination, ADDRESS_LENGTH) == 0) {
return currentToken;
@@ -876,22 +876,22 @@ __attribute__((section(".boot"))) int main(int arg0) {
PRINTF("Hello from Eth-clone\n");
check_api_level(CX_COMPAT_APILEVEL);
// delegate to Ethereum app/lib
libcall_params[0] = "Ethereum";
libcall_params[0] = (unsigned int) "Ethereum";
libcall_params[1] = 0x100;
libcall_params[2] = RUN_APPLICATION;
libcall_params[3] = &local_chainConfig;
libcall_params[3] = (unsigned int) &local_chainConfig;
libcall_params[4] = 0;
if (arg0) {
// call as a library
libcall_params[2] = ((unsigned int *) arg0)[1];
libcall_params[4] = ((unsigned int *) arg0)[3]; // library arguments
os_lib_call(&libcall_params);
os_lib_call((unsigned int *) &libcall_params);
((unsigned int *) arg0)[0] = libcall_params[1];
os_lib_end();
} else {
// launch coin application
libcall_params[1] = 0x100; // use the Init call, as we won't exit
os_lib_call(&libcall_params);
os_lib_call((unsigned int *) &libcall_params);
}
}
FINALLY {

View File

@@ -162,14 +162,14 @@ typedef enum {
#endif
} contract_call_t;
#define NETWORK_NAME_MAX_SIZE 12
#define NETWORK_STRING_MAX_SIZE 16
typedef struct txStringProperties_t {
char fullAddress[43];
char fullAmount[50];
char maxFee[50];
char nonce[8]; // 10M tx per account ought to be enough for everybody
char network_name[NETWORK_NAME_MAX_SIZE];
char network_name[NETWORK_STRING_MAX_SIZE];
} txStringProperties_t;
#define SHARED_CTX_FIELD_1_SIZE 100

View File

@@ -3853,10 +3853,6 @@ const tokenDefinition_t const TOKENS_ETHEREUM[NUM_TOKENS_ETHEREUM] = {
0x91, 0x9a, 0xbc, 0x23, 0x5c, 0xa4, 0xfd, 0x7f, 0x72, 0xc1},
"TGT ",
1},
{{0x38, 0x83, 0xf5, 0xe1, 0x81, 0xfc, 0xca, 0xf8, 0x41, 0x0f,
0xa6, 0x1e, 0x12, 0xb5, 0x9b, 0xad, 0x96, 0x3f, 0xb6, 0x45},
"THETA ",
18},
{{0x1c, 0xb3, 0x20, 0x9d, 0x45, 0xb2, 0xa6, 0x0b, 0x7f, 0xbc,
0xa1, 0xcc, 0xdb, 0xf8, 0x7f, 0x67, 0x42, 0x37, 0xa4, 0xaa},
"THR ",
@@ -4564,8 +4560,8 @@ const tokenDefinition_t const TOKENS_THUNDERCORE[NUM_TOKENS_THUNDERCORE] = {};
const tokenDefinition_t const TOKENS_FLARE[NUM_TOKENS_FLARE] = {};
const tokenDefinition_t const TOKENS_THETA[NUM_TOKENS_THETA] = {};
const tokenDefinition_t const TOKENS_BSC[NUM_TOKENS_BSC] = {};
const tokenDefinition_t const TOKENS_SONGBIRD[NUM_TOKENS_SONGBIRD] = {};
#endif

View File

@@ -95,8 +95,8 @@ static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
#define NUM_TOKENS_WEBCHAIN 0
#define NUM_TOKENS_THUNDERCORE 0
#define NUM_TOKENS_FLARE 0
#define NUM_TOKENS_THETA 0
#define NUM_TOKENS_BSC 0
#define NUM_TOKENS_SONGBIRD 0
extern tokenDefinition_t const TOKENS_AKROMA[NUM_TOKENS_AKROMA];
extern tokenDefinition_t const TOKENS_ELLAISM[NUM_TOKENS_ELLAISM];
@@ -129,8 +129,8 @@ extern tokenDefinition_t const TOKENS_ARTIS_TAU1[NUM_TOKENS_ARTIS_TAU1];
extern tokenDefinition_t const TOKENS_WEBCHAIN[NUM_TOKENS_WEBCHAIN];
extern tokenDefinition_t const TOKENS_THUNDERCORE[NUM_TOKENS_THUNDERCORE];
extern tokenDefinition_t const TOKENS_FLARE[NUM_TOKENS_FLARE];
extern tokenDefinition_t const TOKENS_THETA[NUM_TOKENS_THETA];
extern tokenDefinition_t const TOKENS_BSC[NUM_TOKENS_BSC];
extern tokenDefinition_t const TOKENS_SONGBIRD[NUM_TOKENS_SONGBIRD];
#endif /* HAVE_TOKENS_LIST */

View File

@@ -54,19 +54,17 @@ int local_strchr(char *string, char ch) {
return -1;
}
uint32_t u32_from_BE(uint8_t *in, uint8_t size) {
switch (size) {
case 0:
return 0;
case 1:
return in[0];
case 2:
return (in[0] << 8) | in[1];
case 3:
return (in[0] << 16) | (in[1] << 8) | in[2];
default:
return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
uint64_t u64_from_BE(uint8_t *in, uint8_t size) {
uint8_t i = 0;
uint64_t res = 0;
while (i < size && i < sizeof(res)) {
res <<= 8;
res |= in[i];
i++;
}
return res;
}
bool uint256_to_decimal(const uint8_t *value, size_t value_len, char *out, size_t out_len) {

View File

@@ -28,7 +28,7 @@ void convertUint256BE(uint8_t* data, uint32_t length, uint256_t* target);
int local_strchr(char* string, char ch);
uint32_t u32_from_BE(uint8_t* in, uint8_t size);
uint64_t u64_from_BE(uint8_t* in, uint8_t size);
bool uint256_to_decimal(const uint8_t* value, size_t value_len, char* out, size_t out_len);

View File

@@ -126,7 +126,7 @@ typedef struct txContent_t {
txInt256_t chainID;
uint8_t destination[ADDRESS_LENGTH];
uint8_t destinationLength;
uint8_t v[4];
uint8_t v[8];
uint8_t vLength;
bool dataPresent;
} txContent_t;

View File

@@ -126,17 +126,45 @@ void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, cx_sha3
void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
char *out,
cx_sha3_t *sha3Context,
chain_config_t *chain_config) {
uint64_t chainId) {
uint8_t hashAddress[INT256_LENGTH];
cx_keccak_init(sha3Context, 256);
cx_hash((cx_hash_t *) sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress, 32);
getEthAddressStringFromBinary(hashAddress + 12, out, sha3Context, chain_config);
getEthAddressStringFromBinary(hashAddress + 12, out, sha3Context, chainId);
}
void u64_to_string(uint64_t src, char *dst, uint8_t dst_size) {
// Copy the numbers in ASCII format.
uint8_t i = 0;
do {
// Checking `i + 1` to make sure we have enough space for '\0'.
if (i + 1 >= dst_size) {
THROW(0x6502);
}
dst[i] = src % 10 + '0';
src /= 10;
i++;
} while (src);
// Null terminate string
dst[i] = '\0';
// Revert the string
i--;
uint8_t j = 0;
while (j < i) {
char tmp = dst[i];
dst[i] = dst[j];
dst[j] = tmp;
i--;
j++;
}
}
void getEthAddressStringFromBinary(uint8_t *address,
char *out,
cx_sha3_t *sha3Context,
chain_config_t *chain_config) {
uint64_t chainId) {
// save some precious stack space
union locals_union {
uint8_t hashChecksum[INT256_LENGTH];
@@ -146,18 +174,17 @@ void getEthAddressStringFromBinary(uint8_t *address,
uint8_t i;
bool eip1191 = false;
uint32_t offset = 0;
switch (chain_config->chainId) {
switch (chainId) {
case 30:
case 31:
eip1191 = true;
break;
}
if (eip1191) {
snprintf((char *) locals_union.tmp,
sizeof(locals_union.tmp),
"%d0x",
chain_config->chainId);
offset = strlen((char *) locals_union.tmp);
u64_to_string(chainId, (char *) locals_union.tmp, sizeof(locals_union.tmp));
offset = strnlen((char *) locals_union.tmp, sizeof(locals_union.tmp));
strlcat((char *) locals_union.tmp + offset, "0x", sizeof(locals_union.tmp) - offset);
offset = strnlen((char *) locals_union.tmp, sizeof(locals_union.tmp));
}
for (i = 0; i < 20; i++) {
uint8_t digit = address[i];
@@ -192,6 +219,24 @@ void getEthAddressStringFromBinary(uint8_t *address,
out[40] = '\0';
}
/* Fills the `out` buffer with the lowercase string representation of the pubkey passed in as binary
format by `in`. (eg: uint8_t*:0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB ->
char*:"0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB\0" )
`sha3` context doesn't have have to be initialized prior to call.*/
void getEthDisplayableAddress(uint8_t *in,
char *out,
size_t out_len,
cx_sha3_t *sha3,
uint64_t chainId) {
if (out_len < 43) {
strlcpy(out, "ERROR", out_len);
return;
}
out[0] = '0';
out[1] = 'x';
getEthAddressStringFromBinary(in, out + 2, sha3, chainId);
}
bool adjustDecimals(char *src,
uint32_t srcLength,
char *target,

View File

@@ -42,12 +42,20 @@ void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, cx_sha3
void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
char *out,
cx_sha3_t *sha3Context,
chain_config_t *chain_config);
uint64_t chainId);
void u64_to_string(uint64_t src, char *dst, uint8_t dst_size);
void getEthAddressStringFromBinary(uint8_t *address,
char *out,
cx_sha3_t *sha3Context,
chain_config_t *chain_config);
uint64_t chainId);
void getEthDisplayableAddress(uint8_t *in,
char *out,
size_t out_len,
cx_sha3_t *sha3,
uint64_t chainId);
bool adjustDecimals(char *src,
uint32_t srcLength,

View File

@@ -19,30 +19,33 @@ const network_info_t NETWORK_MAPPING[] = {
{.chain_id = 100, .name = "xDai", .ticker = "xDAI "},
{.chain_id = 137, .name = "Polygon", .ticker = "MATIC "},
{.chain_id = 250, .name = "Fantom", .ticker = "FTM "},
{.chain_id = 43114, .name = "Avalanche", .ticker = "AVAX "}};
{.chain_id = 42220, .name = "Celo", .ticker = "CELO "},
{.chain_id = 43114, .name = "Avalanche", .ticker = "AVAX "},
{.chain_id = 44787, .name = "Celo Alfajores", .ticker = "aCELO "},
{.chain_id = 62320, .name = "Celo Baklava", .ticker = "bCELO "},
{.chain_id = 11297108109, .name = "Palm Network", .ticker = "PALM "}};
uint32_t get_chain_id(void) {
uint32_t chain_id = 0;
uint64_t get_chain_id(void) {
uint64_t chain_id = 0;
switch (txContext.txType) {
case LEGACY:
chain_id = u32_from_BE(txContext.content->v, txContext.content->vLength);
chain_id = u64_from_BE(txContext.content->v, txContext.content->vLength);
break;
case EIP2930:
case EIP1559:
chain_id = u32_from_BE(tmpContent.txContent.chainID.value,
chain_id = u64_from_BE(tmpContent.txContent.chainID.value,
tmpContent.txContent.chainID.length);
break;
default:
PRINTF("Txtype `%d` not supported while generating chainID\n", txContext.txType);
break;
}
PRINTF("ChainID: %d\n", chain_id);
return chain_id;
}
network_info_t *get_network(void) {
uint32_t chain_id = get_chain_id();
uint64_t chain_id = get_chain_id();
for (uint8_t i = 0; i < sizeof(NETWORK_MAPPING) / sizeof(*NETWORK_MAPPING); i++) {
if (NETWORK_MAPPING[i].chain_id == chain_id) {
return (network_info_t *) PIC(&NETWORK_MAPPING[i]);

View File

@@ -1,16 +1,15 @@
#include <stdint.h>
#include "tokens.h"
#define NETWORK_STRING_MAX_SIZE 12
#include "shared_context.h"
typedef struct network_info_s {
const char name[NETWORK_STRING_MAX_SIZE];
const char ticker[MAX_TICKER_LEN];
uint32_t chain_id;
uint64_t chain_id;
} network_info_t;
// Returns the current chain id. Defaults to 0 if txType was not found.
uint32_t get_chain_id(void);
uint64_t get_chain_id(void);
// Returns a pointer to the network struct, or NULL if there is none.
network_info_t *get_network(void);
// Returns a pointer to the network name, or NULL if there is none.

View File

@@ -50,7 +50,7 @@ void handleGetPublicKey(uint8_t p1,
getEthAddressStringFromKey(&tmpCtx.publicKeyContext.publicKey,
tmpCtx.publicKeyContext.address,
&global_sha3,
chainConfig);
chainConfig->chainId);
#ifndef NO_CONSENT
if (p1 == P1_NON_CONFIRM)
#endif // NO_CONSENT

View File

@@ -59,7 +59,7 @@ void handleSign(uint8_t p1,
} else {
txContext.txType = LEGACY;
}
PRINTF("TxType: %d\n", txContext.txType);
PRINTF("TxType: %x\n", txContext.txType);
} else if (p1 != P1_MORE) {
THROW(0x6B00);
}

View File

@@ -8,6 +8,7 @@
#endif
#include "eth_plugin_handler.h"
#include "network.h"
#include "ethUtils.h"
#define ERR_SILENT_MODE_CHECK_FAILED 0x6001
@@ -261,16 +262,8 @@ void prepareNetworkDisplay() {
char *name = get_network_name();
if (name == NULL) {
// No network name found so simply copy the chain ID as the network name.
uint32_t chain_id = get_chain_id();
uint8_t res = snprintf(strings.common.network_name,
sizeof(strings.common.network_name),
"%d",
chain_id);
if (res >= sizeof(strings.common.network_name)) {
// If the return value is higher or equal to the size passed in as parameter, then
// the output was truncated. Return the appropriate error code.
THROW(0x6502);
}
uint64_t chain_id = get_chain_id();
u64_to_string(chain_id, strings.common.network_name, sizeof(strings.common.network_name));
} else {
// Network name found, simply copy it.
strlcpy(strings.common.network_name, name, sizeof(strings.common.network_name));
@@ -308,7 +301,7 @@ void finalizeParsing(bool direct) {
// Verify the chain
if (chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) {
// TODO: Could we remove above check?
uint32_t id = get_chain_id();
uint64_t id = get_chain_id();
if (chainConfig->chainId != id) {
PRINTF("Invalid chainID %u expected %u\n", id, chainConfig->chainId);
@@ -422,12 +415,11 @@ void finalizeParsing(bool direct) {
// Prepare destination address to display
if (genericUI) {
if (tmpContent.txContent.destinationLength != 0) {
displayBuffer[0] = '0';
displayBuffer[1] = 'x';
getEthAddressStringFromBinary(tmpContent.txContent.destination,
displayBuffer + 2,
&global_sha3,
chainConfig);
getEthDisplayableAddress(tmpContent.txContent.destination,
displayBuffer,
sizeof(displayBuffer),
&global_sha3,
chainConfig->chainId);
compareOrCopy(strings.common.fullAddress,
sizeof(strings.common.fullAddress),
displayBuffer,
@@ -459,9 +451,11 @@ void finalizeParsing(bool direct) {
// Compute maximum fee
prepareFeeDisplay();
PRINTF("Fees displayed: %s\n", strings.common.maxFee);
// Prepare chainID field
prepareNetworkDisplay();
PRINTF("Network: %s\n", strings.common.network_name);
bool no_consent;

View File

@@ -7,7 +7,6 @@ unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_elemen
uint8_t signature[100];
cx_ecfp_private_key_t privateKey;
uint32_t tx = 0;
uint32_t v = u32_from_BE(tmpContent.txContent.v, tmpContent.txContent.vLength);
io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32(CX_CURVE_256K1,
tmpCtx.transactionContext.bip32Path,
@@ -40,7 +39,12 @@ unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_elemen
G_io_apdu_buffer[0] = 27;
} else {
// New API
// Note that this is wrong for a large v, but the client can always recover
// Note that this is wrong for a large v, but ledgerjs will recover.
// Taking only the 4 highest bytes to not introduce breaking changes. In the future,
// this should be updated.
uint32_t v = (uint32_t) u64_from_BE(tmpContent.txContent.v,
MIN(4, tmpContent.txContent.vLength));
G_io_apdu_buffer[0] = (v * 2) + 35;
}
if (info & CX_ECCINFO_PARITY_ODD) {

View File

@@ -222,9 +222,8 @@ void ux_approve_tx(bool fromPlugin) {
ux_approval_tx_flow[step++] = &ux_approval_nonce_step;
}
uint32_t chain_id = get_chain_id();
uint64_t chain_id = get_chain_id();
if (chainConfig->chainId == ETHEREUM_MAINNET_CHAINID && chain_id != chainConfig->chainId) {
// TODO: do we need the `&&` above?
ux_approval_tx_flow[step++] = &ux_approval_network_step;
}

View File

@@ -13,16 +13,6 @@ void stark_sign_display_master_account() {
dataContext.starkContext.transferDestination);
}
void stark_sign_display_condition_address() {
strings.tmp.tmp[0] = '0';
strings.tmp.tmp[1] = 'x';
getEthAddressStringFromBinary(dataContext.starkContext.conditionAddress,
strings.tmp.tmp + 2,
&global_sha3,
chainConfig);
strings.tmp.tmp[42] = '\0';
}
void stark_sign_display_condition_fact() {
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.fact);
}
@@ -189,7 +179,11 @@ UX_STEP_NOCB_INIT(
UX_STEP_NOCB_INIT(
ux_stark_conditional_transfer_8_step,
bnnn_paging,
stark_sign_display_condition_address(),
getEthDisplayableAddress(dataContext.starkContext.conditionAddress,
strings.tmp.tmp,
sizeof(strings.tmp.tmp),
&global_sha3,
chainConfig->chainId),
{
.title = "Cond. Address",
.text = strings.tmp.tmp

View File

@@ -212,12 +212,11 @@ void erc20_plugin_call(int message, void *parameters) {
strlcpy(msg->msg, context->contract_name, msg->msgLength);
} else {
strlcpy(msg->title, "Address", msg->titleLength);
msg->msg[0] = '0';
msg->msg[1] = 'x';
getEthAddressStringFromBinary(context->destinationAddress,
msg->msg + 2,
msg->pluginSharedRW->sha3,
chainConfig);
getEthDisplayableAddress(context->destinationAddress,
msg->msg,
msg->msgLength,
msg->pluginSharedRW->sha3,
chainConfig->chainId);
}
msg->result = ETH_PLUGIN_RESULT_OK;

View File

@@ -5,9 +5,6 @@
#include "ethUtils.h"
#include "utils.h"
void starkware_print_stark_key(uint8_t *starkKey, char *destination);
void starkware_print_eth_address(uint8_t *address, char *destination);
typedef struct erc721_parameters_t {
uint8_t selectorIndex;
uint8_t address[ADDRESS_LENGTH];
@@ -119,19 +116,27 @@ void erc721_plugin_call(int message, void *parameters) {
switch (msg->screenIndex) {
case 0:
strlcpy(msg->title, "Contract Name", msg->titleLength);
starkware_print_eth_address(tmpContent.txContent.destination, msg->msg);
getEthDisplayableAddress(tmpContent.txContent.destination,
msg->msg,
msg->msgLength,
&global_sha3,
chainConfig->chainId);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 1:
strlcpy(msg->title, "NFT Contract", msg->titleLength);
starkware_print_eth_address(context->address, msg->msg);
getEthDisplayableAddress(context->address,
msg->msg,
msg->msgLength,
&global_sha3,
chainConfig->chainId);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 2:
strlcpy(msg->title, "TokenID", msg->titleLength);
starkware_print_stark_key(context->tokenId, msg->msg);
snprintf(msg->msg, 70, "0x%.*H", 32, context->tokenId);
msg->result = ETH_PLUGIN_RESULT_OK;
break;

View File

@@ -32,19 +32,6 @@ typedef struct eth2_deposit_parameters_t {
char deposit_address[ETH2_DEPOSIT_PUBKEY_LENGTH];
} eth2_deposit_parameters_t;
// Fills the `out` buffer with the lowercase string representation of the pubkey passed in as binary
// format by `in`. Does not check the size, so expects `out` to be big enough to hold the string
// representation. Returns the length of string (counting the null terminating character).
static int getEthDisplayableAddress(char *out, uint8_t *in, cx_sha3_t *sha3) {
out[0] = '0';
out[1] = 'x';
getEthAddressStringFromBinary(in, out + 2, sha3, chainConfig);
uint8_t destinationLen = strlen(out) + 1; // Adding one to account for \0.
return destinationLen;
}
void eth2_plugin_call(int message, void *parameters) {
switch (message) {
case ETH_PLUGIN_INIT_CONTRACT: {
@@ -130,9 +117,11 @@ void eth2_plugin_call(int message, void *parameters) {
// Use a temporary buffer to store the string representation.
char tmp[ETH2_DEPOSIT_PUBKEY_LENGTH];
getEthDisplayableAddress(tmp,
(uint8_t *) context->deposit_address,
msg->pluginSharedRW->sha3);
getEthDisplayableAddress((uint8_t *) context->deposit_address,
tmp,
sizeof(tmp),
msg->pluginSharedRW->sha3,
chainConfig->chainId);
// Copy back the string to the global variable.
strlcpy(context->deposit_address, tmp, ETH2_DEPOSIT_PUBKEY_LENGTH);

View File

@@ -279,18 +279,6 @@ void starkware_print_stark_key(uint8_t *starkKey, char *destination) {
snprintf(destination, 70, "0x%.*H", 32, starkKey);
}
// TODO : rewrite as independant code
void starkware_print_eth_address(uint8_t *address, char *destination, size_t destinationLength) {
if (destinationLength < 43) {
strlcpy(destination, "ERROR", destinationLength);
return;
}
destination[0] = '0';
destination[1] = 'x';
getEthAddressStringFromBinary(address, destination + 2, &global_sha3, chainConfig);
destination[42] = '\0';
}
// TODO : rewrite as independant code
void starkware_print_amount(uint8_t *amountData,
char *destination,
@@ -348,7 +336,11 @@ void starkware_print_asset_contract(char *destination, size_t destinationLength)
if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) {
tokenDefinition_t *token =
&tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex];
starkware_print_eth_address(token->address, destination, destinationLength);
getEthDisplayableAddress(token->address,
destination,
destinationLength,
&global_sha3,
chainConfig->chainId);
} else {
strlcpy(destination, "UNKNOWN", destinationLength);
}
@@ -372,7 +364,7 @@ void starkware_get_source_address(char *destination) {
io_seproxyhal_io_heartbeat();
destination[0] = '0';
destination[1] = 'x';
getEthAddressStringFromKey(&publicKey, destination + 2, &global_sha3, chainConfig);
getEthAddressStringFromKey(&publicKey, destination + 2, &global_sha3, chainConfig->chainId);
destination[42] = '\0';
}
@@ -708,9 +700,11 @@ void starkware_plugin_call(int message, void *parameters) {
if (is_deversify_contract(tmpContent.txContent.destination)) {
strlcpy(msg->msg, "DeversiFi", msg->msgLength);
} else {
starkware_print_eth_address(tmpContent.txContent.destination,
msg->msg,
msg->msgLength);
getEthDisplayableAddress(tmpContent.txContent.destination,
msg->msg,
msg->msgLength,
&global_sha3,
chainConfig->chainId);
}
msg->result = ETH_PLUGIN_RESULT_OK;
break;
@@ -720,7 +714,11 @@ void starkware_plugin_call(int message, void *parameters) {
case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN:
case STARKWARE_REGISTER_AND_DEPOSIT_ETH:
strlcpy(msg->title, "From ETH Address", msg->titleLength);
starkware_print_eth_address(context->amount, msg->msg, msg->msgLength);
getEthDisplayableAddress(context->amount,
msg->msg,
msg->msgLength,
&global_sha3,
chainConfig->chainId);
break;
case STARKWARE_ESCAPE:
strlcpy(msg->title, "Amount", msg->titleLength);
@@ -784,7 +782,11 @@ void starkware_plugin_call(int message, void *parameters) {
case STARKWARE_WITHDRAW_TO:
case STARKWARE_WITHDRAW_NFT_TO:
strlcpy(msg->title, "To ETH Address", msg->titleLength);
starkware_print_eth_address(context->amount, msg->msg, msg->msgLength);
getEthDisplayableAddress(context->amount,
msg->msg,
msg->msgLength,
&global_sha3,
chainConfig->chainId);
break;
case STARKWARE_WITHDRAW_AND_MINT:
strlcpy(msg->title, "Asset Contract", msg->titleLength);

34
tests/build_local_test_elfs.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
# FILL THESE WITH YOUR OWN SDKs PATHS
NANOS_SDK=$TWO
NANOX_SDK=$X
# list of apps required by tests that we want to build here
appnames=("ethereum" "ethereum_classic")
# create elfs folder if it doesn't exist
mkdir -p elfs
# move to repo's root to build apps
cd ..
echo "*Building elfs for Nano S..."
for app in "${appnames[@]}"
do
echo "**Building $app for Nano S..."
make clean BOLOS_SDK=$NANOS_SDK
make -j DEBUG=1 ALLOW_DATA=1 BOLOS_SDK=$NANOS_SDK CHAIN=$app
cp bin/app.elf "tests/elfs/${app}_nanos.elf"
done
echo "*Building elfs for Nano X..."
for app in "${appnames[@]}"
do
echo "**Building $app for Nano X..."
make clean BOLOS_SDK=$NANOX_SDK
make -j DEBUG=1 ALLOW_DATA=1 BOLOS_SDK=$NANOX_SDK CHAIN=$app
cp bin/app.elf "tests/elfs/${app}_nanox.elf"
done
echo "done"

View File

@@ -1,4 +1,5 @@
import Zemu from "@zondax/zemu";
import fsExtra from "fs-extra";
const catchExit = async () => {
process.on("SIGINT", () => {
@@ -12,4 +13,5 @@ module.exports = async () => {
await catchExit();
await Zemu.checkAndPullImage();
await Zemu.stopAllEmuContainers();
fsExtra.emptyDirSync("snapshots/tmp")
};

View File

@@ -30,4 +30,10 @@ module.exports = {
"**/?(*.)+(spec|test).[tj]s?(x)",
"**/?(*.)+(ispec|test).[tj]s?(x)",
],
// Path of the file where tests can be """decorated"""
setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
// Stop immediatly when a test fail
bail: true,
};

View File

@@ -12,14 +12,15 @@
"license": "ISC",
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@ledgerhq/hw-app-eth": "^5.52.1",
"@ledgerhq/hw-app-eth": "^6.5.0",
"@ledgerhq/hw-transport-http": "^4.74.2",
"@ledgerhq/logs": "^5.50.0",
"@zondax/zemu": "0.13.0",
"@zondax/zemu": "0.16.5",
"bignumber.js": "^9.0.0",
"bip32-path": "^0.4.2",
"core-js": "^3.7.0",
"ethereum-tx-decoder": "^3.0.0",
"fs-extra": "^10.0.0",
"google-protobuf": "^3.11.0",
"jest-serial-runner": "^1.1.0",
"js-sha256": "^0.9.0",

19
tests/setupTests.js Normal file
View File

@@ -0,0 +1,19 @@
import expect from 'expect'
expect.extend({
toMatchSnapshot(received, original) {
if(received.data.equals(original.data)){
return {
message: () => `snapshots are equal`,
pass: true
}
} else {
console.log("snapshots are not equal")
return {
message: () => `snapshots are not equal`,
pass: false
}
}
},
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 612 B

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 730 B

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 530 B

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 745 B

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 B

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 659 B

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 860 B

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 585 B

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 884 B

After

Width:  |  Height:  |  Size: 891 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 692 B

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 555 B

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 869 B

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 636 B

View File

@@ -1 +0,0 @@
*.png

View File

@@ -1 +0,0 @@
*.png

View File

@@ -6,22 +6,19 @@ import Zemu from "@zondax/zemu";
import { TransportStatusError } from "@ledgerhq/errors";
import { expect } from "../jest";
const {NANOS_ELF_PATH, NANOX_ELF_PATH, sim_options_nanos, sim_options_nanox, TIMEOUT} = require("generic.js");
const {NANOS_ELF_PATH, NANOX_ELF_PATH, sim_options_nanos, sim_options_nanox, TIMEOUT, getTmpPath} = require("generic.js");
const ORIGINAL_SNAPSHOT_PATH_PREFIX = "snapshots/approve/";
const SNAPSHOT_PATH_PREFIX = "snapshots/tmp/";
const ORIGINAL_SNAPSHOT_PATH_NANOS = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanos/";
const ORIGINAL_SNAPSHOT_PATH_NANOX = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanox/";
const SNAPSHOT_PATH_NANOS = SNAPSHOT_PATH_PREFIX + "nanos/";
const SNAPSHOT_PATH_NANOX = SNAPSHOT_PATH_PREFIX + "nanox/";
test("Approve DAI tokens nanos", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOS_ELF_PATH);
let tmpPath = getTmpPath(expect.getState().currentTestName);
try {
await sim.start(sim_options_nanos);
@@ -40,59 +37,59 @@ test("Approve DAI tokens nanos", async () => {
// Review tx
filename = "review.png";
await sim.snapshot(SNAPSHOT_PATH_NANOS + filename);
const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
await sim.snapshot(tmpPath + filename);
const review = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(review).toEqual(expected_review);
expect(review).toMatchSnapshot(expected_review);
// Type
filename = "type.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const type = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
await sim.clickRight(tmpPath + filename);
const type = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_type = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(type).toEqual(expected_type);
expect(type).toMatchSnapshot(expected_type);
// Amount
filename = "amount.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const amount = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
await sim.clickRight(tmpPath + filename);
const amount = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount).toEqual(expected_amount);
expect(amount).toMatchSnapshot(expected_amount);
// Address 1/3
filename = "address_1.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const address_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
await sim.clickRight(tmpPath + filename);
const address_1 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_1).toEqual(expected_address_1);
expect(address_1).toMatchSnapshot(expected_address_1);
// Address 2/3
filename = "address_2.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const address_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
await sim.clickRight(tmpPath + filename);
const address_2 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_2).toEqual(expected_address_2);
expect(address_2).toMatchSnapshot(expected_address_2);
// Address 3/3
filename = "address_3.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const address_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
await sim.clickRight(tmpPath + filename);
const address_3 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_3).toEqual(expected_address_3);
expect(address_3).toMatchSnapshot(expected_address_3);
// Max Fees
filename = "fees.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
await sim.clickRight(tmpPath + filename);
const fees = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(fees).toEqual(expected_fees);
expect(fees).toMatchSnapshot(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
await sim.clickRight(tmpPath + filename);
const accept = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(accept).toEqual(expected_accept);
expect(accept).toMatchSnapshot(expected_accept);
await sim.clickBoth();
@@ -108,6 +105,8 @@ test("Approve DAI token nanox", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOX_ELF_PATH);
let tmpPath = getTmpPath(expect.getState().currentTestName);
try {
await sim.start(sim_options_nanox);
@@ -125,45 +124,45 @@ test("Approve DAI token nanox", async () => {
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
// Review tx
filename = "review.png";
await sim.snapshot(SNAPSHOT_PATH_NANOX + filename);
const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
await sim.snapshot(tmpPath + filename);
const review = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(review).toEqual(expected_review);
expect(review).toMatchSnapshot(expected_review);
// Type
filename = "type.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const type = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
await sim.clickRight(tmpPath + filename);
const type = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_type = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(type).toEqual(expected_type);
expect(type).toMatchSnapshot(expected_type);
// Amount
filename = "amount.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const amount = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
await sim.clickRight(tmpPath + filename);
const amount = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(amount).toEqual(expected_amount);
expect(amount).toMatchSnapshot(expected_amount);
// Address
filename = "address.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const address = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
await sim.clickRight(tmpPath + filename);
const address = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(address).toEqual(expected_address);
expect(address).toMatchSnapshot(expected_address);
// Max Fees
filename = "fees.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
await sim.clickRight(tmpPath + filename);
const fees = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(fees).toEqual(expected_fees);
expect(fees).toMatchSnapshot(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
await sim.clickRight(tmpPath + filename);
const accept = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(accept).toEqual(expected_accept);
expect(accept).toMatchSnapshot(expected_accept);
await sim.clickBoth();

370
tests/src/chainid.test.js Normal file
View File

@@ -0,0 +1,370 @@
import "core-js/stable";
import "regenerator-runtime/runtime";
import Eth from "@ledgerhq/hw-app-eth";
import { byContractAddress } from "@ledgerhq/hw-app-eth/erc20";
import Zemu from "@zondax/zemu";
import { TransportStatusError } from "@ledgerhq/errors";
import { expect } from "../jest";
const {NANOS_ELF_PATH, NANOX_ELF_PATH, sim_options_nanos, sim_options_nanox, TIMEOUT, getTmpPath} = require("generic.js");
const ORIGINAL_SNAPSHOT_PATH_PREFIX = "snapshots/chainid/";
const ORIGINAL_SNAPSHOT_PATH_NANOS = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanos/";
const ORIGINAL_SNAPSHOT_PATH_NANOX = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanox/";
test("Transfer on network 112233445566 on Ethereum nanos", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOS_ELF_PATH);
let tmpPath = getTmpPath(expect.getState().currentTestName);
try {
await sim.start(sim_options_nanos);
let transport = await sim.getTransport();
let eth = new Eth(transport);
// Send transaction
let tx = eth.signTransaction(
"44'/60'/0'/0/0",
"f044850306dc4200825208945a321744667052affa8386ed49e00ef223cbffc3876f9c9e7bf6181880851a21a278be8080"
)
let filename;
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
// Review tx
filename = "review.png";
await sim.snapshot(tmpPath + filename);
const review = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(review).toMatchSnapshot(expected_review);
// Amount 1/3
filename = "amount_1.png";
await sim.clickRight(tmpPath + filename);
const amount_1 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_1).toMatchSnapshot(expected_amount_1);
// Amount 2/3
filename = "amount_2.png";
await sim.clickRight(tmpPath + filename);
const amount_2 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_2).toMatchSnapshot(expected_amount_2);
// Amount 3/3
filename = "amount_3.png";
await sim.clickRight(tmpPath + filename);
const amount_3 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_3).toMatchSnapshot(expected_amount_3);
// Address 1/3
filename = "address_1.png";
await sim.clickRight(tmpPath + filename);
const address_1 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_1).toMatchSnapshot(expected_address_1);
// Address 2/3
filename = "address_2.png";
await sim.clickRight(tmpPath + filename);
const address_2 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_2).toMatchSnapshot(expected_address_2);
// Address 3/3
filename = "address_3.png";
await sim.clickRight(tmpPath + filename);
const address_3 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_3).toMatchSnapshot(expected_address_3);
// Network
filename = "network.png";
await sim.clickRight(tmpPath + filename);
const network = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(network).toMatchSnapshot(expected_network);
// Max Fees
filename = "fees.png";
await sim.clickRight(tmpPath + filename);
const fees = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(fees).toMatchSnapshot(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(tmpPath + filename);
const accept = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(accept).toMatchSnapshot(expected_accept);
await sim.clickBoth();
await expect(tx).resolves.toEqual(
{
"r": "31fca443b3cad62f3ce18e287f3cf4892ac2669379cc21b5cf198561f0511d1e",
"s": "3cf21485cd8b86e1acddbcc641e16a3efad18aaeb5ae96a650f1a8b291078494",
"v": "344344f1a0",
}
);
} finally {
await sim.close();
}
});
test("Transfer on palm network on Ethereum nanos", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOS_ELF_PATH);
let tmpPath = getTmpPath(expect.getState().currentTestName);
try {
await sim.start(sim_options_nanos);
let transport = await sim.getTransport();
let eth = new Eth(transport);
// Send transaction
let tx = eth.signTransaction(
"44'/60'/0'/0/0",
"f044850306dc4200825208945a321744667052affa8386ed49e00ef223cbffc3876f9c9e7bf61818808502a15c308d8080"
);
let filename;
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
// Review tx
filename = "review.png";
await sim.snapshot(tmpPath + filename);
const review = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(review).toMatchSnapshot(expected_review);
// Amount 1/3
filename = "amount_1_palm.png";
await sim.clickRight(tmpPath + filename);
const amount_1 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_1).toMatchSnapshot(expected_amount_1);
// Amount 2/3
filename = "amount_2.png";
await sim.clickRight(tmpPath + filename);
const amount_2 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_2).toMatchSnapshot(expected_amount_2);
// Amount 3/3
filename = "amount_3.png";
await sim.clickRight(tmpPath + filename);
const amount_3 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_3).toMatchSnapshot(expected_amount_3);
// Address 1/3
filename = "address_1.png";
await sim.clickRight(tmpPath + filename);
const address_1 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_1).toMatchSnapshot(expected_address_1);
// Address 2/3
filename = "address_2.png";
await sim.clickRight(tmpPath + filename);
const address_2 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_2).toMatchSnapshot(expected_address_2);
// Address 3/3
filename = "address_3.png";
await sim.clickRight(tmpPath + filename);
const address_3 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_3).toMatchSnapshot(expected_address_3);
// Network
filename = "palm.png";
await sim.clickRight(tmpPath + filename);
const network = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(network).toMatchSnapshot(expected_network);
// Max Fees
filename = "fees_palm.png";
await sim.clickRight(tmpPath + filename);
const fees = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(fees).toMatchSnapshot(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(tmpPath + filename);
const accept = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(accept).toMatchSnapshot(expected_accept);
await sim.clickBoth();
await expect(tx).resolves.toEqual(
{
"r": "f9b5d903c47c34027156e869bda5aa002233d6cca583ad53d125612fc0795f3b",
"s": "00da038129414e5ae6f7c1529c6067e82484e3694c84c16d575e77162f631c27",
"v": "0542b8613d",
}
);
} finally {
await sim.close();
}
});
test("Transfer on network 112233445566 on Ethereum nanox", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOX_ELF_PATH);
let tmpPath = getTmpPath(expect.getState().currentTestName);
try {
await sim.start(sim_options_nanox);
let transport = await sim.getTransport();
let eth = new Eth(transport);
// Send transaction
let tx = eth.signTransaction(
"44'/60'/0'/0/0",
"f044850306dc4200825208945a321744667052affa8386ed49e00ef223cbffc3876f9c9e7bf6181880851a21a278be8080"
)
let filename;
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
// Review tx
filename = "review.png";
await sim.snapshot(tmpPath + filename);
const review = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(review).toMatchSnapshot(expected_review);
// Amount
filename = "amount.png";
await sim.clickRight(tmpPath + filename);
const amount = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(amount).toMatchSnapshot(expected_amount);
// Address
filename = "address.png";
await sim.clickRight(tmpPath + filename);
const address = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(address).toMatchSnapshot(expected_address);
// Network
filename = "network.png";
await sim.clickRight(tmpPath + filename);
const network = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(network).toMatchSnapshot(expected_network);
// Max Fees
filename = "fees.png";
await sim.clickRight(tmpPath + filename);
const fees = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(fees).toMatchSnapshot(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(tmpPath + filename);
const accept = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(accept).toMatchSnapshot(expected_accept);
await sim.clickBoth();
await expect(tx).resolves.toEqual(
{
"r": "31fca443b3cad62f3ce18e287f3cf4892ac2669379cc21b5cf198561f0511d1e",
"s": "3cf21485cd8b86e1acddbcc641e16a3efad18aaeb5ae96a650f1a8b291078494",
"v": "344344f1a0",
}
);
} finally {
await sim.close();
}
});
test("Transfer on palm network on Ethereum nanox", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOX_ELF_PATH);
let tmpPath = getTmpPath(expect.getState().currentTestName);
try {
await sim.start(sim_options_nanox);
let transport = await sim.getTransport();
let eth = new Eth(transport);
// Send transaction
let tx = eth.signTransaction(
"44'/60'/0'/0/0",
"f044850306dc4200825208945a321744667052affa8386ed49e00ef223cbffc3876f9c9e7bf61818808502a15c308d8080"
);
let filename;
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
// Review tx
filename = "review.png";
await sim.snapshot(tmpPath + filename);
const review = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(review).toMatchSnapshot(expected_review);
// Amount
filename = "amount_palm.png";
await sim.clickRight(tmpPath + filename);
const amount = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(amount).toMatchSnapshot(expected_amount);
// Address
filename = "address.png";
await sim.clickRight(tmpPath + filename);
const address = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(address).toMatchSnapshot(expected_address);
// Network
filename = "palm.png";
await sim.clickRight(tmpPath + filename);
const network = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(network).toMatchSnapshot(expected_network);
// Max Fees
filename = "fees_palm.png";
await sim.clickRight(tmpPath + filename);
const fees = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(fees).toMatchSnapshot(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(tmpPath + filename);
const accept = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(accept).toMatchSnapshot(expected_accept);
await sim.clickBoth();
await expect(tx).resolves.toEqual(
{
"r": "f9b5d903c47c34027156e869bda5aa002233d6cca583ad53d125612fc0795f3b",
"s": "00da038129414e5ae6f7c1529c6067e82484e3694c84c16d575e77162f631c27",
"v": "0542b8613d",
}
);
} finally {
await sim.close();
}
});

Some files were not shown because too many files have changed in this diff Show More