Add network display (#152)

* Add network name display instead of chainID

* Add display of correct ticker along with network

* Add FTM

* Clang-format

* Add comment in python script

* Rename SIZE_MAX to MAX_SIZE

* Change %u to %d in printf

* Remove needless PIC

* Update comment about get_chain_id()

* Update example script to follow EIP155

* Remove unused PIC calls

* Add whitespace between ticker and amount when using EIP155

* Remove decimal config per network, set back 18 everywhere

* Adapt u32_from_BE to swith cases

* Remove chainid from signTx.py

* Switch to switch in stead of if in get_chain_id

* Revert "Remove chainid from signTx.py"

This reverts commit 454e09f280ec3e3ec1c7d7cc0027247ef4390088.

* Change Ethereum chainid to 1

* Rename chainid_step to network_step

* Adapt finalizeParsing to new chainid for Ethereum

* Update snapshots

* clang-format

* Fix network display logic for clones

* Fix tests

* Add clone tests

Co-authored-by: TamtamHero <10632523+TamtamHero@users.noreply.github.com>
This commit is contained in:
pscott
2021-07-02 18:46:23 +02:00
committed by GitHub
parent ea87a0a646
commit a2d9a8068a
42 changed files with 559 additions and 80 deletions

View File

@@ -25,23 +25,25 @@ jobs:
- name: Build an altcoin
run: |
make DEBUG=1 ALLOW_DATA=1 CHAIN=ethereum_classic
mv bin/app.elf ethereum_classic_nanos.elf
- name: Upload altcoin binary
uses: actions/upload-artifact@v2
with:
name: ethereum_classic_nanos
path: bin
path: ./ethereum_classic_nanos.elf
- name: Build Ethereum
run: |
make clean
make DEBUG=1 ALLOW_DATA=1
mv bin/app.elf ethereum_nanos.elf
- name: Upload app binary
uses: actions/upload-artifact@v2
with:
name: ethereum_nanos
path: bin
path: ./ethereum_nanos.elf
job_build_debug_nano_x:
name: Build debug Nano X
@@ -60,23 +62,25 @@ jobs:
run: |
make clean
make BOLOS_SDK=$NANOX_SDK DEBUG=1 ALLOW_DATA=1 CHAIN=ethereum_classic
mv bin/app.elf ethereum_classic_nanox.elf
- name: Upload altcoin binary
uses: actions/upload-artifact@v2
with:
name: ethereum_classic_nanox
path: bin
path: ./ethereum_classic_nanox.elf
- name: Build Ethereum Nano X
run: |
make clean
make BOLOS_SDK=$NANOX_SDK DEBUG=1 ALLOW_DATA=1
mv bin/app.elf ethereum_nanox.elf
- name: Upload app binary
uses: actions/upload-artifact@v2
with:
name: ethereum_nanox
path: bin
path: ./ethereum_nanox.elf
jobs-e2e-tests:
needs: [job_build_debug_nano_s, job_build_debug_nano_x]
@@ -104,6 +108,9 @@ jobs:
uses: actions/download-artifact@v2
with:
path: tests/elfs
- name: Gather elfs
run: |
cp `find . -name "*.elf"` ./tests/elfs
- name: Run zemu tests
run: |
cd tests && yarn test

View File

@@ -41,7 +41,7 @@ endif
ifeq ($(CHAIN),ethereum)
# Lock the application on its standard path for 1.5. Please complain if non compliant
APP_LOAD_PARAMS += --path "44'/60'"
DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAIN_KIND=CHAIN_KIND_ETHEREUM CHAIN_ID=0
DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAIN_KIND=CHAIN_KIND_ETHEREUM CHAIN_ID=1
# Starkware integration
APP_LOAD_PARAMS += --path "2645'/579218131'"
DEFINES += HAVE_STARKWARE

View File

@@ -59,6 +59,9 @@ class UnsignedTransaction(Serializable):
('to', address),
('value', big_endian_int),
('data', binary),
('chainid', big_endian_int),
('dummy1', big_endian_int),
('dummy2', big_endian_int),
]
def unsigned_tx_from_tx(tx):

View File

@@ -59,6 +59,7 @@ parser.add_argument('--amount', help="Amount to send in ether", required=True)
parser.add_argument('--to', help="Destination address", type=str, required=True)
parser.add_argument('--path', help="BIP 32 path to sign with")
parser.add_argument('--data', help="Data to add, hex encoded")
parser.add_argument('--chainid', help="Chain ID (1 for Ethereum mainnet, 137 for Polygon, etc)", type=int)
parser.add_argument('--descriptor', help="Optional descriptor")
args = parser.parse_args()
@@ -71,6 +72,10 @@ if args.data == None:
else:
args.data = decode_hex(args.data[2:])
# default to Ethereum mainnet
if args.chainid == None:
args.chainid = 1
amount = Decimal(args.amount) * 10**18
tx = UnsignedTransaction(
@@ -80,10 +85,16 @@ tx = UnsignedTransaction(
to=decode_hex(args.to[2:]),
value=int(amount),
data=args.data,
chainid=args.chainid,
dummy1=0,
dummy2=0
)
encodedTx = encode(tx, UnsignedTransaction)
# To test an EIP-2930 transaction, uncomment this line
#encodedTx = bytearray.fromhex("01f8e60380018402625a0094cccccccccccccccccccccccccccccccccccccccc830186a0a4693c61390000000000000000000000000000000000000000000000000000000000000002f85bf859940000000000000000000000000000000000000102f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000060a780a09b8adcd2a4abd34b42d56fcd90b949f74ca9696dfe2b427bc39aa280bbf1924ca029af4a471bb2953b4e7933ea95880648552a9345424a1ac760189655ceb1832a")
dongle = getDongle(True)
if args.descriptor != None:

View File

@@ -162,13 +162,14 @@ typedef enum {
#endif
} contract_call_t;
#define NETWORK_NAME_MAX_SIZE 12
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 chainID[8]; // 10M different chainID ought to be enough for people to find a unique
// chainID for their token / chain.
char nonce[8]; // 10M tx per account ought to be enough for everybody
char network_name[NETWORK_NAME_MAX_SIZE];
} txStringProperties_t;
#define SHARED_CTX_FIELD_1_SIZE 100

View File

@@ -60,7 +60,7 @@ void stark_get_amount_string(uint8_t *contractAddress,
char *target100) {
uint256_t amountPre, quantum, amount;
uint8_t decimals;
char *ticker = (char *) PIC(chainConfig->coinName);
char *ticker = chainConfig->coinName;
PRINTF("stark_get_amount_string %.*H\n", 20, contractAddress);

View File

@@ -57,20 +57,24 @@ int local_strchr(char *string, char ch) {
// Almost like U4BE except that it takes `size` as a parameter.
// The `strict` parameter defines whether we should throw in case of a length > 4.
uint32_t u32_from_BE(uint8_t *in, uint8_t size, bool strict) {
uint32_t res = 0;
if (size == 1) {
res = in[0];
} else if (size == 2) {
res = (in[0] << 8) | in[1];
} else if (size == 3) {
res = (in[0] << 16) | (in[1] << 8) | in[2];
} else if (size == 4) {
res = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
} else if (strict && size != 0) {
PRINTF("Unexpected format\n");
THROW(EXCEPTION);
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];
case 4:
return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
default:
if (strict) {
PRINTF("Unexpected format\n");
THROW(EXCEPTION);
}
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) {

70
src_common/network.c Normal file
View File

@@ -0,0 +1,70 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include "network.h"
#include "os.h"
#include "shared_context.h"
#include "utils.h"
// Mappping of chain ids to networks.
const network_info_t NETWORK_MAPPING[] = {
{.chain_id = 1, .name = "Ethereum", .ticker = "ETH "},
{.chain_id = 3, .name = "Ropsten", .ticker = "ETH "},
{.chain_id = 4, .name = "Rinkeby", .ticker = "ETH "},
{.chain_id = 5, .name = "Goerli", .ticker = "ETH "},
{.chain_id = 10, .name = "Optimism", .ticker = "ETH "},
{.chain_id = 42, .name = "Kovan", .ticker = "ETH "},
{.chain_id = 56, .name = "BSC", .ticker = "BNB "},
{.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 "}};
uint32_t get_chain_id(void) {
uint32_t chain_id = 0;
switch (txContext.txType) {
case LEGACY:
chain_id = u32_from_BE(txContext.content->v, txContext.content->vLength, true);
break;
case EIP2930:
chain_id = u32_from_BE(tmpContent.txContent.chainID.value,
tmpContent.txContent.chainID.length,
true);
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();
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]);
}
}
return NULL;
}
char *get_network_name(void) {
network_info_t *network = get_network();
if (network == NULL) {
return NULL;
} else {
return (char *) PIC(network->name);
}
}
char *get_network_ticker(void) {
network_info_t *network = get_network();
if (network == NULL) {
return chainConfig->coinName;
} else {
return (char *) PIC(network->ticker);
}
}

19
src_common/network.h Normal file
View File

@@ -0,0 +1,19 @@
#include <stdint.h>
#include "tokens.h"
#define NETWORK_STRING_MAX_SIZE 12
typedef struct network_info_s {
const char name[NETWORK_STRING_MAX_SIZE];
const char ticker[MAX_TICKER_LEN];
uint32_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);
// 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.
char *get_network_name(void);
// Returns a pointer to the network ticker, or chainConfig->coinName if there is none.
char *get_network_ticker(void);

View File

@@ -2,3 +2,5 @@
customStatus_e customProcessor(txContext_t *context);
void finalizeParsing(bool direct);
void ux_approve_tx(bool dataPresent);

View File

@@ -6,6 +6,7 @@
#include "stark_utils.h"
#endif
#include "eth_plugin_handler.h"
#include "network.h"
#define ERR_SILENT_MODE_CHECK_FAILED 0x6001
@@ -195,7 +196,7 @@ void reportFinalizeError(bool direct) {
void computeFees(char *displayBuffer, uint32_t displayBufferSize) {
uint256_t gasPrice, startGas, uint256;
uint8_t *feeTicker = (uint8_t *) PIC(chainConfig->coinName);
char *feeTicker = get_network_ticker();
uint8_t tickerOffset = 0;
uint32_t i;
@@ -240,25 +241,14 @@ void computeFees(char *displayBuffer, uint32_t displayBufferSize) {
void finalizeParsing(bool direct) {
char displayBuffer[50];
uint8_t decimals = WEI_TO_ETHER;
uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName);
char *ticker = get_network_ticker();
ethPluginFinalize_t pluginFinalize;
tokenDefinition_t *token1 = NULL, *token2 = NULL;
bool genericUI = true;
// Verify the chain
if (chainConfig->chainId != 0) {
uint32_t id = 0;
if (txContext.txType == LEGACY) {
id = u32_from_BE(txContext.content->v, txContext.content->vLength, true);
} else if (txContext.txType == EIP2930) {
id = u32_from_BE(txContext.content->chainID.value,
txContext.content->chainID.length,
false);
} else {
PRINTF("TxType `%u` not supported while checking for chainID\n", txContext.txType);
return;
}
if (chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) {
uint32_t id = get_chain_id();
if (chainConfig->chainId != id) {
PRINTF("Invalid chainID %u expected %u\n", id, chainConfig->chainId);
@@ -342,7 +332,7 @@ void finalizeParsing(bool direct) {
tmpContent.txContent.destinationLength = 20;
if (token1 != NULL) {
decimals = token1->decimals;
ticker = token1->ticker;
ticker = (char *) token1->ticker;
}
break;
default:
@@ -404,26 +394,22 @@ void finalizeParsing(bool direct) {
// Prepare chainID field
if (genericUI) {
if (txContext.txType == LEGACY) {
uint32_t id = u32_from_BE(txContext.content->v, txContext.content->vLength, true);
PRINTF("Chain ID: %u\n", id);
uint8_t res =
snprintf(strings.common.chainID, sizeof(strings.common.chainID), "%d", id);
if (res >= sizeof(strings.common.chainID)) {
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);
}
} else if (txContext.txType == EIP2930) {
uint256_t chainID;
convertUint256BE(tmpContent.txContent.chainID.value,
tmpContent.txContent.chainID.length,
&chainID);
tostring256(&chainID, 10, displayBuffer, sizeof(displayBuffer));
strncpy(strings.common.chainID, displayBuffer, sizeof(strings.common.chainID));
} else {
PRINTF("Txtype `%u` not supported while generating chainID\n", txContext.txType);
return;
// Network name found, simply copy it.
strncpy(strings.common.network_name, name, sizeof(strings.common.network_name));
}
}

View File

@@ -2,6 +2,8 @@
#include "ui_callbacks.h"
#include "chainConfig.h"
#include "utils.h"
#include "feature_signTx.h"
#include "network.h"
// clang-format off
UX_STEP_NOCB(
@@ -116,11 +118,11 @@ UX_STEP_NOCB(
.text = strings.common.maxFee,
});
UX_STEP_NOCB(
ux_approval_chainid_step,
ux_approval_network_step,
bnnn_paging,
{
.title = "Chain ID",
.text = strings.common.chainID,
.title = "Network",
.text = strings.common.network_name,
});
UX_STEP_CB(
ux_approval_accept_step,
@@ -171,18 +173,9 @@ void ux_approve_tx(bool dataPresent) {
ux_approval_tx_flow_[step++] = &ux_approval_nonce_step;
}
uint32_t id;
if (txContext.txType == LEGACY) {
id = u32_from_BE(txContext.content->v, txContext.content->vLength, true);
} else if (txContext.txType == EIP2930) {
id =
u32_from_BE(txContext.content->chainID.value, txContext.content->chainID.length, false);
} else {
PRINTF("TxType `%u` not supported while preparing to approve tx\n", txContext.txType);
THROW(0x6501);
}
if (id != ETHEREUM_MAINNET_CHAINID) {
ux_approval_tx_flow_[step++] = &ux_approval_chainid_step;
uint32_t chain_id = get_chain_id();
if (chainConfig->chainId == ETHEREUM_MAINNET_CHAINID && chain_id != chainConfig->chainId) {
ux_approval_tx_flow_[step++] = &ux_approval_network_step;
}
ux_approval_tx_flow_[step++] = &ux_approval_fees_step;
ux_approval_tx_flow_[step++] = &ux_approval_accept_step;

View File

@@ -217,12 +217,12 @@ void eth2_plugin_call(int message, void *parameters) {
switch (msg->screenIndex) {
case 0: { // Amount screen
uint8_t decimals = WEI_TO_ETHER;
uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName);
char *ticker = chainConfig->coinName;
strcpy(msg->title, "Amount");
amountToString(tmpContent.txContent.value.value,
tmpContent.txContent.value.length,
decimals,
(char *) ticker,
ticker,
msg->msg,
100);
msg->result = ETH_PLUGIN_RESULT_OK;

View File

@@ -294,7 +294,7 @@ void starkware_print_eth_address(uint8_t *address, char *destination) {
void starkware_print_amount(uint8_t *amountData, char *destination, bool forEscape) {
uint256_t amount, amountPre, quantum;
uint8_t decimals;
char *ticker = (char *) PIC(chainConfig->coinName);
char *ticker = chainConfig->coinName;
if ((amountData == NULL) ||
(forEscape && (dataContext.tokenContext.quantumIndex == MAX_TOKEN))) {
@@ -328,7 +328,7 @@ void starkware_print_amount(uint8_t *amountData, char *destination, bool forEsca
// TODO : rewrite as independant code
void starkware_print_ticker(char *destination) {
char *ticker = (char *) PIC(chainConfig->coinName);
char *ticker = chainConfig->coinName;
if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) {
tokenDefinition_t *token =

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 B

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 860 B

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 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: 475 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: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

View File

@@ -15,14 +15,24 @@ const sim_options_nanox = {
};
const Resolve = require("path").resolve;
const NANOS_ELF_PATH = Resolve("elfs/ethereum_nanos/app.elf");
const NANOX_ELF_PATH = Resolve("elfs/ethereum_nanox/app.elf");
const NANOS_ELF_PATH = Resolve("elfs/ethereum_nanos.elf");
const NANOX_ELF_PATH = Resolve("elfs/ethereum_nanox.elf");
const NANOS_ETH_LIB = { "Ethereum": NANOS_ELF_PATH };
const NANOX_ETH_LIB = { "Ethereum": NANOX_ELF_PATH };
const NANOS_CLONE_ELF_PATH = Resolve("elfs/ethereum_classic_nanos.elf");
const NANOX_CLONE_ELF_PATH = Resolve("elfs/ethereum_classic_nanox.elf");
const TIMEOUT = 1000000;
module.exports = {
NANOS_ELF_PATH,
NANOX_ELF_PATH,
NANOS_ETH_LIB,
NANOX_ETH_LIB,
NANOS_CLONE_ELF_PATH,
NANOX_CLONE_ELF_PATH,
sim_options_nanos,
sim_options_nanox,
TIMEOUT,

View File

@@ -17,7 +17,7 @@ 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("Transfer nanos", async () => {
test("Transfer Ether on Ethereum app nanos", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOS_ELF_PATH);
@@ -106,7 +106,103 @@ test("Transfer nanos", async () => {
}
});
test("Transfer nanox", async () => {
test("Transfer on network 5234 on Ethereum nanos", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOS_ELF_PATH);
try {
await sim.start(sim_options_nanos);
let transport = await sim.getTransport();
let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex");
// Send transaction
let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer);
let filename;
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
// Review tx
filename = "review.png";
await sim.snapshot(SNAPSHOT_PATH_NANOS + filename);
const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(review).toEqual(expected_review);
// Amount 1/3
filename = "amount_1.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const amount_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_amount_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_1).toEqual(expected_amount_1);
// Amount 2/3
filename = "amount_2.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const amount_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_amount_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_2).toEqual(expected_amount_2);
// Amount 3/3
filename = "amount_3.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const amount_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_amount_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_3).toEqual(expected_amount_3);
// Address 1/3
filename = "address_1.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const address_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_address_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_1).toEqual(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);
const expected_address_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_2).toEqual(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);
const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_3).toEqual(expected_address_3);
// Network
filename = "network.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const network = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(network).toEqual(expected_network);
// Max Fees
filename = "fees.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(fees).toEqual(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(accept).toEqual(expected_accept);
await sim.clickBoth();
await expect(tx).resolves.toEqual(
Buffer.from("08f3449bbc245669e26dd076986e11aa3117e2405ffe2ddc7a7e220f81326fbd91150515605c78119367be311345e9ff40c4e4ddb9ec0fd81f37035c3828f4c8b29000", 'hex')
);
} finally {
await sim.close();
}
});
test("Transfer Ether on Ethereum nanox", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOX_ELF_PATH);
@@ -164,4 +260,73 @@ test("Transfer nanox", async () => {
} finally {
await sim.close();
}
});
test("Transfer on network 5234 on Ethereum nanox", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOX_ELF_PATH);
try {
await sim.start(sim_options_nanox);
let transport = await sim.getTransport();
let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex");
// Send transaction
let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer);
let filename;
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);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(review).toEqual(expected_review);
// Amount
filename = "amount.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const amount = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(amount).toEqual(expected_amount);
// Address
filename = "address.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const address = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(address).toEqual(expected_address);
// Network
filename = "network.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const network = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(network).toEqual(expected_network);
// Max Fees
filename = "fees.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(fees).toEqual(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(accept).toEqual(expected_accept);
await sim.clickBoth();
await expect(tx).resolves.toEqual(
Buffer.from("08f3449bbc245669e26dd076986e11aa3117e2405ffe2ddc7a7e220f81326fbd91150515605c78119367be311345e9ff40c4e4ddb9ec0fd81f37035c3828f4c8b29000", 'hex')
);
} finally {
await sim.close();
}
});

View File

@@ -83,8 +83,8 @@ test("Transfer bsc nanos", async () => {
const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_3).toEqual(expected_address_3);
// Chain ID
filename = "chainid.png";
// Network name
filename = "network.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_chainid = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
@@ -151,8 +151,8 @@ test("Transfer bsc nanox", async () => {
const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(address).toEqual(expected_address);
// Chain ID
filename = "chainid.png";
// Network name
filename = "network.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_chainid = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);

208
tests/src/send_etc.test.js Normal file
View File

@@ -0,0 +1,208 @@
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_ETH_LIB, NANOX_ETH_LIB, NANOS_CLONE_ELF_PATH, NANOX_CLONE_ELF_PATH, sim_options_nanos, sim_options_nanox, TIMEOUT} = require("generic.js");
const ORIGINAL_SNAPSHOT_PATH_PREFIX = "snapshots/send_etc/";
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("Transfer on Ethereum clone app nanos", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOS_CLONE_ELF_PATH, NANOS_ETH_LIB);
try {
await sim.start(sim_options_nanos);
let transport = await sim.getTransport();
let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818803D8080", "hex");
// Send transaction
let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer);
let filename;
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
// Review tx
filename = "review.png";
await sim.snapshot(SNAPSHOT_PATH_NANOS + filename);
const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(review).toEqual(expected_review);
// Amount 1/3
filename = "amount_1.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const amount_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_amount_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_1).toEqual(expected_amount_1);
// Amount 2/3
filename = "amount_2.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const amount_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_amount_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_2).toEqual(expected_amount_2);
// Amount 3/3
filename = "amount_3.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const amount_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_amount_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(amount_3).toEqual(expected_amount_3);
// Address 1/3
filename = "address_1.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const address_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_address_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_1).toEqual(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);
const expected_address_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_2).toEqual(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);
const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_3).toEqual(expected_address_3);
// Max Fees
filename = "fees.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(fees).toEqual(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(accept).toEqual(expected_accept);
await sim.clickBoth();
await expect(tx).resolves.toEqual(
Buffer.from("9e52b80e10cb82f3dc8345005e3da3f9cae1fb3f2b9a5df05b7cedba786c685fed381875af27d121beaa9efd8a7450975f9d45a26ba5aa331b7a8b26bcce95e6d09000", 'hex')
);
} finally {
await sim.close();
}
});
test("Transfer on network 5234 on Ethereum clone nanos", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOS_CLONE_ELF_PATH, NANOS_ETH_LIB);
try {
await sim.start(sim_options_nanos);
let transport = await sim.getTransport();
let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex");
// Send transaction
let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer);
await expect(tx).rejects.toEqual(new TransportStatusError(0x6a80));
} finally {
await sim.close();
}
});
test("Transfer on Ethereum clone nanox", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOX_CLONE_ELF_PATH, NANOX_ETH_LIB);
try {
await sim.start(sim_options_nanox);
let transport = await sim.getTransport();
let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818803D8080", "hex");
// Send transaction
let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer);
let filename;
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);
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(review).toEqual(expected_review);
// Amount
filename = "amount.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const amount = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(amount).toEqual(expected_amount);
// Address
filename = "address.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const address = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(address).toEqual(expected_address);
// Max Fees
filename = "fees.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(fees).toEqual(expected_fees);
// Accept
filename = "accept.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(accept).toEqual(expected_accept);
await sim.clickBoth();
await expect(tx).resolves.toEqual(
Buffer.from("9e52b80e10cb82f3dc8345005e3da3f9cae1fb3f2b9a5df05b7cedba786c685fed381875af27d121beaa9efd8a7450975f9d45a26ba5aa331b7a8b26bcce95e6d09000", 'hex')
);
} finally {
await sim.close();
}
});
test("Transfer on network 5234 on Ethereum clone nanox", async () => {
jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOX_CLONE_ELF_PATH, NANOX_ETH_LIB);
try {
await sim.start(sim_options_nanox);
let transport = await sim.getTransport();
let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex");
// Send transaction
let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer);
await expect(tx).rejects.toEqual(new TransportStatusError(0x6a80));
} finally {
await sim.close();
}
});