Merge branch 'bsc'

This commit is contained in:
pscott
2021-07-27 11:21:39 +02:00
76 changed files with 843 additions and 285 deletions

View File

@@ -3,18 +3,18 @@ name: Compilation & tests
on: on:
push: push:
branches: branches:
- master - master
pull_request: pull_request:
branches: branches:
- master - master
jobs: jobs:
job_build_debug: job_build_debug_nano_s:
name: Build debug name: Build debug Nano S
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:2.0.0-1 image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
steps: steps:
- name: Clone - name: Clone
@@ -24,21 +24,93 @@ jobs:
- name: Build an altcoin - name: Build an altcoin
run: | run: |
make DEBUG=1 CHAIN=ethereum_classic make DEBUG=1 ALLOW_DATA=1 CHAIN=ethereum_classic
mv bin/app.elf ethereum_classic_nanos.elf
- name: Upload altcoin binary - name: Upload altcoin binary
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: ethereum-classic-app-debug name: ethereum_classic_nanos
path: bin path: ./ethereum_classic_nanos.elf
- name: Build Ethereum - name: Build Ethereum
run: | run: |
make clean make clean
make DEBUG=1 make DEBUG=1 ALLOW_DATA=1
mv bin/app.elf ethereum_nanos.elf
- name: Upload app binary - name: Upload app binary
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: ethereum-app-debug name: ethereum_nanos
path: bin path: ./ethereum_nanos.elf
job_build_debug_nano_x:
name: Build debug Nano X
runs-on: ubuntu-latest
container:
image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
steps:
- name: Clone
uses: actions/checkout@v2
with:
submodules: recursive
- name: Build an altcoin Nano X
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: ./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: ./ethereum_nanox.elf
jobs-e2e-tests:
needs: [job_build_debug_nano_s, job_build_debug_nano_x]
runs-on: ubuntu-latest
steps:
- name: Test
run: |
id
echo $HOME
echo $DISPLAY
- name: Checkout
uses: actions/checkout@v2
- run: sudo apt-get update -y && sudo apt-get install -y libusb-1.0.0 libudev-dev
- name: Install node
uses: actions/setup-node@v2
with:
node-version: "14.4.0"
- name: Install yarn
run: |
npm install -g yarn
- name: Build/Install build js deps
run: |
cd tests && yarn install
- name: Download app binaries
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

@@ -1,35 +0,0 @@
name: End-to-end tests
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
e2e-tests:
runs-on: ubuntu-latest
steps:
- name: Test
run: |
id
echo $HOME
echo $DISPLAY
- name: Checkout
uses: actions/checkout@v2
- run: sudo apt-get update -y && sudo apt-get install -y libusb-1.0.0 libudev-dev
- name: Install node
uses: actions/setup-node@v2
with:
node-version: '14.4.0'
- name: Install yarn
run: |
npm install -g yarn
- name: Build/Install build js deps
run: |
cd tests && yarn install
- name: Run zemu tests
run: |
cd tests && yarn test

View File

@@ -5,14 +5,34 @@ 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.8.6](https://github.com/ledgerhq/app-ethereum/compare/1.7.9...1.8.6) - 2021-6-15 ## [1.8.8](https://github.com/ledgerhq/app-ethereum/compare/1.7.9...1.8.6) - 2021-7-21
### Added ### Added
- Added support for BSC. - Added support for BSC.
- Added icons for Flare. - Add support for Lido plugin
- Allowed an extra derivation path for Theta.
## [1.8.7](https://github.com/ledgerhq/app-ethereum/compare/1.8.6...1.8.7) - 2021-7-9
### Added
Plugins can now check the address of the transaction sender.
Remove `m/44'/60'` derivation path authorisation for Theta app.
### Fixed
`additional_screens` was introduced previously but wasn't properly initialized in some cases.
## [1.8.6](https://github.com/ledgerhq/app-ethereum/compare/1.8.5...1.8.6) - 2021-7-5
### Added
Display the name of the network when signing a transaction, or the chain ID if the network is not known
When the network is known, amounts and fees are displayed in the network unit instead of ETH.
### Fixed
Fix some compilation warning
## [1.8.5](https://github.com/ledgerhq/app-ethereum/compare/1.7.9...1.8.5) - 2021-6-8 ## [1.8.5](https://github.com/ledgerhq/app-ethereum/compare/1.7.9...1.8.5) - 2021-6-8
@@ -75,9 +95,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added ### Added
- Improve Ethereum 2 deposit security: - Improve Ethereum 2 deposit security:
- Display the validator address on screen when depositing. - Display the validator address on screen when depositing.
- Abort signing when the account index of the withdrawal key is higher than INDEX_MAX. - Abort signing when the account index of the withdrawal key is higher than INDEX_MAX.
- Check that the destination field of the transaction is Ethereum 2 deposit contract. - Check that the destination field of the transaction is Ethereum 2 deposit contract.
## [1.7.1](https://github.com/ledgerhq/app-ethereum/compare/1.7.0...1.7.1) - 2021-5-5 ## [1.7.1](https://github.com/ledgerhq/app-ethereum/compare/1.7.0...1.7.1) - 2021-5-5
@@ -85,21 +105,25 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Support for Berlin hard fork: EIP2718 (transaction types) and EIP2930 (access list transactions) - Support for Berlin hard fork: EIP2718 (transaction types) and EIP2930 (access list transactions)
- Display ChainID when transacting on chains which are not ethereum (BSC, Polygon, etc) - Display ChainID when transacting on chains which are not ethereum (BSC, Polygon, etc)
## [1.7.0](https://github.com/ledgerhq/app-ethereum/compare/1.6.6...1.7.0) - 2021-4-30 ## [1.7.0](https://github.com/ledgerhq/app-ethereum/compare/1.6.6...1.7.0) - 2021-4-30
### Added ### Added
- Wallet ID feature now available on Nano X - Wallet ID feature now available on Nano X
## [1.6.6](https://github.com/ledgerhq/app-ethereum/compare/1.6.5...1.6.6) - 2021-4-16 ## [1.6.6](https://github.com/ledgerhq/app-ethereum/compare/1.6.5...1.6.6) - 2021-4-16
### Added ### Added
- Improved Starkware support - Improved Starkware support
## [1.6.5](https://github.com/ledgerhq/app-ethereum/compare/1.6.4...1.6.5) - 2021-2-12 ## [1.6.5](https://github.com/ledgerhq/app-ethereum/compare/1.6.4...1.6.5) - 2021-2-12
### Added ### Added
- Add a setting to enable nonce display when approving transactions - Add a setting to enable nonce display when approving transactions
## [1.6.4](https://github.com/ledgerhq/app-ethereum/compare/1.6.3...1.6.4) - 2021-1-12 ## [1.6.4](https://github.com/ledgerhq/app-ethereum/compare/1.6.3...1.6.4) - 2021-1-12
### Fixed ### Fixed

View File

@@ -31,7 +31,7 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'"
APPVERSION_M=1 APPVERSION_M=1
APPVERSION_N=8 APPVERSION_N=8
APPVERSION_P=8 APPVERSION_P=8
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)-rc1 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
APP_LOAD_FLAGS= --appFlags 0x240 --dep Ethereum:$(APPVERSION) APP_LOAD_FLAGS= --appFlags 0x240 --dep Ethereum:$(APPVERSION)
ifeq ($(CHAIN),) ifeq ($(CHAIN),)
@@ -41,7 +41,7 @@ endif
ifeq ($(CHAIN),ethereum) ifeq ($(CHAIN),ethereum)
# Lock the application on its standard path for 1.5. Please complain if non compliant # Lock the application on its standard path for 1.5. Please complain if non compliant
APP_LOAD_PARAMS += --path "44'/60'" 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 # Starkware integration
APP_LOAD_PARAMS += --path "2645'/579218131'" APP_LOAD_PARAMS += --path "2645'/579218131'"
DEFINES += HAVE_STARKWARE DEFINES += HAVE_STARKWARE
@@ -197,7 +197,7 @@ 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) else ifeq ($(CHAIN),theta)
APP_LOAD_PARAMS += --path "44'/500'" --path "44'/60'" APP_LOAD_PARAMS += --path "44'/500'"
DEFINES += CHAINID_UPCASE=\"THETA\" CHAINID_COINNAME=\"THETA\" CHAIN_KIND=CHAIN_KIND_THETA CHAIN_ID=500 DEFINES += CHAINID_UPCASE=\"THETA\" CHAINID_COINNAME=\"THETA\" CHAIN_KIND=CHAIN_KIND_THETA CHAIN_ID=500
APPNAME = "Theta" APPNAME = "Theta"
else ifeq ($(CHAIN),bsc) else ifeq ($(CHAIN),bsc)
@@ -270,6 +270,12 @@ ifneq ($(ALLOW_DATA),0)
DEFINES += HAVE_ALLOW_DATA DEFINES += HAVE_ALLOW_DATA
endif endif
# Bypass the signature verification for setExternalPlugin and provideERC20TokenInfo calls
BYPASS_SIGNATURES:=0
ifneq ($(BYPASS_SIGNATURES),0)
DEFINES += HAVE_BYPASS_SIGNATURES
endif
# Enabling debug PRINTF # Enabling debug PRINTF
DEBUG:=0 DEBUG:=0
@@ -338,6 +344,7 @@ endif
# rebuild # rebuild
$(shell python3 ethereum-plugin-sdk/build_sdk.py) $(shell python3 ethereum-plugin-sdk/build_sdk.py)
$(shell find ./ethereum-plugin-sdk -iname '*.h' -o -iname '*.c' | xargs clang-format-10 -i)
# check if a difference is noticed (fail if it happens in CI build) # check if a difference is noticed (fail if it happens in CI build)
ifneq ($(shell git status | grep 'ethereum-plugin-sdk'),) ifneq ($(shell git status | grep 'ethereum-plugin-sdk'),)

View File

@@ -2,9 +2,13 @@
Ethereum wallet application framework for Nano S and Nano X. Ethereum wallet application framework for Nano S and Nano X.
Ledger Blue is not maintained anymore, but the app can still be compiled for this target using the branch `blue-final-release`. Ledger Blue is not maintained anymore, but the app can still be compiled for this target using the branch `blue-final-release`.
This app follows the specification available in the `doc/` folder This app follows the specification available in the `doc/` folder.
To compile it and load it on a device, have a look here: https://ledger.readthedocs.io/en/latest/userspace/getting_started.html To compile it and load it on a device, please check out our [developer portal](https://developers.ledger.com/docs/NA/start_here/).
# Plugins
This app support external plugins. More info in [doc/ethapp_plugin.asc](https://github.com/LedgerHQ/app-ethereum/blob/master/doc/ethapp_plugins.asc). If you wish to have a look at an existing plugin, feel free to check out the [ParaSwap plugin](https://github.com/LedgerHQ/app-plugin-paraswap).
# Testing # Testing
@@ -55,5 +59,4 @@ Then copy the binary to the `tests/elfs` folder (in this case, compiled with SDK
cp bin/app.elf tests/elfs/ethereum_nanos.elf cp bin/app.elf tests/elfs/ethereum_nanos.elf
``` ```
Repeat the operation for a binary compiled with nanoX SDK and change for `ethereum_nanox.elf`. Repeat the operation for a binary compiled with nanoX SDK and change for `ethereum_nanox.elf`.

View File

@@ -10,6 +10,8 @@ Specification version 1.0 - 24th of September 2020
This specification describes the plugin interface used to display a specific UI on device for Ethereum smart contracts. This specification describes the plugin interface used to display a specific UI on device for Ethereum smart contracts.
Feel free to checkout the ParaSwap plugin to see an actual implementation. Link: https://github.com/LedgerHQ/app-ethereum/blob/named-external-plugins/doc/ethapp_plugins.asc .
## Flow overview ## Flow overview
When signing an Ethereum transaction containing data, the Ethereum application looks for a plugin using .either a selector list or the contract address. When signing an Ethereum transaction containing data, the Ethereum application looks for a plugin using .either a selector list or the contract address.
@@ -146,7 +148,7 @@ typedef struct ethPluginFinalize_t {
uint8_t *tokenLookup2; uint8_t *tokenLookup2;
uint8_t *amount; // set an uint256 pointer if uiType is UI_AMOUNT_ADDRESS uint8_t *amount; // set an uint256 pointer if uiType is UI_AMOUNT_ADDRESS
uint8_t *address; // set to a 20 bytes address pointer if uiType is UI_AMOUNT_ADDRESS uint8_t *address; // set to the destination address if uiType is UI_AMOUNT_ADDRESS. Set to the user's address if uiType is UI_TYPE_GENERIC
uint8_t uiType; uint8_t uiType;
uint8_t numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS uint8_t numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS
@@ -279,7 +281,7 @@ The following return codes are expected, any other will abort the signing proces
When setting a pointer from the plugin space, make sure to use an address that will be accessible from the Ethereum application (typically in the plugin RAM context, *not* on the plugin stack) When setting a pointer from the plugin space, make sure to use an address that will be accessible from the Ethereum application (typically in the plugin RAM context, *not* on the plugin stack)
Do not use data types that need to be aligned (such as uint32_t) in the plugin context Do not use data types that need to be aligned (such as uint32_t) in the plugin context.
## TODOs ## TODOs

View File

@@ -59,6 +59,9 @@ class UnsignedTransaction(Serializable):
('to', address), ('to', address),
('value', big_endian_int), ('value', big_endian_int),
('data', binary), ('data', binary),
('chainid', big_endian_int),
('dummy1', big_endian_int),
('dummy2', big_endian_int),
] ]
def unsigned_tx_from_tx(tx): 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('--to', help="Destination address", type=str, required=True)
parser.add_argument('--path', help="BIP 32 path to sign with") parser.add_argument('--path', help="BIP 32 path to sign with")
parser.add_argument('--data', help="Data to add, hex encoded") 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") parser.add_argument('--descriptor', help="Optional descriptor")
args = parser.parse_args() args = parser.parse_args()
@@ -71,6 +72,10 @@ if args.data == None:
else: else:
args.data = decode_hex(args.data[2:]) args.data = decode_hex(args.data[2:])
# default to Ethereum mainnet
if args.chainid == None:
args.chainid = 1
amount = Decimal(args.amount) * 10**18 amount = Decimal(args.amount) * 10**18
tx = UnsignedTransaction( tx = UnsignedTransaction(
@@ -80,10 +85,16 @@ tx = UnsignedTransaction(
to=decode_hex(args.to[2:]), to=decode_hex(args.to[2:]),
value=int(amount), value=int(amount),
data=args.data, data=args.data,
chainid=args.chainid,
dummy1=0,
dummy2=0
) )
encodedTx = encode(tx, UnsignedTransaction) encodedTx = encode(tx, UnsignedTransaction)
# To test an EIP-2930 transaction, uncomment this line
#encodedTx = bytearray.fromhex("01f8e60380018402625a0094cccccccccccccccccccccccccccccccccccccccc830186a0a4693c61390000000000000000000000000000000000000000000000000000000000000002f85bf859940000000000000000000000000000000000000102f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000060a780a09b8adcd2a4abd34b42d56fcd90b949f74ca9696dfe2b427bc39aa280bbf1924ca029af4a471bb2953b4e7933ea95880648552a9345424a1ac760189655ceb1832a")
dongle = getDongle(True) dongle = getDongle(True)
if args.descriptor != None: if args.descriptor != None:

View File

@@ -21,12 +21,8 @@ void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize) {
memset((uint8_t *) finalize, 0, sizeof(ethPluginFinalize_t)); memset((uint8_t *) finalize, 0, sizeof(ethPluginFinalize_t));
} }
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken, void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken) {
tokenDefinition_t *token1,
tokenDefinition_t *token2) {
memset((uint8_t *) provideToken, 0, sizeof(ethPluginProvideToken_t)); memset((uint8_t *) provideToken, 0, sizeof(ethPluginProvideToken_t));
provideToken->token1 = token1;
provideToken->token2 = token2;
} }
void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID, void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID,
@@ -67,11 +63,19 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress,
if (memcmp(contractAddress, if (memcmp(contractAddress,
dataContext.tokenContext.contract_address, dataContext.tokenContext.contract_address,
sizeof(dataContext.tokenContext.contract_address)) != 0) { sizeof(dataContext.tokenContext.contract_address)) != 0) {
PRINTF("Got contract: %.*H\n", ADDRESS_LENGTH, contractAddress);
PRINTF("Expected contract: %.*H\n",
ADDRESS_LENGTH,
dataContext.tokenContext.contract_address);
os_sched_exit(0); os_sched_exit(0);
} }
if (memcmp(init->selector, if (memcmp(init->selector,
dataContext.tokenContext.method_selector, dataContext.tokenContext.method_selector,
sizeof(dataContext.tokenContext.method_selector)) != 0) { sizeof(dataContext.tokenContext.method_selector)) != 0) {
PRINTF("Got selector: %.*H\n", SELECTOR_SIZE, init->selector);
PRINTF("Expected selector: %.*H\n",
SELECTOR_SIZE,
dataContext.tokenContext.method_selector);
os_sched_exit(0); os_sched_exit(0);
} }
PRINTF("External plugin will be used\n"); PRINTF("External plugin will be used\n");
@@ -128,7 +132,6 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress,
eth_plugin_result_t eth_plugin_call(int method, void *parameter) { eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
ethPluginSharedRW_t pluginRW; ethPluginSharedRW_t pluginRW;
ethPluginSharedRO_t pluginRO; ethPluginSharedRO_t pluginRO;
char tmp[PLUGIN_ID_LENGTH];
char *alias; char *alias;
uint8_t i; uint8_t i;
uint8_t internalPlugin = 0; uint8_t internalPlugin = 0;
@@ -146,6 +149,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
switch (method) { switch (method) {
case ETH_PLUGIN_INIT_CONTRACT: case ETH_PLUGIN_INIT_CONTRACT:
PRINTF("-- PLUGIN INIT CONTRACT --\n");
((ethPluginInitContract_t *) parameter)->interfaceVersion = ((ethPluginInitContract_t *) parameter)->interfaceVersion =
ETH_PLUGIN_INTERFACE_VERSION_1; ETH_PLUGIN_INTERFACE_VERSION_1;
((ethPluginInitContract_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; ((ethPluginInitContract_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
@@ -158,6 +162,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
((ethPluginInitContract_t *) parameter)->alias = dataContext.tokenContext.pluginName; ((ethPluginInitContract_t *) parameter)->alias = dataContext.tokenContext.pluginName;
break; break;
case ETH_PLUGIN_PROVIDE_PARAMETER: case ETH_PLUGIN_PROVIDE_PARAMETER:
PRINTF("-- PLUGIN PROVIDE PARAMETER --\n");
((ethPluginProvideParameter_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; ((ethPluginProvideParameter_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethPluginProvideParameter_t *) parameter)->pluginSharedRW = &pluginRW; ((ethPluginProvideParameter_t *) parameter)->pluginSharedRW = &pluginRW;
((ethPluginProvideParameter_t *) parameter)->pluginSharedRO = &pluginRO; ((ethPluginProvideParameter_t *) parameter)->pluginSharedRO = &pluginRO;
@@ -165,6 +170,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
(uint8_t *) &dataContext.tokenContext.pluginContext; (uint8_t *) &dataContext.tokenContext.pluginContext;
break; break;
case ETH_PLUGIN_FINALIZE: case ETH_PLUGIN_FINALIZE:
PRINTF("-- PLUGIN FINALIZE --\n");
((ethPluginFinalize_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; ((ethPluginFinalize_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethPluginFinalize_t *) parameter)->pluginSharedRW = &pluginRW; ((ethPluginFinalize_t *) parameter)->pluginSharedRW = &pluginRW;
((ethPluginFinalize_t *) parameter)->pluginSharedRO = &pluginRO; ((ethPluginFinalize_t *) parameter)->pluginSharedRO = &pluginRO;
@@ -172,6 +178,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
(uint8_t *) &dataContext.tokenContext.pluginContext; (uint8_t *) &dataContext.tokenContext.pluginContext;
break; break;
case ETH_PLUGIN_PROVIDE_TOKEN: case ETH_PLUGIN_PROVIDE_TOKEN:
PRINTF("-- PLUGIN PROVIDE TOKEN --\n");
((ethPluginProvideToken_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; ((ethPluginProvideToken_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethPluginProvideToken_t *) parameter)->pluginSharedRW = &pluginRW; ((ethPluginProvideToken_t *) parameter)->pluginSharedRW = &pluginRW;
((ethPluginProvideToken_t *) parameter)->pluginSharedRO = &pluginRO; ((ethPluginProvideToken_t *) parameter)->pluginSharedRO = &pluginRO;
@@ -179,6 +186,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
(uint8_t *) &dataContext.tokenContext.pluginContext; (uint8_t *) &dataContext.tokenContext.pluginContext;
break; break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: case ETH_PLUGIN_QUERY_CONTRACT_ID:
PRINTF("-- PLUGIN QUERY CONTRACT ID --\n");
((ethQueryContractID_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE; ((ethQueryContractID_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
((ethQueryContractID_t *) parameter)->pluginSharedRW = &pluginRW; ((ethQueryContractID_t *) parameter)->pluginSharedRW = &pluginRW;
((ethQueryContractID_t *) parameter)->pluginSharedRO = &pluginRO; ((ethQueryContractID_t *) parameter)->pluginSharedRO = &pluginRO;
@@ -186,6 +194,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
(uint8_t *) &dataContext.tokenContext.pluginContext; (uint8_t *) &dataContext.tokenContext.pluginContext;
break; break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: case ETH_PLUGIN_QUERY_CONTRACT_UI:
PRINTF("-- PLUGIN QUERY CONTRACT UI --\n");
((ethQueryContractUI_t *) parameter)->pluginSharedRW = &pluginRW; ((ethQueryContractUI_t *) parameter)->pluginSharedRW = &pluginRW;
((ethQueryContractUI_t *) parameter)->pluginSharedRO = &pluginRO; ((ethQueryContractUI_t *) parameter)->pluginSharedRO = &pluginRO;
((ethQueryContractUI_t *) parameter)->pluginContext = ((ethQueryContractUI_t *) parameter)->pluginContext =
@@ -231,7 +240,6 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
PRINTF("method: %d\n", method); PRINTF("method: %d\n", method);
switch (method) { switch (method) {
case ETH_PLUGIN_INIT_CONTRACT: case ETH_PLUGIN_INIT_CONTRACT:
PRINTF("parameter result: %d\n", ((ethPluginInitContract_t *) parameter)->result);
switch (((ethPluginInitContract_t *) parameter)->result) { switch (((ethPluginInitContract_t *) parameter)->result) {
case ETH_PLUGIN_RESULT_OK: case ETH_PLUGIN_RESULT_OK:
break; break;
@@ -264,6 +272,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
} }
break; break;
case ETH_PLUGIN_PROVIDE_TOKEN: case ETH_PLUGIN_PROVIDE_TOKEN:
PRINTF("RESULT: %d\n", ((ethPluginProvideToken_t *) parameter)->result);
switch (((ethPluginProvideToken_t *) parameter)->result) { switch (((ethPluginProvideToken_t *) parameter)->result) {
case ETH_PLUGIN_RESULT_OK: case ETH_PLUGIN_RESULT_OK:
case ETH_PLUGIN_RESULT_FALLBACK: case ETH_PLUGIN_RESULT_FALLBACK:
@@ -280,7 +289,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
} }
break; break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: case ETH_PLUGIN_QUERY_CONTRACT_UI:
if (((ethQueryContractUI_t *) parameter)->result <= ETH_PLUGIN_RESULT_OK) { if (((ethQueryContractUI_t *) parameter)->result <= ETH_PLUGIN_RESULT_UNSUCCESSFUL) {
return ETH_PLUGIN_RESULT_UNAVAILABLE; return ETH_PLUGIN_RESULT_UNAVAILABLE;
} }
break; break;

View File

@@ -7,9 +7,7 @@ void eth_plugin_prepare_provide_parameter(ethPluginProvideParameter_t *providePa
uint8_t *parameter, uint8_t *parameter,
uint32_t parameterOffset); uint32_t parameterOffset);
void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize); void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize);
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken, void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken);
tokenDefinition_t *token1,
tokenDefinition_t *token2);
void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID, void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID,
char *name, char *name,
uint32_t nameLength, uint32_t nameLength,

View File

@@ -104,7 +104,8 @@ typedef struct ethPluginFinalize_t {
uint8_t *tokenLookup2; uint8_t *tokenLookup2;
uint8_t *amount; // set an uint256 pointer if uiType is UI_AMOUNT_ADDRESS uint8_t *amount; // set an uint256 pointer if uiType is UI_AMOUNT_ADDRESS
uint8_t *address; // set to a 20 bytes address pointer if uiType is UI_AMOUNT_ADDRESS uint8_t *address; // set to the destination address if uiType is UI_AMOUNT_ADDRESS. Set to the
// user's address if uiType is UI_TYPE_GENERIC
uint8_t uiType; uint8_t uiType;
uint8_t numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS uint8_t numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS

View File

@@ -13,23 +13,20 @@ void starkware_plugin_call(int message, void* parameters);
void eth2_plugin_call(int message, void* parameters); void eth2_plugin_call(int message, void* parameters);
#endif #endif
static const uint8_t const ERC20_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0xa9, 0x05, 0x9c, 0xbb}; static const uint8_t ERC20_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0xa9, 0x05, 0x9c, 0xbb};
static const uint8_t const ERC20_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3}; static const uint8_t ERC20_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3};
const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS] = {ERC20_TRANSFER_SELECTOR, const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS] = {ERC20_TRANSFER_SELECTOR,
ERC20_APPROVE_SELECTOR}; ERC20_APPROVE_SELECTOR};
static const uint8_t const ERC721_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3}; static const uint8_t ERC721_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3};
const uint8_t* const ERC721_SELECTORS[NUM_ERC721_SELECTORS] = {ERC721_APPROVE_SELECTOR}; const uint8_t* const ERC721_SELECTORS[NUM_ERC721_SELECTORS] = {ERC721_APPROVE_SELECTOR};
static const uint8_t const COMPOUND_REDEEM_UNDERLYING_SELECTOR[SELECTOR_SIZE] = {0x85, static const uint8_t COMPOUND_REDEEM_UNDERLYING_SELECTOR[SELECTOR_SIZE] = {0x85, 0x2a, 0x12, 0xe3};
0x2a, static const uint8_t COMPOUND_REDEEM_SELECTOR[SELECTOR_SIZE] = {0xdb, 0x00, 0x6a, 0x75};
0x12, static const uint8_t COMPOUND_MINT_SELECTOR[SELECTOR_SIZE] = {0xa0, 0x71, 0x2d, 0x68};
0xe3}; static const uint8_t CETH_MINT_SELECTOR[SELECTOR_SIZE] = {0x12, 0x49, 0xc5, 0x8b};
static const uint8_t const COMPOUND_REDEEM_SELECTOR[SELECTOR_SIZE] = {0xdb, 0x00, 0x6a, 0x75};
static const uint8_t const COMPOUND_MINT_SELECTOR[SELECTOR_SIZE] = {0xa0, 0x71, 0x2d, 0x68};
static const uint8_t const CETH_MINT_SELECTOR[SELECTOR_SIZE] = {0x12, 0x49, 0xc5, 0x8b};
const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = { const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = {
COMPOUND_REDEEM_UNDERLYING_SELECTOR, COMPOUND_REDEEM_UNDERLYING_SELECTOR,
@@ -39,7 +36,7 @@ const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = {
#ifdef HAVE_ETH2 #ifdef HAVE_ETH2
static const uint8_t const ETH2_DEPOSIT_SELECTOR[SELECTOR_SIZE] = {0x22, 0x89, 0x51, 0x18}; static const uint8_t ETH2_DEPOSIT_SELECTOR[SELECTOR_SIZE] = {0x22, 0x89, 0x51, 0x18};
const uint8_t* const ETH2_SELECTORS[NUM_ETH2_SELECTORS] = {ETH2_DEPOSIT_SELECTOR}; const uint8_t* const ETH2_SELECTORS[NUM_ETH2_SELECTORS] = {ETH2_DEPOSIT_SELECTOR};
@@ -47,39 +44,33 @@ const uint8_t* const ETH2_SELECTORS[NUM_ETH2_SELECTORS] = {ETH2_DEPOSIT_SELECTOR
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
static const uint8_t const STARKWARE_REGISTER_ID[SELECTOR_SIZE] = {0xdd, 0x24, 0x14, 0xd4}; static const uint8_t STARKWARE_REGISTER_ID[SELECTOR_SIZE] = {0xdd, 0x24, 0x14, 0xd4};
static const uint8_t const STARKWARE_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x25, 0x05, 0xc3, 0xd9}; static const uint8_t STARKWARE_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x25, 0x05, 0xc3, 0xd9};
static const uint8_t const STARKWARE_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x00, 0xae, 0xef, 0x8a}; static const uint8_t STARKWARE_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x00, 0xae, 0xef, 0x8a};
static const uint8_t const STARKWARE_DEPOSIT_CANCEL_ID[SELECTOR_SIZE] = {0x7d, 0xf7, 0xdc, 0x04}; static const uint8_t STARKWARE_DEPOSIT_CANCEL_ID[SELECTOR_SIZE] = {0x7d, 0xf7, 0xdc, 0x04};
static const uint8_t const STARKWARE_DEPOSIT_RECLAIM_ID[SELECTOR_SIZE] = {0xae, 0x87, 0x38, 0x16}; static const uint8_t STARKWARE_DEPOSIT_RECLAIM_ID[SELECTOR_SIZE] = {0xae, 0x87, 0x38, 0x16};
static const uint8_t const STARKWARE_WITHDRAW_ID[SELECTOR_SIZE] = {0x44, 0x1a, 0x3e, 0x70}; static const uint8_t STARKWARE_WITHDRAW_ID[SELECTOR_SIZE] = {0x44, 0x1a, 0x3e, 0x70};
static const uint8_t const STARKWARE_FULL_WITHDRAWAL_ID[SELECTOR_SIZE] = {0xa9, 0x33, 0x10, 0xc4}; static const uint8_t STARKWARE_FULL_WITHDRAWAL_ID[SELECTOR_SIZE] = {0xa9, 0x33, 0x10, 0xc4};
static const uint8_t const STARKWARE_FREEZE_ID[SELECTOR_SIZE] = {0x93, 0xc1, 0xe4, 0x66}; static const uint8_t STARKWARE_FREEZE_ID[SELECTOR_SIZE] = {0x93, 0xc1, 0xe4, 0x66};
static const uint8_t const STARKWARE_ESCAPE_ID[SELECTOR_SIZE] = {0x9e, 0x3a, 0xda, 0xc4}; static const uint8_t STARKWARE_ESCAPE_ID[SELECTOR_SIZE] = {0x9e, 0x3a, 0xda, 0xc4};
static const uint8_t const STARKWARE_VERIFY_ESCAPE_ID[SELECTOR_SIZE] = {0x2d, 0xd5, 0x30, 0x06}; static const uint8_t STARKWARE_VERIFY_ESCAPE_ID[SELECTOR_SIZE] = {0x2d, 0xd5, 0x30, 0x06};
static const uint8_t const STARKWARE_WITHDRAW_TO_ID[SELECTOR_SIZE] = {0x14, 0xcd, 0x70, 0xe4}; static const uint8_t STARKWARE_WITHDRAW_TO_ID[SELECTOR_SIZE] = {0x14, 0xcd, 0x70, 0xe4};
static const uint8_t const STARKWARE_DEPOSIT_NFT_ID[SELECTOR_SIZE] = {0xae, 0x1c, 0xdd, 0xe6}; static const uint8_t STARKWARE_DEPOSIT_NFT_ID[SELECTOR_SIZE] = {0xae, 0x1c, 0xdd, 0xe6};
static const uint8_t const STARKWARE_DEPOSIT_NFT_RECLAIM_ID[SELECTOR_SIZE] = {0xfc, static const uint8_t STARKWARE_DEPOSIT_NFT_RECLAIM_ID[SELECTOR_SIZE] = {0xfc, 0xb0, 0x58, 0x22};
0xb0, static const uint8_t STARKWARE_WITHDRAW_AND_MINT_ID[SELECTOR_SIZE] = {0xd9, 0x14, 0x43, 0xb7};
0x58, static const uint8_t STARKWARE_WITHDRAW_NFT_ID[SELECTOR_SIZE] = {0x01, 0x9b, 0x41, 0x7a};
0x22}; static const uint8_t STARKWARE_WITHDRAW_NFT_TO_ID[SELECTOR_SIZE] = {0xeb, 0xef, 0x0f, 0xd0};
static const uint8_t const STARKWARE_WITHDRAW_AND_MINT_ID[SELECTOR_SIZE] = {0xd9, 0x14, 0x43, 0xb7}; static const uint8_t STARKWARE_REGISTER_AND_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x10,
static const uint8_t const STARKWARE_WITHDRAW_NFT_ID[SELECTOR_SIZE] = {0x01, 0x9b, 0x41, 0x7a}; 0x82,
static const uint8_t const STARKWARE_WITHDRAW_NFT_TO_ID[SELECTOR_SIZE] = {0xeb, 0xef, 0x0f, 0xd0}; 0x08,
static const uint8_t const STARKWARE_REGISTER_AND_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x10, 0xcf};
0x82, static const uint8_t STARKWARE_REGISTER_AND_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0xa7,
0x08, 0x78,
0xcf}; 0xc0,
static const uint8_t const STARKWARE_REGISTER_AND_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0xa7, 0xc3};
0x78, static const uint8_t STARKWARE_PROXY_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0xdc, 0xca, 0xd5, 0x24};
0xc0, static const uint8_t STARKWARE_PROXY_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x6c, 0xe5, 0xd9, 0x57};
0xc3};
static const uint8_t const STARKWARE_PROXY_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0xdc,
0xca,
0xd5,
0x24};
static const uint8_t const STARKWARE_PROXY_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x6c, 0xe5, 0xd9, 0x57};
const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS] = { const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS] = {
STARKWARE_REGISTER_ID, STARKWARE_REGISTER_ID,
@@ -107,7 +98,7 @@ const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS] = {
// All internal alias names start with 'minus' // All internal alias names start with 'minus'
const internalEthPlugin_t const INTERNAL_ETH_PLUGINS[] = { const internalEthPlugin_t INTERNAL_ETH_PLUGINS[] = {
{erc20_plugin_available_check, {erc20_plugin_available_check,
(const uint8_t**) ERC20_SELECTORS, (const uint8_t**) ERC20_SELECTORS,
NUM_ERC20_SELECTORS, NUM_ERC20_SELECTORS,

View File

@@ -23,7 +23,9 @@ void plugin_ui_get_id() {
strings.tmp.tmp2, strings.tmp.tmp2,
sizeof(strings.tmp.tmp2)); sizeof(strings.tmp.tmp2));
// Query the original contract for ID if it's not an internal alias // Query the original contract for ID if it's not an internal alias
if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_ID, (void *) &pluginQueryContractID)) { eth_plugin_result_t status =
eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_ID, (void *) &pluginQueryContractID);
if (status != ETH_PLUGIN_RESULT_OK) {
PRINTF("Plugin query contract ID call failed\n"); PRINTF("Plugin query contract ID call failed\n");
io_seproxyhal_touch_tx_cancel(NULL); io_seproxyhal_touch_tx_cancel(NULL);
} }
@@ -37,8 +39,10 @@ void plugin_ui_get_item() {
sizeof(strings.tmp.tmp), sizeof(strings.tmp.tmp),
strings.tmp.tmp2, strings.tmp.tmp2,
sizeof(strings.tmp.tmp2)); sizeof(strings.tmp.tmp2));
if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_UI, (void *) &pluginQueryContractUI)) { eth_plugin_result_t status =
PRINTF("Plugin query contract UI call failed\n"); eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_UI, (void *) &pluginQueryContractUI);
if (status != ETH_PLUGIN_RESULT_OK) {
PRINTF("Plugin query contract UI call failed, got: %d\n", status);
io_seproxyhal_touch_tx_cancel(NULL); io_seproxyhal_touch_tx_cancel(NULL);
} }
} }

View File

@@ -93,28 +93,12 @@ void ui_idle(void) {
ux_flow_init(0, ux_idle_flow, NULL); ux_flow_init(0, ux_idle_flow, NULL);
} }
unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_exit(__attribute__((unused)) const bagl_element_t *e) {
// Go back to the dashboard // Go back to the dashboard
os_sched_exit(0); os_sched_exit(0);
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
#if defined(TARGET_NANOS)
unsigned int ui_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) {
switch (button_mask) {
case BUTTON_EVT_RELEASED | BUTTON_LEFT: // CANCEL
io_seproxyhal_touch_address_cancel(NULL);
break;
case BUTTON_EVT_RELEASED | BUTTON_RIGHT: { // OK
io_seproxyhal_touch_address_ok(NULL);
break;
}
}
return 0;
}
#endif // #if defined(TARGET_NANOS)
void io_seproxyhal_send_status(uint32_t sw) { void io_seproxyhal_send_status(uint32_t sw) {
G_io_apdu_buffer[0] = ((sw >> 8) & 0xff); G_io_apdu_buffer[0] = ((sw >> 8) & 0xff);
G_io_apdu_buffer[1] = (sw & 0xff); G_io_apdu_buffer[1] = (sw & 0xff);
@@ -392,13 +376,13 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) {
return NULL; return NULL;
} }
#ifndef HAVE_WALLET_ID_SDK
unsigned int const U_os_perso_seed_cookie[] = { unsigned int const U_os_perso_seed_cookie[] = {
0xda7aba5e, 0xda7aba5e,
0xc1a551c5, 0xc1a551c5,
}; };
#ifndef HAVE_WALLET_ID_SDK
void handleGetWalletId(volatile unsigned int *tx) { void handleGetWalletId(volatile unsigned int *tx) {
unsigned char t[64]; unsigned char t[64];
cx_ecfp_256_private_key_t priv; cx_ecfp_256_private_key_t priv;
@@ -416,7 +400,7 @@ void handleGetWalletId(volatile unsigned int *tx) {
THROW(0x9000); THROW(0x9000);
} }
#endif #endif // HAVE_WALLET_ID_SDK
void handleApdu(unsigned int *flags, unsigned int *tx) { void handleApdu(unsigned int *flags, unsigned int *tx) {
unsigned short sw = 0; unsigned short sw = 0;
@@ -431,7 +415,7 @@ void handleApdu(unsigned int *flags, unsigned int *tx) {
return; return;
} }
#endif #endif // HAVE_WALLET_ID_SDK
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
@@ -688,7 +672,7 @@ void io_seproxyhal_display(const bagl_element_t *element) {
io_seproxyhal_display_default((bagl_element_t *) element); io_seproxyhal_display_default((bagl_element_t *) element);
} }
unsigned char io_event(unsigned char channel) { unsigned char io_event(__attribute__((unused)) unsigned char channel) {
// nothing done with the event, throw an error on the transport layer if // nothing done with the event, throw an error on the transport layer if
// needed // needed

View File

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

View File

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

View File

@@ -43,7 +43,7 @@ extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
#ifndef HAVE_TOKENS_LIST #ifndef HAVE_TOKENS_LIST
#ifndef LEDGER_TEST_PUBLIC_KEY #ifndef LEDGER_TEST_PUBLIC_KEY
static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = { static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
// production key 2019-01-11 03:07PM (erc20signer) // production key 2019-01-11 03:07PM (erc20signer)
0x04, 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9, 0x04, 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9,
0x7c, 0x0b, 0x68, 0xcd, 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e, 0x7c, 0x0b, 0x68, 0xcd, 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e,
@@ -52,7 +52,7 @@ static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = {
0xcd, 0x09, 0x8f, 0xce, 0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83}; 0xcd, 0x09, 0x8f, 0xce, 0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83};
#else #else
static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = { static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = {
// test key 2019-01-11 03:07PM (erc20signer) // test key 2019-01-11 03:07PM (erc20signer)
0x04, 0x20, 0xda, 0x62, 0x00, 0x3c, 0x0c, 0xe0, 0x97, 0xe3, 0x36, 0x44, 0xa1, 0x04, 0x20, 0xda, 0x62, 0x00, 0x3c, 0x0c, 0xe0, 0x97, 0xe3, 0x36, 0x44, 0xa1,
0x0f, 0xe4, 0xc3, 0x04, 0x54, 0x06, 0x9a, 0x44, 0x54, 0xf0, 0xfa, 0x9d, 0x4e, 0x0f, 0xe4, 0xc3, 0x04, 0x54, 0x06, 0x9a, 0x44, 0x54, 0xf0, 0xfa, 0x9d, 0x4e,

View File

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

View File

@@ -411,7 +411,6 @@ static parserStatus_e parseRLP(txContext_t *context) {
} }
// Ready to process this field // Ready to process this field
if (!rlpDecodeLength(context->rlpBuffer, if (!rlpDecodeLength(context->rlpBuffer,
context->rlpBufferPos,
&context->currentFieldLength, &context->currentFieldLength,
&offset, &offset,
&context->currentFieldIsList)) { &context->currentFieldIsList)) {

View File

@@ -58,11 +58,7 @@ bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid) {
return true; return true;
} }
bool rlpDecodeLength(uint8_t *buffer, bool rlpDecodeLength(uint8_t *buffer, uint32_t *fieldLength, uint32_t *offset, bool *list) {
uint32_t bufferLength,
uint32_t *fieldLength,
uint32_t *offset,
bool *list) {
if (*buffer <= 0x7f) { if (*buffer <= 0x7f) {
*offset = 0; *offset = 0;
*fieldLength = 1; *fieldLength = 1;
@@ -128,7 +124,7 @@ 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,
uint8_t *out, char *out,
cx_sha3_t *sha3Context, cx_sha3_t *sha3Context,
chain_config_t *chain_config) { chain_config_t *chain_config) {
uint8_t hashAddress[INT256_LENGTH]; uint8_t hashAddress[INT256_LENGTH];

View File

@@ -26,7 +26,6 @@
* @brief Decode an RLP encoded field - see * @brief Decode an RLP encoded field - see
* https://github.com/ethereum/wiki/wiki/RLP * https://github.com/ethereum/wiki/wiki/RLP
* @param [in] buffer buffer containing the RLP encoded field to decode * @param [in] buffer buffer containing the RLP encoded field to decode
* @param [in] bufferLength size of the buffer
* @param [out] fieldLength length of the RLP encoded field * @param [out] fieldLength length of the RLP encoded field
* @param [out] offset offset to the beginning of the RLP encoded field from the * @param [out] offset offset to the beginning of the RLP encoded field from the
* buffer * buffer
@@ -34,18 +33,14 @@
* string * string
* @return true if the RLP header is consistent * @return true if the RLP header is consistent
*/ */
bool rlpDecodeLength(uint8_t *buffer, bool rlpDecodeLength(uint8_t *buffer, uint32_t *fieldLength, uint32_t *offset, bool *list);
uint32_t bufferLength,
uint32_t *fieldLength,
uint32_t *offset,
bool *list);
bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid); bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid);
void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, cx_sha3_t *sha3Context); void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, cx_sha3_t *sha3Context);
void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
uint8_t *out, char *out,
cx_sha3_t *sha3Context, cx_sha3_t *sha3Context,
chain_config_t *chain_config); chain_config_t *chain_config);

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

@@ -4,7 +4,7 @@
#include "feature_getEth2PublicKey.h" #include "feature_getEth2PublicKey.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
unsigned int io_seproxyhal_touch_eth2_address_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_eth2_address_ok(__attribute__((unused)) const bagl_element_t *e) {
uint32_t tx = set_result_get_eth2_publicKey(); uint32_t tx = set_result_get_eth2_publicKey();
G_io_apdu_buffer[tx++] = 0x90; G_io_apdu_buffer[tx++] = 0x90;
G_io_apdu_buffer[tx++] = 0x00; G_io_apdu_buffer[tx++] = 0x00;

View File

@@ -2,7 +2,7 @@
#include "feature_getPublicKey.h" #include "feature_getPublicKey.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_address_ok(__attribute__((unused)) const bagl_element_t *e) {
uint32_t tx = set_result_get_publicKey(); uint32_t tx = set_result_get_publicKey();
G_io_apdu_buffer[tx++] = 0x90; G_io_apdu_buffer[tx++] = 0x90;
G_io_apdu_buffer[tx++] = 0x00; G_io_apdu_buffer[tx++] = 0x00;
@@ -14,7 +14,7 @@ unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e) {
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_address_cancel(__attribute__((unused)) const bagl_element_t *e) {
G_io_apdu_buffer[0] = 0x69; G_io_apdu_buffer[0] = 0x69;
G_io_apdu_buffer[1] = 0x85; G_io_apdu_buffer[1] = 0x85;
reset_app_context(); reset_app_context();

View File

@@ -88,8 +88,10 @@ void handleProvideErc20TokenInformation(uint8_t p1,
32, 32,
workBuffer + offset, workBuffer + offset,
dataLength)) { dataLength)) {
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid token signature\n"); PRINTF("Invalid token signature\n");
THROW(0x6A80); THROW(0x6A80);
#endif
} }
tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1; tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1;
THROW(0x9000); THROW(0x9000);
@@ -102,7 +104,7 @@ void handleProvideErc20TokenInformation(uint8_t p1,
uint8_t *workBuffer, uint8_t *workBuffer,
uint16_t dataLength, uint16_t dataLength,
unsigned int *flags, unsigned int *flags,
unsigned int *tx) { __attribute__((unused)) unsigned int *tx) {
UNUSED(p1); UNUSED(p1);
UNUSED(p2); UNUSED(p2);
UNUSED(flags); UNUSED(flags);
@@ -175,8 +177,10 @@ void handleProvideErc20TokenInformation(uint8_t p1,
32, 32,
workBuffer + offset, workBuffer + offset,
dataLength)) { dataLength)) {
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid token signature\n"); PRINTF("Invalid token signature\n");
THROW(0x6A80); THROW(0x6A80);
#endif
} }
} }
@@ -193,8 +197,10 @@ void handleProvideErc20TokenInformation(uint8_t p1,
32, 32,
workBuffer + offset, workBuffer + offset,
dataLength)) { dataLength)) {
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid token signature\n"); PRINTF("Invalid token signature\n");
THROW(0x6A80); THROW(0x6A80);
#endif
} }
#endif #endif

View File

@@ -7,8 +7,8 @@ void handleSetEth2WithdrawalIndex(uint8_t p1,
uint8_t p2, uint8_t p2,
uint8_t *dataBuffer, uint8_t *dataBuffer,
uint16_t dataLength, uint16_t dataLength,
unsigned int *flags, __attribute__((unused)) unsigned int *flags,
unsigned int *tx) { __attribute__((unused)) unsigned int *tx) {
if (dataLength != 4) { if (dataLength != 4) {
THROW(0x6700); THROW(0x6700);
} }

View File

@@ -3,8 +3,7 @@
#include "ui_flow.h" #include "ui_flow.h"
#include "tokens.h" #include "tokens.h"
#define CONTRACT_ADDR_SIZE 20 #define SELECTOR_SIZE 4
#define SELECTOR_SIZE 4
void handleSetExternalPlugin(uint8_t p1, void handleSetExternalPlugin(uint8_t p1,
uint8_t p2, uint8_t p2,
@@ -19,7 +18,7 @@ void handleSetExternalPlugin(uint8_t p1,
uint8_t hash[32]; uint8_t hash[32];
cx_ecfp_public_key_t tokenKey; cx_ecfp_public_key_t tokenKey;
uint8_t pluginNameLength = *workBuffer; uint8_t pluginNameLength = *workBuffer;
const size_t payload_size = 1 + pluginNameLength + CONTRACT_ADDR_SIZE + SELECTOR_SIZE; const size_t payload_size = 1 + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE;
if (dataLength <= payload_size) { if (dataLength <= payload_size) {
THROW(0x6A80); THROW(0x6A80);
@@ -43,7 +42,9 @@ void handleSetExternalPlugin(uint8_t p1,
workBuffer + payload_size, workBuffer + payload_size,
dataLength - payload_size)) { dataLength - payload_size)) {
PRINTF("Invalid external plugin signature %.*H\n", payload_size, workBuffer); PRINTF("Invalid external plugin signature %.*H\n", payload_size, workBuffer);
#ifndef HAVE_BYPASS_SIGNATURES
THROW(0x6A80); THROW(0x6A80);
#endif
} }
// move on to the rest of the payload parsing // move on to the rest of the payload parsing
@@ -65,8 +66,8 @@ void handleSetExternalPlugin(uint8_t p1,
CATCH_OTHER(e) { CATCH_OTHER(e) {
PRINTF("%s external plugin is not present\n", dataContext.tokenContext.pluginName); PRINTF("%s external plugin is not present\n", dataContext.tokenContext.pluginName);
memset(dataContext.tokenContext.pluginName, memset(dataContext.tokenContext.pluginName,
sizeof(dataContext.tokenContext.pluginName), 0,
0); sizeof(dataContext.tokenContext.pluginName));
THROW(0x6984); THROW(0x6984);
} }
FINALLY { FINALLY {
@@ -76,8 +77,8 @@ void handleSetExternalPlugin(uint8_t p1,
PRINTF("Plugin found\n"); PRINTF("Plugin found\n");
memmove(dataContext.tokenContext.contract_address, workBuffer, CONTRACT_ADDR_SIZE); memmove(dataContext.tokenContext.contract_address, workBuffer, ADDRESS_LENGTH);
workBuffer += 20; workBuffer += ADDRESS_LENGTH;
memmove(dataContext.tokenContext.method_selector, workBuffer, SELECTOR_SIZE); memmove(dataContext.tokenContext.method_selector, workBuffer, SELECTOR_SIZE);
externalPluginIsSet = true; externalPluginIsSet = true;

View File

@@ -3,7 +3,7 @@
#include "utils.h" #include "utils.h"
#include "ui_flow.h" #include "ui_flow.h"
static const char const SIGN_MAGIC[] = static const char SIGN_MAGIC[] =
"\x19" "\x19"
"Ethereum Signed Message:\n"; "Ethereum Signed Message:\n";

View File

@@ -1,7 +1,7 @@
#include "shared_context.h" #include "shared_context.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_signMessage_ok(__attribute__((unused)) const bagl_element_t *e) {
uint8_t privateKeyData[INT256_LENGTH]; uint8_t privateKeyData[INT256_LENGTH];
uint8_t signature[100]; uint8_t signature[100];
uint8_t signatureLength; uint8_t signatureLength;
@@ -46,7 +46,8 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) {
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_signMessage_cancel(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_signMessage_cancel(__attribute__((unused))
const bagl_element_t *e) {
reset_app_context(); reset_app_context();
G_io_apdu_buffer[0] = 0x69; G_io_apdu_buffer[0] = 0x69;
G_io_apdu_buffer[1] = 0x85; G_io_apdu_buffer[1] = 0x85;

View File

@@ -1,9 +1,10 @@
#include "shared_context.h" #include "shared_context.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
static const uint8_t const EIP_712_MAGIC[] = {0x19, 0x01}; static const uint8_t EIP_712_MAGIC[] = {0x19, 0x01};
unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_signMessage712_v0_ok(__attribute__((unused))
const bagl_element_t *e) {
uint8_t privateKeyData[INT256_LENGTH]; uint8_t privateKeyData[INT256_LENGTH];
uint8_t hash[INT256_LENGTH]; uint8_t hash[INT256_LENGTH];
uint8_t signature[100]; uint8_t signature[100];
@@ -70,7 +71,8 @@ unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) {
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_signMessage712_v0_cancel(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_signMessage712_v0_cancel(__attribute__((unused))
const bagl_element_t *e) {
reset_app_context(); reset_app_context();
G_io_apdu_buffer[0] = 0x69; G_io_apdu_buffer[0] = 0x69;
G_io_apdu_buffer[1] = 0x85; G_io_apdu_buffer[1] = 0x85;

View File

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

View File

@@ -2,10 +2,12 @@
#include "utils.h" #include "utils.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
#include "ui_flow.h" #include "ui_flow.h"
#include "feature_signTx.h"
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
#include "stark_utils.h" #include "stark_utils.h"
#endif #endif
#include "eth_plugin_handler.h" #include "eth_plugin_handler.h"
#include "network.h"
#define ERR_SILENT_MODE_CHECK_FAILED 0x6001 #define ERR_SILENT_MODE_CHECK_FAILED 0x6001
@@ -195,7 +197,7 @@ void reportFinalizeError(bool direct) {
void computeFees(char *displayBuffer, uint32_t displayBufferSize) { void computeFees(char *displayBuffer, uint32_t displayBufferSize) {
uint256_t gasPrice, startGas, uint256; uint256_t gasPrice, startGas, uint256;
uint8_t *feeTicker = (uint8_t *) PIC(chainConfig->coinName); char *feeTicker = get_network_ticker();
uint8_t tickerOffset = 0; uint8_t tickerOffset = 0;
uint32_t i; uint32_t i;
@@ -237,28 +239,37 @@ void computeFees(char *displayBuffer, uint32_t displayBufferSize) {
displayBuffer[tickerOffset + i] = '\0'; displayBuffer[tickerOffset + i] = '\0';
} }
static void get_public_key(uint8_t *out, uint8_t outLength) {
uint8_t privateKeyData[INT256_LENGTH] = {0};
cx_ecfp_private_key_t privateKey = {0};
cx_ecfp_public_key_t publicKey = {0};
if (outLength < ADDRESS_LENGTH) {
return;
}
os_perso_derive_node_bip32(CX_CURVE_256K1,
tmpCtx.transactionContext.bip32Path,
tmpCtx.transactionContext.pathLength,
privateKeyData,
NULL);
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
cx_ecfp_generate_pair(CX_CURVE_256K1, &publicKey, &privateKey, 1);
explicit_bzero(&privateKey, sizeof(privateKey));
explicit_bzero(privateKeyData, sizeof(privateKeyData));
getEthAddressFromKey(&publicKey, out, &global_sha3);
}
void finalizeParsing(bool direct) { void finalizeParsing(bool direct) {
char displayBuffer[50]; char displayBuffer[50];
uint8_t decimals = WEI_TO_ETHER; uint8_t decimals = WEI_TO_ETHER;
uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName); char *ticker = get_network_ticker();
ethPluginFinalize_t pluginFinalize; ethPluginFinalize_t pluginFinalize;
tokenDefinition_t *token1 = NULL, *token2 = NULL;
bool genericUI = true; bool genericUI = true;
// Verify the chain // Verify the chain
if (chainConfig->chainId != 0) { if (chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) {
uint32_t id = 0; uint32_t id = get_chain_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 checking for chainID\n", txContext.txType);
return;
}
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);
@@ -281,6 +292,11 @@ void finalizeParsing(bool direct) {
if (dataContext.tokenContext.pluginStatus >= ETH_PLUGIN_RESULT_SUCCESSFUL) { if (dataContext.tokenContext.pluginStatus >= ETH_PLUGIN_RESULT_SUCCESSFUL) {
genericUI = false; genericUI = false;
eth_plugin_prepare_finalize(&pluginFinalize); eth_plugin_prepare_finalize(&pluginFinalize);
uint8_t msg_sender[ADDRESS_LENGTH] = {0};
get_public_key(msg_sender, sizeof(msg_sender));
pluginFinalize.address = msg_sender;
if (!eth_plugin_call(ETH_PLUGIN_FINALIZE, (void *) &pluginFinalize)) { if (!eth_plugin_call(ETH_PLUGIN_FINALIZE, (void *) &pluginFinalize)) {
PRINTF("Plugin finalize call failed\n"); PRINTF("Plugin finalize call failed\n");
reportFinalizeError(direct); reportFinalizeError(direct);
@@ -290,22 +306,22 @@ void finalizeParsing(bool direct) {
} }
// Lookup tokens if requested // Lookup tokens if requested
ethPluginProvideToken_t pluginProvideToken; ethPluginProvideToken_t pluginProvideToken;
eth_plugin_prepare_provide_token(&pluginProvideToken);
if ((pluginFinalize.tokenLookup1 != NULL) || (pluginFinalize.tokenLookup2 != NULL)) { if ((pluginFinalize.tokenLookup1 != NULL) || (pluginFinalize.tokenLookup2 != NULL)) {
if (pluginFinalize.tokenLookup1 != NULL) { if (pluginFinalize.tokenLookup1 != NULL) {
PRINTF("Lookup1: %.*H\n", ADDRESS_LENGTH, pluginFinalize.tokenLookup1); PRINTF("Lookup1: %.*H\n", ADDRESS_LENGTH, pluginFinalize.tokenLookup1);
token1 = getKnownToken(pluginFinalize.tokenLookup1); pluginProvideToken.token1 = getKnownToken(pluginFinalize.tokenLookup1);
if (token1 != NULL) { if (pluginProvideToken.token1 != NULL) {
PRINTF("Token1 ticker: %s\n", token1->ticker); PRINTF("Token1 ticker: %s\n", pluginProvideToken.token1->ticker);
} }
} }
if (pluginFinalize.tokenLookup2 != NULL) { if (pluginFinalize.tokenLookup2 != NULL) {
PRINTF("Lookup2: %.*H\n", ADDRESS_LENGTH, pluginFinalize.tokenLookup2); PRINTF("Lookup2: %.*H\n", ADDRESS_LENGTH, pluginFinalize.tokenLookup2);
token2 = getKnownToken(pluginFinalize.tokenLookup2); pluginProvideToken.token2 = getKnownToken(pluginFinalize.tokenLookup2);
if (token2 != NULL) { if (pluginProvideToken.token2 != NULL) {
PRINTF("Token2 ticker: %s\n", token2->ticker); PRINTF("Token2 ticker: %s\n", pluginProvideToken.token2->ticker);
} }
} }
eth_plugin_prepare_provide_token(&pluginProvideToken, token1, token2);
if (eth_plugin_call(ETH_PLUGIN_PROVIDE_TOKEN, (void *) &pluginProvideToken) <= if (eth_plugin_call(ETH_PLUGIN_PROVIDE_TOKEN, (void *) &pluginProvideToken) <=
ETH_PLUGIN_RESULT_UNSUCCESSFUL) { ETH_PLUGIN_RESULT_UNSUCCESSFUL) {
PRINTF("Plugin provide token call failed\n"); PRINTF("Plugin provide token call failed\n");
@@ -340,9 +356,9 @@ void finalizeParsing(bool direct) {
tmpContent.txContent.value.length = 32; tmpContent.txContent.value.length = 32;
memmove(tmpContent.txContent.destination, pluginFinalize.address, 20); memmove(tmpContent.txContent.destination, pluginFinalize.address, 20);
tmpContent.txContent.destinationLength = 20; tmpContent.txContent.destinationLength = 20;
if (token1 != NULL) { if (pluginProvideToken.token1 != NULL) {
decimals = token1->decimals; decimals = pluginProvideToken.token1->decimals;
ticker = token1->ticker; ticker = (char *) pluginProvideToken.token1->ticker;
} }
break; break;
default: default:
@@ -404,26 +420,22 @@ void finalizeParsing(bool direct) {
// Prepare chainID field // Prepare chainID field
if (genericUI) { if (genericUI) {
if (txContext.txType == LEGACY) { char *name = get_network_name();
uint32_t id = u32_from_BE(txContext.content->v, txContext.content->vLength, true); if (name == NULL) {
PRINTF("Chain ID: %u\n", id); // No network name found so simply copy the chain ID as the network name.
uint8_t res = uint32_t chain_id = get_chain_id();
snprintf(strings.common.chainID, sizeof(strings.common.chainID), "%d", id); uint8_t res = snprintf(strings.common.network_name,
if (res >= sizeof(strings.common.chainID)) { 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 // 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. // the output was truncated. Return the appropriate error code.
THROW(0x6502); 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 { } else {
PRINTF("Txtype `%u` not supported while generating chainID\n", txContext.txType); // Network name found, simply copy it.
return; strncpy(strings.common.network_name, name, sizeof(strings.common.network_name));
} }
} }

View File

@@ -2,7 +2,7 @@
#include "utils.h" #include "utils.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_tx_ok(__attribute__((unused)) const bagl_element_t *e) {
uint8_t privateKeyData[INT256_LENGTH]; uint8_t privateKeyData[INT256_LENGTH];
uint8_t signature[100]; uint8_t signature[100];
uint8_t signatureLength; uint8_t signatureLength;
@@ -58,7 +58,7 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_tx_cancel(__attribute__((unused)) const bagl_element_t *e) {
reset_app_context(); reset_app_context();
G_io_apdu_buffer[0] = 0x69; G_io_apdu_buffer[0] = 0x69;
G_io_apdu_buffer[1] = 0x85; G_io_apdu_buffer[1] = 0x85;
@@ -69,7 +69,7 @@ unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) {
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_data_ok(__attribute__((unused)) const bagl_element_t *e) {
parserStatus_e txResult = USTREAM_FINISHED; parserStatus_e txResult = USTREAM_FINISHED;
txResult = continueTx(&txContext); txResult = continueTx(&txContext);
switch (txResult) { switch (txResult) {
@@ -100,7 +100,7 @@ unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) {
return 0; return 0;
} }
unsigned int io_seproxyhal_touch_data_cancel(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_data_cancel(__attribute__((unused)) const bagl_element_t *e) {
reset_app_context(); reset_app_context();
io_seproxyhal_send_status(0x6985); io_seproxyhal_send_status(0x6985);
// Display back the original UX // Display back the original UX

View File

@@ -2,6 +2,8 @@
#include "ui_callbacks.h" #include "ui_callbacks.h"
#include "chainConfig.h" #include "chainConfig.h"
#include "utils.h" #include "utils.h"
#include "feature_signTx.h"
#include "network.h"
// clang-format off // clang-format off
UX_STEP_NOCB( UX_STEP_NOCB(
@@ -116,11 +118,11 @@ UX_STEP_NOCB(
.text = strings.common.maxFee, .text = strings.common.maxFee,
}); });
UX_STEP_NOCB( UX_STEP_NOCB(
ux_approval_chainid_step, ux_approval_network_step,
bnnn_paging, bnnn_paging,
{ {
.title = "Chain ID", .title = "Network",
.text = strings.common.chainID, .text = strings.common.network_name,
}); });
UX_STEP_CB( UX_STEP_CB(
ux_approval_accept_step, ux_approval_accept_step,
@@ -171,18 +173,9 @@ void ux_approve_tx(bool dataPresent) {
ux_approval_tx_flow_[step++] = &ux_approval_nonce_step; ux_approval_tx_flow_[step++] = &ux_approval_nonce_step;
} }
uint32_t id; uint32_t chain_id = get_chain_id();
if (txContext.txType == LEGACY) { if (chainConfig->chainId == ETHEREUM_MAINNET_CHAINID && chain_id != chainConfig->chainId) {
id = u32_from_BE(txContext.content->v, txContext.content->vLength, true); ux_approval_tx_flow_[step++] = &ux_approval_network_step;
} 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;
} }
ux_approval_tx_flow_[step++] = &ux_approval_fees_step; ux_approval_tx_flow_[step++] = &ux_approval_fees_step;
ux_approval_tx_flow_[step++] = &ux_approval_accept_step; ux_approval_tx_flow_[step++] = &ux_approval_accept_step;

View File

@@ -4,7 +4,7 @@
#include "ui_callbacks.h" #include "ui_callbacks.h"
#include "feature_stark_getPublicKey.h" #include "feature_stark_getPublicKey.h"
unsigned int io_seproxyhal_touch_stark_pubkey_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_stark_pubkey_ok(__attribute__((unused)) const bagl_element_t *e) {
uint32_t tx = set_result_get_stark_publicKey(); uint32_t tx = set_result_get_stark_publicKey();
G_io_apdu_buffer[tx++] = 0x90; G_io_apdu_buffer[tx++] = 0x90;
G_io_apdu_buffer[tx++] = 0x00; G_io_apdu_buffer[tx++] = 0x00;

View File

@@ -5,11 +5,11 @@
#include "ui_flow.h" #include "ui_flow.h"
void handleStarkwareProvideQuantum(uint8_t p1, void handleStarkwareProvideQuantum(uint8_t p1,
uint8_t p2, __attribute__((unused)) uint8_t p2,
uint8_t *dataBuffer, uint8_t *dataBuffer,
uint16_t dataLength, uint16_t dataLength,
unsigned int *flags, __attribute__((unused)) unsigned int *flags,
unsigned int *tx) { __attribute__((unused)) unsigned int *tx) {
size_t i = 0; size_t i = 0;
uint8_t expectedDataSize = 20 + 32; uint8_t expectedDataSize = 20 + 32;
uint8_t addressZero = 0; uint8_t addressZero = 0;

View File

@@ -16,7 +16,7 @@ void handleStarkwareSignMessage(uint8_t p1,
uint8_t *dataBuffer, uint8_t *dataBuffer,
uint16_t dataLength, uint16_t dataLength,
unsigned int *flags, unsigned int *flags,
unsigned int *tx) { __attribute__((unused)) unsigned int *tx) {
uint8_t privateKeyData[INT256_LENGTH]; uint8_t privateKeyData[INT256_LENGTH];
uint32_t i; uint32_t i;
uint8_t bip32PathLength = *(dataBuffer); uint8_t bip32PathLength = *(dataBuffer);

View File

@@ -4,7 +4,7 @@
#include "stark_utils.h" #include "stark_utils.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
unsigned int io_seproxyhal_touch_stark_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_stark_ok(__attribute__((unused)) const bagl_element_t *e) {
uint8_t privateKeyData[32]; uint8_t privateKeyData[32];
uint8_t signature[72]; uint8_t signature[72];
uint32_t tx = 0; uint32_t tx = 0;

View File

@@ -11,7 +11,7 @@ void handleStarkwareUnsafeSign(uint8_t p1,
uint8_t *dataBuffer, uint8_t *dataBuffer,
uint16_t dataLength, uint16_t dataLength,
unsigned int *flags, unsigned int *flags,
unsigned int *tx) { __attribute__((unused)) unsigned int *tx) {
uint32_t i; uint32_t i;
uint8_t privateKeyData[INT256_LENGTH]; uint8_t privateKeyData[INT256_LENGTH];
cx_ecfp_public_key_t publicKey; cx_ecfp_public_key_t publicKey;

View File

@@ -4,7 +4,8 @@
#include "stark_utils.h" #include "stark_utils.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(__attribute__((unused))
const bagl_element_t *e) {
cx_ecfp_private_key_t privateKey; cx_ecfp_private_key_t privateKey;
uint8_t privateKeyData[INT256_LENGTH]; uint8_t privateKeyData[INT256_LENGTH];
uint8_t signature[72]; uint8_t signature[72];

View File

@@ -43,7 +43,7 @@ typedef struct underlying_asset_decimals_t {
the cToken decimals. Therefore, we hardcode a binding table. If Compound adds a lot of token in the the cToken decimals. Therefore, we hardcode a binding table. If Compound adds a lot of token in the
future, we will have to move to a CAL based architecture instead, as this one doesn't scale well.*/ future, we will have to move to a CAL based architecture instead, as this one doesn't scale well.*/
#define NUM_COMPOUND_BINDINGS 9 #define NUM_COMPOUND_BINDINGS 9
const underlying_asset_decimals_t const UNDERLYING_ASSET_DECIMALS[NUM_COMPOUND_BINDINGS] = { const underlying_asset_decimals_t UNDERLYING_ASSET_DECIMALS[NUM_COMPOUND_BINDINGS] = {
{"cDAI", 18}, {"cDAI", 18},
{"CETH", 18}, {"CETH", 18},
{"CUSDC", 6}, {"CUSDC", 6},

View File

@@ -27,8 +27,8 @@ typedef struct contract_t {
uint8_t address[ADDRESS_LENGTH]; uint8_t address[ADDRESS_LENGTH];
} contract_t; } contract_t;
#define NUM_CONTRACTS 11 #define NUM_CONTRACTS 13
const contract_t const CONTRACTS[NUM_CONTRACTS] = { const contract_t CONTRACTS[NUM_CONTRACTS] = {
// Compound // Compound
{"Compound DAI", {0x5d, 0x3a, 0x53, 0x6e, 0x4d, 0x6d, 0xbd, 0x61, 0x14, 0xcc, {"Compound DAI", {0x5d, 0x3a, 0x53, 0x6e, 0x4d, 0x6d, 0xbd, 0x61, 0x14, 0xcc,
0x1e, 0xad, 0x35, 0x77, 0x7b, 0xab, 0x94, 0x8e, 0x36, 0x43}}, 0x1e, 0xad, 0x35, 0x77, 0x7b, 0xab, 0x94, 0x8e, 0x36, 0x43}},
@@ -52,7 +52,15 @@ const contract_t const CONTRACTS[NUM_CONTRACTS] = {
0x48, 0x73, 0xd0, 0x0f, 0xf8, 0x5b, 0xcc, 0xde, 0xd5, 0x50}}, 0x48, 0x73, 0xd0, 0x0f, 0xf8, 0x5b, 0xcc, 0xde, 0xd5, 0x50}},
// Paraswap // Paraswap
{"Paraswap", {0x1b, 0xd4, 0x35, 0xf3, 0xc0, 0x54, 0xb6, 0xe9, 0x01, 0xb7, {"Paraswap", {0x1b, 0xd4, 0x35, 0xf3, 0xc0, 0x54, 0xb6, 0xe9, 0x01, 0xb7,
0xb1, 0x08, 0xa0, 0xab, 0x76, 0x17, 0xc8, 0x08, 0x67, 0x7b}}}; 0xb1, 0x08, 0xa0, 0xab, 0x76, 0x17, 0xc8, 0x08, 0x67, 0x7b}},
// stETH
{"Lido", {0x7f, 0x39, 0xc5, 0x81, 0xf5, 0x95, 0xb5, 0x3c, 0x5c, 0xb1,
0x9b, 0xd0, 0xb3, 0xf8, 0xda, 0x6c, 0x93, 0x5e, 0x2c, 0xa0}},
// wstETH
{"Wrapped stETH", {0xae, 0x7a, 0xb9, 0x65, 0x20, 0xde, 0x3a, 0x18, 0xe5, 0xe1,
0x11, 0xb5, 0xea, 0xab, 0x09, 0x53, 0x12, 0xd7, 0xfe, 0x84}}};
bool check_contract(erc20_parameters_t *context) { bool check_contract(erc20_parameters_t *context) {
for (size_t i = 0; i < NUM_CONTRACTS; i++) { for (size_t i = 0; i < NUM_CONTRACTS; i++) {

View File

@@ -32,14 +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;
static void to_lowercase(char *str, unsigned char size) {
for (unsigned char i = 0; i < size && str[i] != 0; i++) {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] += 'a' - 'A';
}
}
}
// Fills the `out` buffer with the lowercase string representation of the pubkey passed in as binary // 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 // 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). // representation. Returns the length of string (counting the null terminating character).
@@ -217,12 +209,12 @@ void eth2_plugin_call(int message, void *parameters) {
switch (msg->screenIndex) { switch (msg->screenIndex) {
case 0: { // Amount screen case 0: { // Amount screen
uint8_t decimals = WEI_TO_ETHER; uint8_t decimals = WEI_TO_ETHER;
uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName); char *ticker = chainConfig->coinName;
strcpy(msg->title, "Amount"); strcpy(msg->title, "Amount");
amountToString(tmpContent.txContent.value.value, amountToString(tmpContent.txContent.value.value,
tmpContent.txContent.value.length, tmpContent.txContent.value.length,
decimals, decimals,
(char *) ticker, ticker,
msg->msg, msg->msg,
100); 100);
msg->result = ETH_PLUGIN_RESULT_OK; 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) { void starkware_print_amount(uint8_t *amountData, char *destination, bool forEscape) {
uint256_t amount, amountPre, quantum; uint256_t amount, amountPre, quantum;
uint8_t decimals; uint8_t decimals;
char *ticker = (char *) PIC(chainConfig->coinName); char *ticker = chainConfig->coinName;
if ((amountData == NULL) || if ((amountData == NULL) ||
(forEscape && (dataContext.tokenContext.quantumIndex == MAX_TOKEN))) { (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 // TODO : rewrite as independant code
void starkware_print_ticker(char *destination) { void starkware_print_ticker(char *destination) {
char *ticker = (char *) PIC(chainConfig->coinName); char *ticker = chainConfig->coinName;
if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) { if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) {
tokenDefinition_t *token = tokenDefinition_t *token =

Binary file not shown.

Binary file not shown.

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

@@ -18,11 +18,21 @@ const Resolve = require("path").resolve;
const NANOS_ELF_PATH = Resolve("elfs/ethereum_nanos.elf"); const NANOS_ELF_PATH = Resolve("elfs/ethereum_nanos.elf");
const NANOX_ELF_PATH = Resolve("elfs/ethereum_nanox.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; const TIMEOUT = 1000000;
module.exports = { module.exports = {
NANOS_ELF_PATH, NANOS_ELF_PATH,
NANOX_ELF_PATH, NANOX_ELF_PATH,
NANOS_ETH_LIB,
NANOX_ETH_LIB,
NANOS_CLONE_ELF_PATH,
NANOX_CLONE_ELF_PATH,
sim_options_nanos, sim_options_nanos,
sim_options_nanox, sim_options_nanox,
TIMEOUT, 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_NANOS = SNAPSHOT_PATH_PREFIX + "nanos/";
const SNAPSHOT_PATH_NANOX = SNAPSHOT_PATH_PREFIX + "nanox/"; const SNAPSHOT_PATH_NANOX = SNAPSHOT_PATH_PREFIX + "nanox/";
test("Transfer nanos", async () => { test("Transfer Ether on Ethereum app nanos", async () => {
jest.setTimeout(TIMEOUT); jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOS_ELF_PATH); 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); jest.setTimeout(TIMEOUT);
const sim = new Zemu(NANOX_ELF_PATH); const sim = new Zemu(NANOX_ELF_PATH);
@@ -164,4 +260,73 @@ test("Transfer nanox", async () => {
} finally { } finally {
await sim.close(); 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); const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
expect(address_3).toEqual(expected_address_3); expect(address_3).toEqual(expected_address_3);
// Chain ID // Network name
filename = "chainid.png"; filename = "network.png";
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename); await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename); const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
const expected_chainid = Zemu.LoadPng2RGB(ORIGINAL_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); const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
expect(address).toEqual(expected_address); expect(address).toEqual(expected_address);
// Chain ID // Network name
filename = "chainid.png"; filename = "network.png";
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename); await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename); const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
const expected_chainid = Zemu.LoadPng2RGB(ORIGINAL_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();
}
});