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 - name: Build/Install build js deps
run: | run: |
cd tests && yarn install cd tests && yarn install
- name: Create tmp folder for artifacts
run: |
mkdir tests/elfs
- name: Download app binaries - name: Download app binaries
uses: actions/download-artifact@v2 uses: actions/download-artifact@v2
with: with:
path: tests/elfs path: tests/elfs
- name: Gather elfs - name: Gather elfs
run: | run: |
cp `find . -name "*.elf"` ./tests/elfs cd tests/elfs
cp `find . -name "*.elf"` .
- name: Run zemu tests - name: Run zemu tests
run: | run: |
cd tests && yarn test cd tests && yarn test

3
.gitignore vendored
View File

@@ -14,6 +14,7 @@ obj/
tests/node_modules tests/node_modules
tests/lib tests/lib
tests/yarn-error.log tests/yarn-error.log
tests/elfs/*
tests/snapshots/tmp/*
.vscode .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/) The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/). 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 ## [1.9.2](https://github.com/ledgerhq/app-ethereum/compare/1.9.0...1.9.2) - 2021-8-11
### Added ### Added

View File

@@ -30,7 +30,7 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'"
APPVERSION_M=1 APPVERSION_M=1
APPVERSION_N=9 APPVERSION_N=9
APPVERSION_P=2 APPVERSION_P=3
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
APP_LOAD_FLAGS= --appFlags 0x240 --dep Ethereum:$(APPVERSION) 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'" APP_LOAD_PARAMS += --path "44'/554'" --path "44'/60'"
DEFINES += CHAINID_UPCASE=\"FLARE\" CHAINID_COINNAME=\"FLR\" CHAIN_KIND=CHAIN_KIND_FLARE CHAIN_ID=16 DEFINES += CHAINID_UPCASE=\"FLARE\" CHAINID_COINNAME=\"FLR\" CHAIN_KIND=CHAIN_KIND_FLARE CHAIN_ID=16
APPNAME = "Flare Coston" 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) else ifeq ($(CHAIN),bsc)
APP_LOAD_PARAMS += --path "44'/60'" APP_LOAD_PARAMS += --path "44'/60'"
DEFINES += CHAINID_UPCASE=\"BSC\" CHAINID_COINNAME=\"BNB\" CHAIN_KIND=CHAIN_KIND_BSC CHAIN_ID=56 DEFINES += CHAINID_UPCASE=\"BSC\" CHAINID_COINNAME=\"BNB\" CHAIN_KIND=CHAIN_KIND_BSC CHAIN_ID=56
APPNAME = "Binance Smart Chain" 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 else
ifeq ($(filter clean,$(MAKECMDGOALS)),) 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
endif endif
@@ -384,4 +384,4 @@ include $(BOLOS_SDK)/Makefile.rules
dep/%.d: %.c Makefile dep/%.d: %.c Makefile
listvariants: 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 ## Running tests
First [install yarn](https://classic.yarnpkg.com/en/docs/install/#debian-stable). 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: Then you can install the project by simply running:
``` ```
cd ..
make test make test
``` ```
This will run `make install_tests` and `make run_tests` 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* | *SW* | *Description*
| 6501 | TransactionType not supported | 6501 | TransactionType not supported
| 6502 | Output buffer too small for snprintf input | 6502 | Output buffer too small for chainId conversion
| 6503 | Plugin error | 6503 | Plugin error
| 6504 | Failed to convert from int256 | 6504 | Failed to convert from int256
| 6700 | Incorrect length | 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_WEBCHAIN,
CHAIN_KIND_THUNDERCORE, CHAIN_KIND_THUNDERCORE,
CHAIN_KIND_FLARE, CHAIN_KIND_FLARE,
CHAIN_KIND_THETA, CHAIN_KIND_BSC,
CHAIN_KIND_BSC CHAIN_KIND_SONGBIRD
} chain_kind_t; } chain_kind_t;
typedef struct chain_config_s { typedef struct chain_config_s {
char coinName[10]; // ticker char coinName[10]; // ticker
uint32_t chainId; uint64_t chainId;
chain_kind_t kind; chain_kind_t kind;
} chain_config_t; } 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: case ETH_PLUGIN_INIT_CONTRACT:
PRINTF("-- PLUGIN INIT CONTRACT --\n"); PRINTF("-- PLUGIN INIT CONTRACT --\n");
((ethPluginInitContract_t *) parameter)->interfaceVersion = ((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)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethPluginInitContract_t *) parameter)->pluginSharedRW = &pluginRW; ((ethPluginInitContract_t *) parameter)->pluginSharedRW = &pluginRW;
((ethPluginInitContract_t *) parameter)->pluginSharedRO = &pluginRO; ((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. // Interface version. To be updated everytime we introduce breaking changes to the plugin interface.
typedef enum { typedef enum {
ETH_PLUGIN_INTERFACE_VERSION_1 = 1, // Version 1 ETH_PLUGIN_INTERFACE_VERSION_1 = 1, // Version 1
ETH_PLUGIN_INTERFACE_VERSION_LATEST = 2,
} eth_plugin_interface_version_t; } eth_plugin_interface_version_t;
typedef enum { 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, getEthAddressStringFromKey(&locals_union2.publicKey,
locals_union1.address, locals_union1.address,
&local_sha3, &local_sha3,
chain_config); chain_config->chainId);
ZERO(locals_union2); ZERO(locals_union2);
uint8_t offset_0x = 0; uint8_t offset_0x = 0;

View File

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

View File

@@ -162,14 +162,14 @@ typedef enum {
#endif #endif
} contract_call_t; } contract_call_t;
#define NETWORK_NAME_MAX_SIZE 12 #define NETWORK_STRING_MAX_SIZE 16
typedef struct txStringProperties_t { typedef struct txStringProperties_t {
char fullAddress[43]; char fullAddress[43];
char fullAmount[50]; char fullAmount[50];
char maxFee[50]; char maxFee[50];
char nonce[8]; // 10M tx per account ought to be enough for everybody 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; } txStringProperties_t;
#define SHARED_CTX_FIELD_1_SIZE 100 #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}, 0x91, 0x9a, 0xbc, 0x23, 0x5c, 0xa4, 0xfd, 0x7f, 0x72, 0xc1},
"TGT ", "TGT ",
1}, 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, {{0x1c, 0xb3, 0x20, 0x9d, 0x45, 0xb2, 0xa6, 0x0b, 0x7f, 0xbc,
0xa1, 0xcc, 0xdb, 0xf8, 0x7f, 0x67, 0x42, 0x37, 0xa4, 0xaa}, 0xa1, 0xcc, 0xdb, 0xf8, 0x7f, 0x67, 0x42, 0x37, 0xa4, 0xaa},
"THR ", "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_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_BSC[NUM_TOKENS_BSC] = {};
const tokenDefinition_t const TOKENS_SONGBIRD[NUM_TOKENS_SONGBIRD] = {};
#endif #endif

View File

@@ -95,8 +95,8 @@ static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
#define NUM_TOKENS_WEBCHAIN 0 #define NUM_TOKENS_WEBCHAIN 0
#define NUM_TOKENS_THUNDERCORE 0 #define NUM_TOKENS_THUNDERCORE 0
#define NUM_TOKENS_FLARE 0 #define NUM_TOKENS_FLARE 0
#define NUM_TOKENS_THETA 0
#define NUM_TOKENS_BSC 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_AKROMA[NUM_TOKENS_AKROMA];
extern tokenDefinition_t const TOKENS_ELLAISM[NUM_TOKENS_ELLAISM]; 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_WEBCHAIN[NUM_TOKENS_WEBCHAIN];
extern tokenDefinition_t const TOKENS_THUNDERCORE[NUM_TOKENS_THUNDERCORE]; extern tokenDefinition_t const TOKENS_THUNDERCORE[NUM_TOKENS_THUNDERCORE];
extern tokenDefinition_t const TOKENS_FLARE[NUM_TOKENS_FLARE]; 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_BSC[NUM_TOKENS_BSC];
extern tokenDefinition_t const TOKENS_SONGBIRD[NUM_TOKENS_SONGBIRD];
#endif /* HAVE_TOKENS_LIST */ #endif /* HAVE_TOKENS_LIST */

View File

@@ -54,19 +54,17 @@ int local_strchr(char *string, char ch) {
return -1; return -1;
} }
uint32_t u32_from_BE(uint8_t *in, uint8_t size) { uint64_t u64_from_BE(uint8_t *in, uint8_t size) {
switch (size) { uint8_t i = 0;
case 0: uint64_t res = 0;
return 0;
case 1: while (i < size && i < sizeof(res)) {
return in[0]; res <<= 8;
case 2: res |= in[i];
return (in[0] << 8) | in[1]; i++;
case 3:
return (in[0] << 16) | (in[1] << 8) | in[2];
default:
return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
} }
return res;
} }
bool uint256_to_decimal(const uint8_t *value, size_t value_len, char *out, size_t out_len) { 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); 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); 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; txInt256_t chainID;
uint8_t destination[ADDRESS_LENGTH]; uint8_t destination[ADDRESS_LENGTH];
uint8_t destinationLength; uint8_t destinationLength;
uint8_t v[4]; uint8_t v[8];
uint8_t vLength; uint8_t vLength;
bool dataPresent; bool dataPresent;
} txContent_t; } 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, void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
char *out, char *out,
cx_sha3_t *sha3Context, cx_sha3_t *sha3Context,
chain_config_t *chain_config) { uint64_t chainId) {
uint8_t hashAddress[INT256_LENGTH]; uint8_t hashAddress[INT256_LENGTH];
cx_keccak_init(sha3Context, 256); cx_keccak_init(sha3Context, 256);
cx_hash((cx_hash_t *) sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress, 32); 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, void getEthAddressStringFromBinary(uint8_t *address,
char *out, char *out,
cx_sha3_t *sha3Context, cx_sha3_t *sha3Context,
chain_config_t *chain_config) { uint64_t chainId) {
// save some precious stack space // save some precious stack space
union locals_union { union locals_union {
uint8_t hashChecksum[INT256_LENGTH]; uint8_t hashChecksum[INT256_LENGTH];
@@ -146,18 +174,17 @@ void getEthAddressStringFromBinary(uint8_t *address,
uint8_t i; uint8_t i;
bool eip1191 = false; bool eip1191 = false;
uint32_t offset = 0; uint32_t offset = 0;
switch (chain_config->chainId) { switch (chainId) {
case 30: case 30:
case 31: case 31:
eip1191 = true; eip1191 = true;
break; break;
} }
if (eip1191) { if (eip1191) {
snprintf((char *) locals_union.tmp, u64_to_string(chainId, (char *) locals_union.tmp, sizeof(locals_union.tmp));
sizeof(locals_union.tmp), offset = strnlen((char *) locals_union.tmp, sizeof(locals_union.tmp));
"%d0x", strlcat((char *) locals_union.tmp + offset, "0x", sizeof(locals_union.tmp) - offset);
chain_config->chainId); offset = strnlen((char *) locals_union.tmp, sizeof(locals_union.tmp));
offset = strlen((char *) locals_union.tmp);
} }
for (i = 0; i < 20; i++) { for (i = 0; i < 20; i++) {
uint8_t digit = address[i]; uint8_t digit = address[i];
@@ -192,6 +219,24 @@ void getEthAddressStringFromBinary(uint8_t *address,
out[40] = '\0'; 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, bool adjustDecimals(char *src,
uint32_t srcLength, uint32_t srcLength,
char *target, 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, void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
char *out, char *out,
cx_sha3_t *sha3Context, 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, void getEthAddressStringFromBinary(uint8_t *address,
char *out, char *out,
cx_sha3_t *sha3Context, 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, bool adjustDecimals(char *src,
uint32_t srcLength, uint32_t srcLength,

View File

@@ -19,30 +19,33 @@ const network_info_t NETWORK_MAPPING[] = {
{.chain_id = 100, .name = "xDai", .ticker = "xDAI "}, {.chain_id = 100, .name = "xDai", .ticker = "xDAI "},
{.chain_id = 137, .name = "Polygon", .ticker = "MATIC "}, {.chain_id = 137, .name = "Polygon", .ticker = "MATIC "},
{.chain_id = 250, .name = "Fantom", .ticker = "FTM "}, {.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) { uint64_t get_chain_id(void) {
uint32_t chain_id = 0; uint64_t chain_id = 0;
switch (txContext.txType) { switch (txContext.txType) {
case LEGACY: 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; break;
case EIP2930: case EIP2930:
case EIP1559: case EIP1559:
chain_id = u32_from_BE(tmpContent.txContent.chainID.value, chain_id = u64_from_BE(tmpContent.txContent.chainID.value,
tmpContent.txContent.chainID.length); tmpContent.txContent.chainID.length);
break; break;
default: default:
PRINTF("Txtype `%d` not supported while generating chainID\n", txContext.txType); PRINTF("Txtype `%d` not supported while generating chainID\n", txContext.txType);
break; break;
} }
PRINTF("ChainID: %d\n", chain_id);
return chain_id; return chain_id;
} }
network_info_t *get_network(void) { 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++) { for (uint8_t i = 0; i < sizeof(NETWORK_MAPPING) / sizeof(*NETWORK_MAPPING); i++) {
if (NETWORK_MAPPING[i].chain_id == chain_id) { if (NETWORK_MAPPING[i].chain_id == chain_id) {
return (network_info_t *) PIC(&NETWORK_MAPPING[i]); return (network_info_t *) PIC(&NETWORK_MAPPING[i]);

View File

@@ -1,16 +1,15 @@
#include <stdint.h> #include <stdint.h>
#include "tokens.h" #include "tokens.h"
#include "shared_context.h"
#define NETWORK_STRING_MAX_SIZE 12
typedef struct network_info_s { typedef struct network_info_s {
const char name[NETWORK_STRING_MAX_SIZE]; const char name[NETWORK_STRING_MAX_SIZE];
const char ticker[MAX_TICKER_LEN]; const char ticker[MAX_TICKER_LEN];
uint32_t chain_id; uint64_t chain_id;
} network_info_t; } network_info_t;
// Returns the current chain id. Defaults to 0 if txType was not found. // 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. // Returns a pointer to the network struct, or NULL if there is none.
network_info_t *get_network(void); network_info_t *get_network(void);
// Returns a pointer to the network name, or NULL if there is none. // 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, getEthAddressStringFromKey(&tmpCtx.publicKeyContext.publicKey,
tmpCtx.publicKeyContext.address, tmpCtx.publicKeyContext.address,
&global_sha3, &global_sha3,
chainConfig); chainConfig->chainId);
#ifndef NO_CONSENT #ifndef NO_CONSENT
if (p1 == P1_NON_CONFIRM) if (p1 == P1_NON_CONFIRM)
#endif // NO_CONSENT #endif // NO_CONSENT

View File

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

View File

@@ -8,6 +8,7 @@
#endif #endif
#include "eth_plugin_handler.h" #include "eth_plugin_handler.h"
#include "network.h" #include "network.h"
#include "ethUtils.h"
#define ERR_SILENT_MODE_CHECK_FAILED 0x6001 #define ERR_SILENT_MODE_CHECK_FAILED 0x6001
@@ -261,16 +262,8 @@ void prepareNetworkDisplay() {
char *name = get_network_name(); char *name = get_network_name();
if (name == NULL) { if (name == NULL) {
// No network name found so simply copy the chain ID as the network name. // No network name found so simply copy the chain ID as the network name.
uint32_t chain_id = get_chain_id(); uint64_t chain_id = get_chain_id();
uint8_t res = snprintf(strings.common.network_name, u64_to_string(chain_id, strings.common.network_name, sizeof(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);
}
} else { } else {
// Network name found, simply copy it. // Network name found, simply copy it.
strlcpy(strings.common.network_name, name, sizeof(strings.common.network_name)); strlcpy(strings.common.network_name, name, sizeof(strings.common.network_name));
@@ -308,7 +301,7 @@ void finalizeParsing(bool direct) {
// Verify the chain // Verify the chain
if (chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) { if (chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) {
// TODO: Could we remove above check? // TODO: Could we remove above check?
uint32_t id = get_chain_id(); uint64_t id = get_chain_id();
if (chainConfig->chainId != id) { if (chainConfig->chainId != id) {
PRINTF("Invalid chainID %u expected %u\n", id, chainConfig->chainId); PRINTF("Invalid chainID %u expected %u\n", id, chainConfig->chainId);
@@ -422,12 +415,11 @@ void finalizeParsing(bool direct) {
// Prepare destination address to display // Prepare destination address to display
if (genericUI) { if (genericUI) {
if (tmpContent.txContent.destinationLength != 0) { if (tmpContent.txContent.destinationLength != 0) {
displayBuffer[0] = '0'; getEthDisplayableAddress(tmpContent.txContent.destination,
displayBuffer[1] = 'x'; displayBuffer,
getEthAddressStringFromBinary(tmpContent.txContent.destination, sizeof(displayBuffer),
displayBuffer + 2, &global_sha3,
&global_sha3, chainConfig->chainId);
chainConfig);
compareOrCopy(strings.common.fullAddress, compareOrCopy(strings.common.fullAddress,
sizeof(strings.common.fullAddress), sizeof(strings.common.fullAddress),
displayBuffer, displayBuffer,
@@ -459,9 +451,11 @@ void finalizeParsing(bool direct) {
// Compute maximum fee // Compute maximum fee
prepareFeeDisplay(); prepareFeeDisplay();
PRINTF("Fees displayed: %s\n", strings.common.maxFee);
// Prepare chainID field // Prepare chainID field
prepareNetworkDisplay(); prepareNetworkDisplay();
PRINTF("Network: %s\n", strings.common.network_name);
bool no_consent; 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]; uint8_t signature[100];
cx_ecfp_private_key_t privateKey; cx_ecfp_private_key_t privateKey;
uint32_t tx = 0; uint32_t tx = 0;
uint32_t v = u32_from_BE(tmpContent.txContent.v, tmpContent.txContent.vLength);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32(CX_CURVE_256K1, os_perso_derive_node_bip32(CX_CURVE_256K1,
tmpCtx.transactionContext.bip32Path, 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; G_io_apdu_buffer[0] = 27;
} else { } else {
// New API // 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; G_io_apdu_buffer[0] = (v * 2) + 35;
} }
if (info & CX_ECCINFO_PARITY_ODD) { 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; 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) { 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; ux_approval_tx_flow[step++] = &ux_approval_network_step;
} }

View File

@@ -13,16 +13,6 @@ void stark_sign_display_master_account() {
dataContext.starkContext.transferDestination); 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() { void stark_sign_display_condition_fact() {
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.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_STEP_NOCB_INIT(
ux_stark_conditional_transfer_8_step, ux_stark_conditional_transfer_8_step,
bnnn_paging, 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", .title = "Cond. Address",
.text = strings.tmp.tmp .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); strlcpy(msg->msg, context->contract_name, msg->msgLength);
} else { } else {
strlcpy(msg->title, "Address", msg->titleLength); strlcpy(msg->title, "Address", msg->titleLength);
msg->msg[0] = '0'; getEthDisplayableAddress(context->destinationAddress,
msg->msg[1] = 'x'; msg->msg,
getEthAddressStringFromBinary(context->destinationAddress, msg->msgLength,
msg->msg + 2, msg->pluginSharedRW->sha3,
msg->pluginSharedRW->sha3, chainConfig->chainId);
chainConfig);
} }
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;

View File

@@ -5,9 +5,6 @@
#include "ethUtils.h" #include "ethUtils.h"
#include "utils.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 { typedef struct erc721_parameters_t {
uint8_t selectorIndex; uint8_t selectorIndex;
uint8_t address[ADDRESS_LENGTH]; uint8_t address[ADDRESS_LENGTH];
@@ -119,19 +116,27 @@ void erc721_plugin_call(int message, void *parameters) {
switch (msg->screenIndex) { switch (msg->screenIndex) {
case 0: case 0:
strlcpy(msg->title, "Contract Name", msg->titleLength); 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; msg->result = ETH_PLUGIN_RESULT_OK;
break; break;
case 1: case 1:
strlcpy(msg->title, "NFT Contract", msg->titleLength); 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; msg->result = ETH_PLUGIN_RESULT_OK;
break; break;
case 2: case 2:
strlcpy(msg->title, "TokenID", msg->titleLength); 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; msg->result = ETH_PLUGIN_RESULT_OK;
break; break;

View File

@@ -32,19 +32,6 @@ typedef struct eth2_deposit_parameters_t {
char deposit_address[ETH2_DEPOSIT_PUBKEY_LENGTH]; char deposit_address[ETH2_DEPOSIT_PUBKEY_LENGTH];
} eth2_deposit_parameters_t; } 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) { void eth2_plugin_call(int message, void *parameters) {
switch (message) { switch (message) {
case ETH_PLUGIN_INIT_CONTRACT: { 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. // Use a temporary buffer to store the string representation.
char tmp[ETH2_DEPOSIT_PUBKEY_LENGTH]; char tmp[ETH2_DEPOSIT_PUBKEY_LENGTH];
getEthDisplayableAddress(tmp, getEthDisplayableAddress((uint8_t *) context->deposit_address,
(uint8_t *) context->deposit_address, tmp,
msg->pluginSharedRW->sha3); sizeof(tmp),
msg->pluginSharedRW->sha3,
chainConfig->chainId);
// Copy back the string to the global variable. // Copy back the string to the global variable.
strlcpy(context->deposit_address, tmp, ETH2_DEPOSIT_PUBKEY_LENGTH); 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); 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 // TODO : rewrite as independant code
void starkware_print_amount(uint8_t *amountData, void starkware_print_amount(uint8_t *amountData,
char *destination, char *destination,
@@ -348,7 +336,11 @@ void starkware_print_asset_contract(char *destination, size_t destinationLength)
if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) { if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) {
tokenDefinition_t *token = tokenDefinition_t *token =
&tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex]; &tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex];
starkware_print_eth_address(token->address, destination, destinationLength); getEthDisplayableAddress(token->address,
destination,
destinationLength,
&global_sha3,
chainConfig->chainId);
} else { } else {
strlcpy(destination, "UNKNOWN", destinationLength); strlcpy(destination, "UNKNOWN", destinationLength);
} }
@@ -372,7 +364,7 @@ void starkware_get_source_address(char *destination) {
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
destination[0] = '0'; destination[0] = '0';
destination[1] = 'x'; destination[1] = 'x';
getEthAddressStringFromKey(&publicKey, destination + 2, &global_sha3, chainConfig); getEthAddressStringFromKey(&publicKey, destination + 2, &global_sha3, chainConfig->chainId);
destination[42] = '\0'; destination[42] = '\0';
} }
@@ -708,9 +700,11 @@ void starkware_plugin_call(int message, void *parameters) {
if (is_deversify_contract(tmpContent.txContent.destination)) { if (is_deversify_contract(tmpContent.txContent.destination)) {
strlcpy(msg->msg, "DeversiFi", msg->msgLength); strlcpy(msg->msg, "DeversiFi", msg->msgLength);
} else { } else {
starkware_print_eth_address(tmpContent.txContent.destination, getEthDisplayableAddress(tmpContent.txContent.destination,
msg->msg, msg->msg,
msg->msgLength); msg->msgLength,
&global_sha3,
chainConfig->chainId);
} }
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;
break; break;
@@ -720,7 +714,11 @@ void starkware_plugin_call(int message, void *parameters) {
case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN: case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN:
case STARKWARE_REGISTER_AND_DEPOSIT_ETH: case STARKWARE_REGISTER_AND_DEPOSIT_ETH:
strlcpy(msg->title, "From ETH Address", msg->titleLength); 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; break;
case STARKWARE_ESCAPE: case STARKWARE_ESCAPE:
strlcpy(msg->title, "Amount", msg->titleLength); 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_TO:
case STARKWARE_WITHDRAW_NFT_TO: case STARKWARE_WITHDRAW_NFT_TO:
strlcpy(msg->title, "To ETH Address", msg->titleLength); 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; break;
case STARKWARE_WITHDRAW_AND_MINT: case STARKWARE_WITHDRAW_AND_MINT:
strlcpy(msg->title, "Asset Contract", msg->titleLength); 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 Zemu from "@zondax/zemu";
import fsExtra from "fs-extra";
const catchExit = async () => { const catchExit = async () => {
process.on("SIGINT", () => { process.on("SIGINT", () => {
@@ -12,4 +13,5 @@ module.exports = async () => {
await catchExit(); await catchExit();
await Zemu.checkAndPullImage(); await Zemu.checkAndPullImage();
await Zemu.stopAllEmuContainers(); await Zemu.stopAllEmuContainers();
fsExtra.emptyDirSync("snapshots/tmp")
}; };

View File

@@ -30,4 +30,10 @@ module.exports = {
"**/?(*.)+(spec|test).[tj]s?(x)", "**/?(*.)+(spec|test).[tj]s?(x)",
"**/?(*.)+(ispec|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", "license": "ISC",
"dependencies": { "dependencies": {
"@babel/plugin-proposal-class-properties": "^7.12.1", "@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/hw-transport-http": "^4.74.2",
"@ledgerhq/logs": "^5.50.0", "@ledgerhq/logs": "^5.50.0",
"@zondax/zemu": "0.13.0", "@zondax/zemu": "0.16.5",
"bignumber.js": "^9.0.0", "bignumber.js": "^9.0.0",
"bip32-path": "^0.4.2", "bip32-path": "^0.4.2",
"core-js": "^3.7.0", "core-js": "^3.7.0",
"ethereum-tx-decoder": "^3.0.0", "ethereum-tx-decoder": "^3.0.0",
"fs-extra": "^10.0.0",
"google-protobuf": "^3.11.0", "google-protobuf": "^3.11.0",
"jest-serial-runner": "^1.1.0", "jest-serial-runner": "^1.1.0",
"js-sha256": "^0.9.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 { TransportStatusError } from "@ledgerhq/errors";
import { expect } from "../jest"; 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 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_NANOS = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanos/";
const ORIGINAL_SNAPSHOT_PATH_NANOX = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanox/"; 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 () => { test("Approve DAI tokens nanos", async () => {
jest.setTimeout(TIMEOUT); jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOS_ELF_PATH); const sim = new Zemu(NANOS_ELF_PATH);
let tmpPath = getTmpPath(expect.getState().currentTestName);
try { try {
await sim.start(sim_options_nanos); await sim.start(sim_options_nanos);
@@ -40,59 +37,59 @@ test("Approve DAI tokens nanos", async () => {
// Review tx // Review tx
filename = "review.png"; filename = "review.png";
await sim.snapshot(SNAPSHOT_PATH_NANOS + filename); await sim.snapshot(tmpPath + filename);
const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const review = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(review).toEqual(expected_review); expect(review).toMatchSnapshot(expected_review);
// Type // Type
filename = "type.png"; filename = "type.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); await sim.clickRight(tmpPath + filename);
const type = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const type = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_type = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); const expected_type = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(type).toEqual(expected_type); expect(type).toMatchSnapshot(expected_type);
// Amount // Amount
filename = "amount.png"; filename = "amount.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); await sim.clickRight(tmpPath + filename);
const amount = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const amount = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount).toEqual(expected_amount); expect(amount).toMatchSnapshot(expected_amount);
// Address 1/3 // Address 1/3
filename = "address_1.png"; filename = "address_1.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); await sim.clickRight(tmpPath + filename);
const address_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const address_1 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + 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 // Address 2/3
filename = "address_2.png"; filename = "address_2.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); await sim.clickRight(tmpPath + filename);
const address_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const address_2 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + 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 // Address 3/3
filename = "address_3.png"; filename = "address_3.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); await sim.clickRight(tmpPath + filename);
const address_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const address_3 = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + 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 // Max Fees
filename = "fees.png"; filename = "fees.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); await sim.clickRight(tmpPath + filename);
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const fees = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(fees).toEqual(expected_fees); expect(fees).toMatchSnapshot(expected_fees);
// Accept // Accept
filename = "accept.png"; filename = "accept.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); await sim.clickRight(tmpPath + filename);
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const accept = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename); const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(accept).toEqual(expected_accept); expect(accept).toMatchSnapshot(expected_accept);
await sim.clickBoth(); await sim.clickBoth();
@@ -108,6 +105,8 @@ test("Approve DAI token nanox", async () => {
jest.setTimeout(TIMEOUT); jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOX_ELF_PATH); const sim = new Zemu(NANOX_ELF_PATH);
let tmpPath = getTmpPath(expect.getState().currentTestName);
try { try {
await sim.start(sim_options_nanox); await sim.start(sim_options_nanox);
@@ -125,45 +124,45 @@ test("Approve DAI token nanox", async () => {
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot()); await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
// Review tx // Review tx
filename = "review.png"; filename = "review.png";
await sim.snapshot(SNAPSHOT_PATH_NANOX + filename); await sim.snapshot(tmpPath + filename);
const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); const review = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(review).toEqual(expected_review); expect(review).toMatchSnapshot(expected_review);
// Type // Type
filename = "type.png"; filename = "type.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); await sim.clickRight(tmpPath + filename);
const type = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); const type = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_type = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); const expected_type = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(type).toEqual(expected_type); expect(type).toMatchSnapshot(expected_type);
// Amount // Amount
filename = "amount.png"; filename = "amount.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); await sim.clickRight(tmpPath + filename);
const amount = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); const amount = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(amount).toEqual(expected_amount); expect(amount).toMatchSnapshot(expected_amount);
// Address // Address
filename = "address.png"; filename = "address.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); await sim.clickRight(tmpPath + filename);
const address = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); const address = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(address).toEqual(expected_address); expect(address).toMatchSnapshot(expected_address);
// Max Fees // Max Fees
filename = "fees.png"; filename = "fees.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); await sim.clickRight(tmpPath + filename);
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); const fees = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(fees).toEqual(expected_fees); expect(fees).toMatchSnapshot(expected_fees);
// Accept // Accept
filename = "accept.png"; filename = "accept.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); await sim.clickRight(tmpPath + filename);
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); const accept = Zemu.LoadPng2RGB(tmpPath + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename); const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(accept).toEqual(expected_accept); expect(accept).toMatchSnapshot(expected_accept);
await sim.clickBoth(); 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