Merge branch 'master' into support_eip1559
114
.github/workflows/ci-workflow.yml
vendored
@@ -3,18 +3,18 @@ name: Compilation & tests
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- master
|
||||
|
||||
jobs:
|
||||
job_build_debug:
|
||||
name: Build debug
|
||||
job_build_debug_nano_s:
|
||||
name: Build debug Nano S
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
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:
|
||||
- name: Clone
|
||||
@@ -24,21 +24,113 @@ jobs:
|
||||
|
||||
- name: Build an altcoin
|
||||
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
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ethereum-classic-app-debug
|
||||
path: bin
|
||||
name: ethereum_classic_nanos
|
||||
path: ./ethereum_classic_nanos.elf
|
||||
|
||||
- name: Build Ethereum
|
||||
run: |
|
||||
make clean
|
||||
make DEBUG=1
|
||||
make DEBUG=1 ALLOW_DATA=1
|
||||
mv bin/app.elf ethereum_nanos.elf
|
||||
|
||||
- name: Upload app binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ethereum-app-debug
|
||||
path: bin
|
||||
name: ethereum_nanos
|
||||
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
|
||||
|
||||
scan-build:
|
||||
name: Clang Static Analyzer
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Build with Clang Static Analyzer
|
||||
run: |
|
||||
make clean
|
||||
scan-build --use-cc=clang -analyze-headers -enable-checker security -enable-checker unix -enable-checker valist -o scan-build --status-bugs make default
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: scan-build
|
||||
path: scan-build
|
||||
|
||||
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
|
||||
|
||||
35
.github/workflows/e2e-tests.yml
vendored
@@ -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
|
||||
2
.gitignore
vendored
@@ -15,3 +15,5 @@ tests/node_modules
|
||||
tests/lib
|
||||
tests/yarn-error.log
|
||||
|
||||
|
||||
.vscode
|
||||
|
||||
53
CHANGELOG.md
@@ -5,43 +5,72 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [1.8.8](https://github.com/ledgerhq/app-ethereum/compare/1.8.7...1.8.8) - 2021-7-21
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for BSC.
|
||||
- Add support for Lido plugin
|
||||
|
||||
## [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
|
||||
|
||||
### Added
|
||||
|
||||
Added support for external plugins.
|
||||
- Added support for external plugins.
|
||||
|
||||
## [1.7.9](https://github.com/ledgerhq/app-ethereum/compare/1.7.8...1.7.9) - 2021-6-2
|
||||
|
||||
### Added
|
||||
|
||||
Added support for Flare Network and Theta Chain.
|
||||
- Added support for Flare Network and Theta Chain.
|
||||
|
||||
## [1.7.8](https://github.com/ledgerhq/app-ethereum/compare/1.7.7...1.7.8) - 2021-5-20
|
||||
|
||||
### Fixed
|
||||
|
||||
Fixed a bug where transaction would sometimes not get properly signed.
|
||||
- Fixed a bug where transaction would sometimes not get properly signed.
|
||||
|
||||
## [1.7.7](https://github.com/ledgerhq/app-ethereum/compare/1.7.6...1.7.7) - 2021-5-19
|
||||
|
||||
### Special
|
||||
|
||||
Version bump needed for deployment reasons, nothing changed.
|
||||
- Version bump needed for deployment reasons, nothing changed.
|
||||
|
||||
## [1.7.6](https://github.com/ledgerhq/app-ethereum/compare/1.7.5...1.7.6) - 2021-5-14
|
||||
|
||||
### Special
|
||||
|
||||
Version bump needed for deployment reasons, nothing changed.
|
||||
- Version bump needed for deployment reasons, nothing changed.
|
||||
|
||||
## [1.7.7](https://github.com/ledgerhq/app-ethereum/compare/1.7.6...1.7.7) - 2021-5-19
|
||||
|
||||
N/A
|
||||
- N/A
|
||||
|
||||
## [1.7.6](https://github.com/ledgerhq/app-ethereum/compare/1.7.6...1.7.6) - 2021-5-14
|
||||
|
||||
N/A
|
||||
- N/A
|
||||
|
||||
## [1.7.5](https://github.com/ledgerhq/app-ethereum/compare/1.7.4...1.7.5) - 2021-5-10
|
||||
|
||||
@@ -66,9 +95,9 @@ N/A
|
||||
### Added
|
||||
|
||||
- Improve Ethereum 2 deposit security:
|
||||
- Display the validator address on screen when depositing.
|
||||
- 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.
|
||||
- Display the validator address on screen when depositing.
|
||||
- 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.
|
||||
|
||||
## [1.7.1](https://github.com/ledgerhq/app-ethereum/compare/1.7.0...1.7.1) - 2021-5-5
|
||||
|
||||
@@ -76,21 +105,25 @@ N/A
|
||||
|
||||
- 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)
|
||||
|
||||
## [1.7.0](https://github.com/ledgerhq/app-ethereum/compare/1.6.6...1.7.0) - 2021-4-30
|
||||
|
||||
### Added
|
||||
|
||||
- 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
|
||||
|
||||
### Added
|
||||
|
||||
- Improved Starkware support
|
||||
|
||||
## [1.6.5](https://github.com/ledgerhq/app-ethereum/compare/1.6.4...1.6.5) - 2021-2-12
|
||||
|
||||
### Added
|
||||
|
||||
- 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
|
||||
|
||||
### Fixed
|
||||
|
||||
21
Makefile
@@ -30,7 +30,7 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'"
|
||||
|
||||
APPVERSION_M=1
|
||||
APPVERSION_N=8
|
||||
APPVERSION_P=5
|
||||
APPVERSION_P=8
|
||||
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
|
||||
APP_LOAD_FLAGS= --appFlags 0x240 --dep Ethereum:$(APPVERSION)
|
||||
|
||||
@@ -41,7 +41,7 @@ endif
|
||||
ifeq ($(CHAIN),ethereum)
|
||||
# Lock the application on its standard path for 1.5. Please complain if non compliant
|
||||
APP_LOAD_PARAMS += --path "44'/60'"
|
||||
DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAIN_KIND=CHAIN_KIND_ETHEREUM CHAIN_ID=0
|
||||
DEFINES += CHAINID_UPCASE=\"ETHEREUM\" CHAINID_COINNAME=\"ETH\" CHAIN_KIND=CHAIN_KIND_ETHEREUM CHAIN_ID=1
|
||||
# Starkware integration
|
||||
APP_LOAD_PARAMS += --path "2645'/579218131'"
|
||||
DEFINES += HAVE_STARKWARE
|
||||
@@ -197,9 +197,13 @@ APP_LOAD_PARAMS += --path "44'/554'" --path "44'/60'"
|
||||
DEFINES += CHAINID_UPCASE=\"FLARE\" CHAINID_COINNAME=\"FLR\" CHAIN_KIND=CHAIN_KIND_FLARE CHAIN_ID=16
|
||||
APPNAME = "Flare Coston"
|
||||
else ifeq ($(CHAIN),theta)
|
||||
APP_LOAD_PARAMS += --path "44'/500'" --path "44'/60'"
|
||||
APP_LOAD_PARAMS += --path "44'/500'"
|
||||
DEFINES += CHAINID_UPCASE=\"THETA\" CHAINID_COINNAME=\"THETA\" CHAIN_KIND=CHAIN_KIND_THETA CHAIN_ID=500
|
||||
APPNAME = "Theta"
|
||||
else ifeq ($(CHAIN),bsc)
|
||||
APP_LOAD_PARAMS += --path "44'/60'"
|
||||
DEFINES += CHAINID_UPCASE=\"BSC\" CHAINID_COINNAME=\"BNB\" CHAIN_KIND=CHAIN_KIND_BSC CHAIN_ID=56
|
||||
APPNAME = "Binance Smart Chain"
|
||||
else
|
||||
ifeq ($(filter clean,$(MAKECMDGOALS)),)
|
||||
$(error Unsupported CHAIN - use ethereum, ropsten, ethereum_classic, expanse, poa, artis_sigma1, artis_tau1, rsk, rsk_testnet, ubiq, wanchain, kusd, musicoin, pirl, akroma, atheios, callisto, ethersocial, ellaism, ether1, ethergem, gochain, mix, reosc, hpb, tomochain, tobalaba, dexon, volta, ewc, webchain, thundercore, flare, flare_coston, theta)
|
||||
@@ -266,6 +270,12 @@ ifneq ($(ALLOW_DATA),0)
|
||||
DEFINES += HAVE_ALLOW_DATA
|
||||
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
|
||||
DEBUG:=0
|
||||
@@ -306,7 +316,7 @@ endif
|
||||
CC := $(CLANGPATH)clang
|
||||
|
||||
#CFLAGS += -O0
|
||||
CFLAGS += -O3 -Os -Wno-format-invalid-specifier -Wno-format-extra-args -Wno-main
|
||||
CFLAGS += -O3 -Os -Wno-format-invalid-specifier -Wno-format-extra-args
|
||||
|
||||
AS := $(GCCPATH)arm-none-eabi-gcc
|
||||
|
||||
@@ -334,6 +344,7 @@ endif
|
||||
|
||||
# rebuild
|
||||
$(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)
|
||||
ifneq ($(shell git status | grep 'ethereum-plugin-sdk'),)
|
||||
@@ -366,4 +377,4 @@ include $(BOLOS_SDK)/Makefile.rules
|
||||
dep/%.d: %.c Makefile
|
||||
|
||||
listvariants:
|
||||
@echo VARIANTS CHAIN ethereum ropsten ethereum_classic expanse poa rsk rsk_testnet ubiq wanchain pirl akroma atheios callisto ethersocial ether1 gochain musicoin ethergem mix ellaism reosc hpb tomochain dexon volta ewc thundercore flare flare_coston theta
|
||||
@echo VARIANTS CHAIN ethereum ropsten ethereum_classic expanse poa rsk rsk_testnet ubiq wanchain pirl akroma atheios callisto ethersocial ether1 gochain musicoin ethergem mix ellaism reosc hpb tomochain dexon volta ewc thundercore flare flare_coston theta bsc
|
||||
|
||||
11
README.md
@@ -2,9 +2,13 @@
|
||||
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`.
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
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`.
|
||||
@@ -13,6 +13,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.
|
||||
|
||||
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
|
||||
|
||||
When signing an Ethereum transaction containing data, the Ethereum application looks for a plugin using .either a selector list or the contract address.
|
||||
@@ -149,7 +151,7 @@ typedef struct ethPluginFinalize_t {
|
||||
uint8_t *tokenLookup2;
|
||||
|
||||
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 numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS
|
||||
@@ -282,7 +284,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)
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -59,6 +59,9 @@ class UnsignedTransaction(Serializable):
|
||||
('to', address),
|
||||
('value', big_endian_int),
|
||||
('data', binary),
|
||||
('chainid', big_endian_int),
|
||||
('dummy1', big_endian_int),
|
||||
('dummy2', big_endian_int),
|
||||
]
|
||||
|
||||
def unsigned_tx_from_tx(tx):
|
||||
|
||||
@@ -77,6 +77,10 @@ if args.data == None:
|
||||
else:
|
||||
args.data = decode_hex(args.data[2:])
|
||||
|
||||
# default to Ethereum mainnet
|
||||
if args.chainid == None:
|
||||
args.chainid = 1
|
||||
|
||||
amount = Decimal(args.amount) * 10**18
|
||||
|
||||
tx = UnsignedTransaction(
|
||||
@@ -86,11 +90,17 @@ tx = UnsignedTransaction(
|
||||
to=decode_hex(args.to[2:]),
|
||||
value=int(amount),
|
||||
data=args.data,
|
||||
chainid=args.chainid,
|
||||
dummy1=0,
|
||||
dummy2=0
|
||||
)
|
||||
|
||||
encodedTx = encode(tx, UnsignedTransaction)
|
||||
encodedTx = bytearray.fromhex(
|
||||
"02ef0306843b9aca008504a817c80082520894b2bb2b958afa2e96dab3f3ce7162b87daea39017872386f26fc1000080c0")
|
||||
# encodedTx = bytearray.fromhex(
|
||||
# "02ef0306843b9aca008504a817c80082520894b2bb2b958afa2e96dab3f3ce7162b87daea39017872386f26fc1000080c0")
|
||||
|
||||
# To test an EIP-2930 transaction, uncomment this line
|
||||
#encodedTx = bytearray.fromhex("01f8e60380018402625a0094cccccccccccccccccccccccccccccccccccccccc830186a0a4693c61390000000000000000000000000000000000000000000000000000000000000002f85bf859940000000000000000000000000000000000000102f842a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000060a780a09b8adcd2a4abd34b42d56fcd90b949f74ca9696dfe2b427bc39aa280bbf1924ca029af4a471bb2953b4e7933ea95880648552a9345424a1ac760189655ceb1832a")
|
||||
|
||||
dongle = getDongle(True)
|
||||
|
||||
|
||||
BIN
icons/nanos_app_bsc.gif
Normal file
|
After Width: | Height: | Size: 71 B |
BIN
icons/nanox_app_bsc.gif
Normal file
|
After Width: | Height: | Size: 68 B |
@@ -54,7 +54,8 @@ typedef enum chain_kind_e {
|
||||
CHAIN_KIND_WEBCHAIN,
|
||||
CHAIN_KIND_THUNDERCORE,
|
||||
CHAIN_KIND_FLARE,
|
||||
CHAIN_KIND_THETA
|
||||
CHAIN_KIND_THETA,
|
||||
CHAIN_KIND_BSC
|
||||
} chain_kind_t;
|
||||
|
||||
typedef struct chain_config_s {
|
||||
|
||||
@@ -21,12 +21,8 @@ void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize) {
|
||||
memset((uint8_t *) finalize, 0, sizeof(ethPluginFinalize_t));
|
||||
}
|
||||
|
||||
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken,
|
||||
tokenDefinition_t *token1,
|
||||
tokenDefinition_t *token2) {
|
||||
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken) {
|
||||
memset((uint8_t *) provideToken, 0, sizeof(ethPluginProvideToken_t));
|
||||
provideToken->token1 = token1;
|
||||
provideToken->token2 = token2;
|
||||
}
|
||||
|
||||
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,
|
||||
dataContext.tokenContext.contract_address,
|
||||
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);
|
||||
}
|
||||
if (memcmp(init->selector,
|
||||
dataContext.tokenContext.method_selector,
|
||||
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);
|
||||
}
|
||||
PRINTF("External plugin will be used\n");
|
||||
@@ -90,7 +94,9 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress,
|
||||
if (memcmp(init->selector, (const void *) PIC(selectors[j]), SELECTOR_SIZE) == 0) {
|
||||
if ((INTERNAL_ETH_PLUGINS[i].availableCheck == NULL) ||
|
||||
((PluginAvailableCheck) PIC(INTERNAL_ETH_PLUGINS[i].availableCheck))()) {
|
||||
strcpy(dataContext.tokenContext.pluginName, INTERNAL_ETH_PLUGINS[i].alias);
|
||||
strlcpy(dataContext.tokenContext.pluginName,
|
||||
INTERNAL_ETH_PLUGINS[i].alias,
|
||||
PLUGIN_ID_LENGTH);
|
||||
dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK;
|
||||
contractAddress = NULL;
|
||||
break;
|
||||
@@ -128,7 +134,6 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress,
|
||||
eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
ethPluginSharedRW_t pluginRW;
|
||||
ethPluginSharedRO_t pluginRO;
|
||||
char tmp[PLUGIN_ID_LENGTH];
|
||||
char *alias;
|
||||
uint8_t i;
|
||||
uint8_t internalPlugin = 0;
|
||||
@@ -146,6 +151,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
|
||||
switch (method) {
|
||||
case ETH_PLUGIN_INIT_CONTRACT:
|
||||
PRINTF("-- PLUGIN INIT CONTRACT --\n");
|
||||
((ethPluginInitContract_t *) parameter)->interfaceVersion =
|
||||
ETH_PLUGIN_INTERFACE_VERSION_1;
|
||||
((ethPluginInitContract_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
@@ -158,6 +164,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
((ethPluginInitContract_t *) parameter)->alias = dataContext.tokenContext.pluginName;
|
||||
break;
|
||||
case ETH_PLUGIN_PROVIDE_PARAMETER:
|
||||
PRINTF("-- PLUGIN PROVIDE PARAMETER --\n");
|
||||
((ethPluginProvideParameter_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
((ethPluginProvideParameter_t *) parameter)->pluginSharedRW = &pluginRW;
|
||||
((ethPluginProvideParameter_t *) parameter)->pluginSharedRO = &pluginRO;
|
||||
@@ -165,6 +172,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
(uint8_t *) &dataContext.tokenContext.pluginContext;
|
||||
break;
|
||||
case ETH_PLUGIN_FINALIZE:
|
||||
PRINTF("-- PLUGIN FINALIZE --\n");
|
||||
((ethPluginFinalize_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
((ethPluginFinalize_t *) parameter)->pluginSharedRW = &pluginRW;
|
||||
((ethPluginFinalize_t *) parameter)->pluginSharedRO = &pluginRO;
|
||||
@@ -172,6 +180,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
(uint8_t *) &dataContext.tokenContext.pluginContext;
|
||||
break;
|
||||
case ETH_PLUGIN_PROVIDE_TOKEN:
|
||||
PRINTF("-- PLUGIN PROVIDE TOKEN --\n");
|
||||
((ethPluginProvideToken_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
((ethPluginProvideToken_t *) parameter)->pluginSharedRW = &pluginRW;
|
||||
((ethPluginProvideToken_t *) parameter)->pluginSharedRO = &pluginRO;
|
||||
@@ -179,6 +188,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
(uint8_t *) &dataContext.tokenContext.pluginContext;
|
||||
break;
|
||||
case ETH_PLUGIN_QUERY_CONTRACT_ID:
|
||||
PRINTF("-- PLUGIN QUERY CONTRACT ID --\n");
|
||||
((ethQueryContractID_t *) parameter)->result = ETH_PLUGIN_RESULT_UNAVAILABLE;
|
||||
((ethQueryContractID_t *) parameter)->pluginSharedRW = &pluginRW;
|
||||
((ethQueryContractID_t *) parameter)->pluginSharedRO = &pluginRO;
|
||||
@@ -186,6 +196,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
(uint8_t *) &dataContext.tokenContext.pluginContext;
|
||||
break;
|
||||
case ETH_PLUGIN_QUERY_CONTRACT_UI:
|
||||
PRINTF("-- PLUGIN QUERY CONTRACT UI --\n");
|
||||
((ethQueryContractUI_t *) parameter)->pluginSharedRW = &pluginRW;
|
||||
((ethQueryContractUI_t *) parameter)->pluginSharedRO = &pluginRO;
|
||||
((ethQueryContractUI_t *) parameter)->pluginContext =
|
||||
@@ -231,7 +242,6 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
PRINTF("method: %d\n", method);
|
||||
switch (method) {
|
||||
case ETH_PLUGIN_INIT_CONTRACT:
|
||||
PRINTF("parameter result: %d\n", ((ethPluginInitContract_t *) parameter)->result);
|
||||
switch (((ethPluginInitContract_t *) parameter)->result) {
|
||||
case ETH_PLUGIN_RESULT_OK:
|
||||
break;
|
||||
@@ -264,6 +274,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
}
|
||||
break;
|
||||
case ETH_PLUGIN_PROVIDE_TOKEN:
|
||||
PRINTF("RESULT: %d\n", ((ethPluginProvideToken_t *) parameter)->result);
|
||||
switch (((ethPluginProvideToken_t *) parameter)->result) {
|
||||
case ETH_PLUGIN_RESULT_OK:
|
||||
case ETH_PLUGIN_RESULT_FALLBACK:
|
||||
@@ -280,7 +291,7 @@ eth_plugin_result_t eth_plugin_call(int method, void *parameter) {
|
||||
}
|
||||
break;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -7,9 +7,7 @@ void eth_plugin_prepare_provide_parameter(ethPluginProvideParameter_t *providePa
|
||||
uint8_t *parameter,
|
||||
uint32_t parameterOffset);
|
||||
void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize);
|
||||
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken,
|
||||
tokenDefinition_t *token1,
|
||||
tokenDefinition_t *token2);
|
||||
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken);
|
||||
void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID,
|
||||
char *name,
|
||||
uint32_t nameLength,
|
||||
|
||||
@@ -105,7 +105,8 @@ typedef struct ethPluginFinalize_t {
|
||||
uint8_t *tokenLookup2;
|
||||
|
||||
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 numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS
|
||||
|
||||
@@ -13,23 +13,20 @@ void starkware_plugin_call(int message, void* parameters);
|
||||
void eth2_plugin_call(int message, void* parameters);
|
||||
#endif
|
||||
|
||||
static const uint8_t const 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_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0xa9, 0x05, 0x9c, 0xbb};
|
||||
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,
|
||||
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};
|
||||
|
||||
static const uint8_t const COMPOUND_REDEEM_UNDERLYING_SELECTOR[SELECTOR_SIZE] = {0x85,
|
||||
0x2a,
|
||||
0x12,
|
||||
0xe3};
|
||||
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};
|
||||
static const uint8_t COMPOUND_REDEEM_UNDERLYING_SELECTOR[SELECTOR_SIZE] = {0x85, 0x2a, 0x12, 0xe3};
|
||||
static const uint8_t COMPOUND_REDEEM_SELECTOR[SELECTOR_SIZE] = {0xdb, 0x00, 0x6a, 0x75};
|
||||
static const uint8_t COMPOUND_MINT_SELECTOR[SELECTOR_SIZE] = {0xa0, 0x71, 0x2d, 0x68};
|
||||
static const uint8_t CETH_MINT_SELECTOR[SELECTOR_SIZE] = {0x12, 0x49, 0xc5, 0x8b};
|
||||
|
||||
const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = {
|
||||
COMPOUND_REDEEM_UNDERLYING_SELECTOR,
|
||||
@@ -39,7 +36,7 @@ const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = {
|
||||
|
||||
#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};
|
||||
|
||||
@@ -47,39 +44,33 @@ const uint8_t* const ETH2_SELECTORS[NUM_ETH2_SELECTORS] = {ETH2_DEPOSIT_SELECTOR
|
||||
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
static const uint8_t const 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 const 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 const 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 const 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 const 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_REGISTER_ID[SELECTOR_SIZE] = {0xdd, 0x24, 0x14, 0xd4};
|
||||
static const uint8_t STARKWARE_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x25, 0x05, 0xc3, 0xd9};
|
||||
static const uint8_t STARKWARE_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x00, 0xae, 0xef, 0x8a};
|
||||
static const uint8_t STARKWARE_DEPOSIT_CANCEL_ID[SELECTOR_SIZE] = {0x7d, 0xf7, 0xdc, 0x04};
|
||||
static const uint8_t STARKWARE_DEPOSIT_RECLAIM_ID[SELECTOR_SIZE] = {0xae, 0x87, 0x38, 0x16};
|
||||
static const uint8_t STARKWARE_WITHDRAW_ID[SELECTOR_SIZE] = {0x44, 0x1a, 0x3e, 0x70};
|
||||
static const uint8_t STARKWARE_FULL_WITHDRAWAL_ID[SELECTOR_SIZE] = {0xa9, 0x33, 0x10, 0xc4};
|
||||
static const uint8_t STARKWARE_FREEZE_ID[SELECTOR_SIZE] = {0x93, 0xc1, 0xe4, 0x66};
|
||||
static const uint8_t STARKWARE_ESCAPE_ID[SELECTOR_SIZE] = {0x9e, 0x3a, 0xda, 0xc4};
|
||||
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 const STARKWARE_DEPOSIT_NFT_ID[SELECTOR_SIZE] = {0xae, 0x1c, 0xdd, 0xe6};
|
||||
static const uint8_t const STARKWARE_DEPOSIT_NFT_RECLAIM_ID[SELECTOR_SIZE] = {0xfc,
|
||||
0xb0,
|
||||
0x58,
|
||||
0x22};
|
||||
static const uint8_t const STARKWARE_WITHDRAW_AND_MINT_ID[SELECTOR_SIZE] = {0xd9, 0x14, 0x43, 0xb7};
|
||||
static const uint8_t const STARKWARE_WITHDRAW_NFT_ID[SELECTOR_SIZE] = {0x01, 0x9b, 0x41, 0x7a};
|
||||
static const uint8_t const STARKWARE_WITHDRAW_NFT_TO_ID[SELECTOR_SIZE] = {0xeb, 0xef, 0x0f, 0xd0};
|
||||
static const uint8_t const STARKWARE_REGISTER_AND_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x10,
|
||||
0x82,
|
||||
0x08,
|
||||
0xcf};
|
||||
static const uint8_t const STARKWARE_REGISTER_AND_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0xa7,
|
||||
0x78,
|
||||
0xc0,
|
||||
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};
|
||||
static const uint8_t STARKWARE_WITHDRAW_TO_ID[SELECTOR_SIZE] = {0x14, 0xcd, 0x70, 0xe4};
|
||||
static const uint8_t STARKWARE_DEPOSIT_NFT_ID[SELECTOR_SIZE] = {0xae, 0x1c, 0xdd, 0xe6};
|
||||
static const uint8_t STARKWARE_DEPOSIT_NFT_RECLAIM_ID[SELECTOR_SIZE] = {0xfc, 0xb0, 0x58, 0x22};
|
||||
static const uint8_t STARKWARE_WITHDRAW_AND_MINT_ID[SELECTOR_SIZE] = {0xd9, 0x14, 0x43, 0xb7};
|
||||
static const uint8_t STARKWARE_WITHDRAW_NFT_ID[SELECTOR_SIZE] = {0x01, 0x9b, 0x41, 0x7a};
|
||||
static const uint8_t STARKWARE_WITHDRAW_NFT_TO_ID[SELECTOR_SIZE] = {0xeb, 0xef, 0x0f, 0xd0};
|
||||
static const uint8_t STARKWARE_REGISTER_AND_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x10,
|
||||
0x82,
|
||||
0x08,
|
||||
0xcf};
|
||||
static const uint8_t STARKWARE_REGISTER_AND_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0xa7,
|
||||
0x78,
|
||||
0xc0,
|
||||
0xc3};
|
||||
static const uint8_t STARKWARE_PROXY_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0xdc, 0xca, 0xd5, 0x24};
|
||||
static const uint8_t STARKWARE_PROXY_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x6c, 0xe5, 0xd9, 0x57};
|
||||
|
||||
const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS] = {
|
||||
STARKWARE_REGISTER_ID,
|
||||
@@ -107,7 +98,7 @@ const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS] = {
|
||||
|
||||
// All internal alias names start with 'minus'
|
||||
|
||||
const internalEthPlugin_t const INTERNAL_ETH_PLUGINS[] = {
|
||||
const internalEthPlugin_t INTERNAL_ETH_PLUGINS[] = {
|
||||
{erc20_plugin_available_check,
|
||||
(const uint8_t**) ERC20_SELECTORS,
|
||||
NUM_ERC20_SELECTORS,
|
||||
|
||||
@@ -59,7 +59,7 @@ int handle_check_address(check_address_parameters_t* params, chain_config_t* cha
|
||||
cx_ecfp_generate_pair(CX_CURVE_256K1, &locals_union2.publicKey, &locals_union1.privateKey, 1);
|
||||
ZERO(locals_union1);
|
||||
getEthAddressStringFromKey(&locals_union2.publicKey,
|
||||
(uint8_t*) locals_union1.address,
|
||||
locals_union1.address,
|
||||
&local_sha3,
|
||||
chain_config);
|
||||
ZERO(locals_union2);
|
||||
|
||||
@@ -10,7 +10,7 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
|
||||
// We need this "trick" as the input data position can overlap with app-ethereum globals
|
||||
txStringProperties_t stack_data;
|
||||
memset(&stack_data, 0, sizeof(stack_data));
|
||||
strncpy(stack_data.fullAddress,
|
||||
strlcpy(stack_data.fullAddress,
|
||||
sign_transaction_params->destination_address,
|
||||
sizeof(stack_data.fullAddress));
|
||||
if ((stack_data.fullAddress[sizeof(stack_data.fullAddress) - 1] != '\0') ||
|
||||
@@ -36,7 +36,7 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
|
||||
sizeof(stack_data.fullAmount));
|
||||
|
||||
// If the amount is a fee, its value is nominated in ETH even if we're doing an ERC20 swap
|
||||
strcpy(ticker, config->coinName);
|
||||
strlcpy(ticker, config->coinName, MAX_TICKER_LEN);
|
||||
decimals = WEI_TO_ETHER;
|
||||
amountToString(sign_transaction_params->fee_amount,
|
||||
sign_transaction_params->fee_amount_length,
|
||||
|
||||
34
src/main.c
@@ -92,28 +92,12 @@ void ui_idle(void) {
|
||||
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
|
||||
os_sched_exit(0);
|
||||
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) {
|
||||
G_io_apdu_buffer[0] = ((sw >> 8) & 0xff);
|
||||
G_io_apdu_buffer[1] = (sw & 0xff);
|
||||
@@ -269,6 +253,9 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) {
|
||||
case CHAIN_KIND_THETA:
|
||||
numTokens = NUM_TOKENS_THETA;
|
||||
break;
|
||||
case CHAIN_KIND_BSC:
|
||||
numTokens = NUM_TOKENS_BSC;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < numTokens; i++) {
|
||||
switch (chainConfig->kind) {
|
||||
@@ -367,6 +354,9 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) {
|
||||
break case CHAIN_KIND_THETA : currentToken =
|
||||
(tokenDefinition_t *) PIC(&TOKENS_THETA[i]);
|
||||
break;
|
||||
case CHAIN_KIND_BSC:
|
||||
currentToken = (tokenDefinition_t *) PIC(&TOKENS_BSC[i]);
|
||||
break;
|
||||
}
|
||||
if (memcmp(currentToken->address, tmpContent.txContent.destination, ADDRESS_LENGTH) == 0) {
|
||||
return currentToken;
|
||||
@@ -385,13 +375,13 @@ tokenDefinition_t *getKnownToken(uint8_t *contractAddress) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef HAVE_WALLET_ID_SDK
|
||||
|
||||
unsigned int const U_os_perso_seed_cookie[] = {
|
||||
0xda7aba5e,
|
||||
0xc1a551c5,
|
||||
};
|
||||
|
||||
#ifndef HAVE_WALLET_ID_SDK
|
||||
|
||||
void handleGetWalletId(volatile unsigned int *tx) {
|
||||
unsigned char t[64];
|
||||
cx_ecfp_256_private_key_t priv;
|
||||
@@ -409,7 +399,7 @@ void handleGetWalletId(volatile unsigned int *tx) {
|
||||
THROW(0x9000);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // HAVE_WALLET_ID_SDK
|
||||
|
||||
void handleApdu(unsigned int *flags, unsigned int *tx) {
|
||||
unsigned short sw = 0;
|
||||
@@ -424,7 +414,7 @@ void handleApdu(unsigned int *flags, unsigned int *tx) {
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // HAVE_WALLET_ID_SDK
|
||||
|
||||
#ifdef HAVE_STARKWARE
|
||||
|
||||
@@ -681,7 +671,7 @@ void io_seproxyhal_display(const 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
|
||||
// needed
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ typedef struct tokenContext_t {
|
||||
|
||||
typedef struct publicKeyContext_t {
|
||||
cx_ecfp_public_key_t publicKey;
|
||||
uint8_t address[41];
|
||||
char address[41];
|
||||
uint8_t chainCode[INT256_LENGTH];
|
||||
bool getChaincode;
|
||||
} publicKeyContext_t;
|
||||
@@ -162,13 +162,14 @@ typedef enum {
|
||||
#endif
|
||||
} contract_call_t;
|
||||
|
||||
#define NETWORK_NAME_MAX_SIZE 12
|
||||
|
||||
typedef struct txStringProperties_t {
|
||||
char fullAddress[43];
|
||||
char fullAmount[50];
|
||||
char maxFee[50];
|
||||
char nonce[8]; // 10M tx per account ought to be enough for everybody
|
||||
char chainID[8]; // 10M different chainID ought to be enough for people to find a unique
|
||||
// chainID for their token / chain.
|
||||
char nonce[8]; // 10M tx per account ought to be enough for everybody
|
||||
char network_name[NETWORK_NAME_MAX_SIZE];
|
||||
} txStringProperties_t;
|
||||
|
||||
#define SHARED_CTX_FIELD_1_SIZE 100
|
||||
|
||||
@@ -60,7 +60,7 @@ void stark_get_amount_string(uint8_t *contractAddress,
|
||||
char *target100) {
|
||||
uint256_t amountPre, quantum, amount;
|
||||
uint8_t decimals;
|
||||
char *ticker = (char *) PIC(chainConfig->coinName);
|
||||
char *ticker = chainConfig->coinName;
|
||||
|
||||
PRINTF("stark_get_amount_string %.*H\n", 20, contractAddress);
|
||||
|
||||
@@ -81,7 +81,7 @@ void stark_get_amount_string(uint8_t *contractAddress,
|
||||
mul256(&amountPre, &quantum, &amount);
|
||||
tostring256(&amount, 10, tmp100, 100);
|
||||
PRINTF("stark_get_amount_string - mul256 %s\n", tmp100);
|
||||
strcpy(target100, ticker);
|
||||
strlcpy(target100, ticker, 100);
|
||||
adjustDecimals(tmp100, strlen(tmp100), target100 + strlen(ticker), 100, decimals);
|
||||
PRINTF("get_amount_string %s\n", target100);
|
||||
}
|
||||
|
||||
@@ -4566,4 +4566,6 @@ const tokenDefinition_t const TOKENS_FLARE[NUM_TOKENS_FLARE] = {};
|
||||
|
||||
const tokenDefinition_t const TOKENS_THETA[NUM_TOKENS_THETA] = {};
|
||||
|
||||
const tokenDefinition_t const TOKENS_BSC[NUM_TOKENS_BSC] = {};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,7 +28,7 @@ typedef struct tokenDefinition_t {
|
||||
uint8_t contractName[ADDRESS_LENGTH];
|
||||
#endif
|
||||
uint8_t address[ADDRESS_LENGTH];
|
||||
uint8_t ticker[MAX_TICKER_LEN];
|
||||
char ticker[MAX_TICKER_LEN];
|
||||
uint8_t decimals;
|
||||
} tokenDefinition_t;
|
||||
|
||||
@@ -43,7 +43,7 @@ extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
|
||||
#ifndef HAVE_TOKENS_LIST
|
||||
|
||||
#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)
|
||||
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,
|
||||
@@ -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};
|
||||
|
||||
#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)
|
||||
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,
|
||||
@@ -96,6 +96,7 @@ static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = {
|
||||
#define NUM_TOKENS_THUNDERCORE 0
|
||||
#define NUM_TOKENS_FLARE 0
|
||||
#define NUM_TOKENS_THETA 0
|
||||
#define NUM_TOKENS_BSC 0
|
||||
|
||||
extern tokenDefinition_t const TOKENS_AKROMA[NUM_TOKENS_AKROMA];
|
||||
extern tokenDefinition_t const TOKENS_ELLAISM[NUM_TOKENS_ELLAISM];
|
||||
@@ -129,6 +130,7 @@ extern tokenDefinition_t const TOKENS_WEBCHAIN[NUM_TOKENS_WEBCHAIN];
|
||||
extern tokenDefinition_t const TOKENS_THUNDERCORE[NUM_TOKENS_THUNDERCORE];
|
||||
extern tokenDefinition_t const TOKENS_FLARE[NUM_TOKENS_FLARE];
|
||||
extern tokenDefinition_t const TOKENS_THETA[NUM_TOKENS_THETA];
|
||||
extern tokenDefinition_t const TOKENS_BSC[NUM_TOKENS_BSC];
|
||||
|
||||
#endif /* HAVE_TOKENS_LIST */
|
||||
|
||||
|
||||
@@ -132,11 +132,13 @@ UX_FLOW(ux_settings_flow,
|
||||
&ux_settings_flow_4_step);
|
||||
|
||||
void display_settings(const ux_flow_step_t* const start_step) {
|
||||
strcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed"));
|
||||
strcpy(strings.common.fullAddress + 12,
|
||||
(N_storage.contractDetails ? "Displayed" : "NOT Displayed"));
|
||||
strcpy(strings.common.fullAddress + 26,
|
||||
(N_storage.displayNonce ? "Displayed" : "NOT Displayed"));
|
||||
strlcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed"), 12);
|
||||
strlcpy(strings.common.fullAddress + 12,
|
||||
(N_storage.contractDetails ? "Displayed" : "NOT Displayed"),
|
||||
26 - 12);
|
||||
strlcpy(strings.common.fullAddress + 26,
|
||||
(N_storage.displayNonce ? "Displayed" : "NOT Displayed"),
|
||||
sizeof(strings.common.fullAddress) - 26);
|
||||
ux_flow_init(0, ux_settings_flow, start_step);
|
||||
}
|
||||
|
||||
|
||||
32
src/utils.c
@@ -57,20 +57,24 @@ int local_strchr(char *string, char ch) {
|
||||
// Almost like U4BE except that it takes `size` as a parameter.
|
||||
// The `strict` parameter defines whether we should throw in case of a length > 4.
|
||||
uint32_t u32_from_BE(uint8_t *in, uint8_t size, bool strict) {
|
||||
uint32_t res = 0;
|
||||
if (size == 1) {
|
||||
res = in[0];
|
||||
} else if (size == 2) {
|
||||
res = (in[0] << 8) | in[1];
|
||||
} else if (size == 3) {
|
||||
res = (in[0] << 16) | (in[1] << 8) | in[2];
|
||||
} else if (size == 4) {
|
||||
res = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
|
||||
} else if (strict && size != 0) {
|
||||
PRINTF("Unexpected format\n");
|
||||
THROW(EXCEPTION);
|
||||
switch (size) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return in[0];
|
||||
case 2:
|
||||
return (in[0] << 8) | in[1];
|
||||
case 3:
|
||||
return (in[0] << 16) | (in[1] << 8) | in[2];
|
||||
case 4:
|
||||
return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
|
||||
default:
|
||||
if (strict) {
|
||||
PRINTF("Unexpected format\n");
|
||||
THROW(EXCEPTION);
|
||||
}
|
||||
return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool uint256_to_decimal(const uint8_t *value, size_t value_len, char *out, size_t out_len) {
|
||||
@@ -89,7 +93,7 @@ bool uint256_to_decimal(const uint8_t *value, size_t value_len, char *out, size_
|
||||
// Not enough space to hold "0" and \0.
|
||||
return false;
|
||||
}
|
||||
strncpy(out, "0", out_len);
|
||||
strlcpy(out, "0", out_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -486,7 +486,6 @@ static parserStatus_e parseRLP(txContext_t *context) {
|
||||
}
|
||||
// Ready to process this field
|
||||
if (!rlpDecodeLength(context->rlpBuffer,
|
||||
context->rlpBufferPos,
|
||||
&context->currentFieldLength,
|
||||
&offset,
|
||||
&context->currentFieldIsList)) {
|
||||
|
||||
@@ -58,11 +58,7 @@ bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rlpDecodeLength(uint8_t *buffer,
|
||||
uint32_t bufferLength,
|
||||
uint32_t *fieldLength,
|
||||
uint32_t *offset,
|
||||
bool *list) {
|
||||
bool rlpDecodeLength(uint8_t *buffer, uint32_t *fieldLength, uint32_t *offset, bool *list) {
|
||||
if (*buffer <= 0x7f) {
|
||||
*offset = 0;
|
||||
*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,
|
||||
uint8_t *out,
|
||||
char *out,
|
||||
cx_sha3_t *sha3Context,
|
||||
chain_config_t *chain_config) {
|
||||
uint8_t hashAddress[INT256_LENGTH];
|
||||
@@ -138,7 +134,7 @@ void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
|
||||
}
|
||||
|
||||
void getEthAddressStringFromBinary(uint8_t *address,
|
||||
uint8_t *out,
|
||||
char *out,
|
||||
cx_sha3_t *sha3Context,
|
||||
chain_config_t *chain_config) {
|
||||
// save some precious stack space
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
* @brief Decode an RLP encoded field - see
|
||||
* https://github.com/ethereum/wiki/wiki/RLP
|
||||
* @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] offset offset to the beginning of the RLP encoded field from the
|
||||
* buffer
|
||||
@@ -34,23 +33,19 @@
|
||||
* string
|
||||
* @return true if the RLP header is consistent
|
||||
*/
|
||||
bool rlpDecodeLength(uint8_t *buffer,
|
||||
uint32_t bufferLength,
|
||||
uint32_t *fieldLength,
|
||||
uint32_t *offset,
|
||||
bool *list);
|
||||
bool rlpDecodeLength(uint8_t *buffer, uint32_t *fieldLength, uint32_t *offset, bool *list);
|
||||
|
||||
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 getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
|
||||
uint8_t *out,
|
||||
char *out,
|
||||
cx_sha3_t *sha3Context,
|
||||
chain_config_t *chain_config);
|
||||
|
||||
void getEthAddressStringFromBinary(uint8_t *address,
|
||||
uint8_t *out,
|
||||
char *out,
|
||||
cx_sha3_t *sha3Context,
|
||||
chain_config_t *chain_config);
|
||||
|
||||
|
||||
71
src_common/network.c
Normal file
@@ -0,0 +1,71 @@
|
||||
#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:
|
||||
case EIP1559:
|
||||
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
@@ -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);
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "feature_getEth2PublicKey.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();
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "feature_getPublicKey.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();
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
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
|
||||
}
|
||||
|
||||
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[1] = 0x85;
|
||||
reset_app_context();
|
||||
|
||||
@@ -88,8 +88,10 @@ void handleProvideErc20TokenInformation(uint8_t p1,
|
||||
32,
|
||||
workBuffer + offset,
|
||||
dataLength)) {
|
||||
#ifndef HAVE_BYPASS_SIGNATURES
|
||||
PRINTF("Invalid token signature\n");
|
||||
THROW(0x6A80);
|
||||
#endif
|
||||
}
|
||||
tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1;
|
||||
THROW(0x9000);
|
||||
@@ -102,7 +104,7 @@ void handleProvideErc20TokenInformation(uint8_t p1,
|
||||
uint8_t *workBuffer,
|
||||
uint16_t dataLength,
|
||||
unsigned int *flags,
|
||||
unsigned int *tx) {
|
||||
__attribute__((unused)) unsigned int *tx) {
|
||||
UNUSED(p1);
|
||||
UNUSED(p2);
|
||||
UNUSED(flags);
|
||||
@@ -143,8 +145,8 @@ void handleProvideErc20TokenInformation(uint8_t p1,
|
||||
offset += 4;
|
||||
dataLength -= 4;
|
||||
chainId = U4BE(workBuffer, offset);
|
||||
if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) {
|
||||
PRINTF("ChainId token mismatch\n");
|
||||
if ((chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) && (chainConfig->chainId != chainId)) {
|
||||
PRINTF("ChainId token mismatch: %d vs %d\n", chainConfig->chainId, chainId);
|
||||
THROW(0x6A80);
|
||||
}
|
||||
offset += 4;
|
||||
@@ -175,8 +177,10 @@ void handleProvideErc20TokenInformation(uint8_t p1,
|
||||
32,
|
||||
workBuffer + offset,
|
||||
dataLength)) {
|
||||
#ifndef HAVE_BYPASS_SIGNATURES
|
||||
PRINTF("Invalid token signature\n");
|
||||
THROW(0x6A80);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,8 +197,10 @@ void handleProvideErc20TokenInformation(uint8_t p1,
|
||||
32,
|
||||
workBuffer + offset,
|
||||
dataLength)) {
|
||||
#ifndef HAVE_BYPASS_SIGNATURES
|
||||
PRINTF("Invalid token signature\n");
|
||||
THROW(0x6A80);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ void handleSetEth2WithdrawalIndex(uint8_t p1,
|
||||
uint8_t p2,
|
||||
uint8_t *dataBuffer,
|
||||
uint16_t dataLength,
|
||||
unsigned int *flags,
|
||||
unsigned int *tx) {
|
||||
__attribute__((unused)) unsigned int *flags,
|
||||
__attribute__((unused)) unsigned int *tx) {
|
||||
if (dataLength != 4) {
|
||||
THROW(0x6700);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "ui_flow.h"
|
||||
#include "tokens.h"
|
||||
|
||||
#define CONTRACT_ADDR_SIZE 20
|
||||
#define SELECTOR_SIZE 4
|
||||
#define SELECTOR_SIZE 4
|
||||
|
||||
void handleSetExternalPlugin(uint8_t p1,
|
||||
uint8_t p2,
|
||||
@@ -19,7 +18,7 @@ void handleSetExternalPlugin(uint8_t p1,
|
||||
uint8_t hash[32];
|
||||
cx_ecfp_public_key_t tokenKey;
|
||||
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) {
|
||||
THROW(0x6A80);
|
||||
@@ -43,7 +42,9 @@ void handleSetExternalPlugin(uint8_t p1,
|
||||
workBuffer + payload_size,
|
||||
dataLength - payload_size)) {
|
||||
PRINTF("Invalid external plugin signature %.*H\n", payload_size, workBuffer);
|
||||
#ifndef HAVE_BYPASS_SIGNATURES
|
||||
THROW(0x6A80);
|
||||
#endif
|
||||
}
|
||||
|
||||
// move on to the rest of the payload parsing
|
||||
@@ -65,8 +66,8 @@ void handleSetExternalPlugin(uint8_t p1,
|
||||
CATCH_OTHER(e) {
|
||||
PRINTF("%s external plugin is not present\n", dataContext.tokenContext.pluginName);
|
||||
memset(dataContext.tokenContext.pluginName,
|
||||
sizeof(dataContext.tokenContext.pluginName),
|
||||
0);
|
||||
0,
|
||||
sizeof(dataContext.tokenContext.pluginName));
|
||||
THROW(0x6984);
|
||||
}
|
||||
FINALLY {
|
||||
@@ -76,8 +77,8 @@ void handleSetExternalPlugin(uint8_t p1,
|
||||
|
||||
PRINTF("Plugin found\n");
|
||||
|
||||
memmove(dataContext.tokenContext.contract_address, workBuffer, CONTRACT_ADDR_SIZE);
|
||||
workBuffer += 20;
|
||||
memmove(dataContext.tokenContext.contract_address, workBuffer, ADDRESS_LENGTH);
|
||||
workBuffer += ADDRESS_LENGTH;
|
||||
memmove(dataContext.tokenContext.method_selector, workBuffer, SELECTOR_SIZE);
|
||||
externalPluginIsSet = true;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "utils.h"
|
||||
#include "ui_flow.h"
|
||||
|
||||
static const char const SIGN_MAGIC[] =
|
||||
static const char SIGN_MAGIC[] =
|
||||
"\x19"
|
||||
"Ethereum Signed Message:\n";
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include "shared_context.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 signature[100];
|
||||
uint8_t signatureLength;
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
uint32_t tx = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
@@ -18,14 +17,14 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) {
|
||||
explicit_bzero(privateKeyData, sizeof(privateKeyData));
|
||||
unsigned int info = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
signatureLength = cx_ecdsa_sign(&privateKey,
|
||||
CX_RND_RFC6979 | CX_LAST,
|
||||
CX_SHA256,
|
||||
tmpCtx.messageSigningContext.hash,
|
||||
sizeof(tmpCtx.messageSigningContext.hash),
|
||||
signature,
|
||||
sizeof(signature),
|
||||
&info);
|
||||
cx_ecdsa_sign(&privateKey,
|
||||
CX_RND_RFC6979 | CX_LAST,
|
||||
CX_SHA256,
|
||||
tmpCtx.messageSigningContext.hash,
|
||||
sizeof(tmpCtx.messageSigningContext.hash),
|
||||
signature,
|
||||
sizeof(signature),
|
||||
&info);
|
||||
explicit_bzero(&privateKey, sizeof(privateKey));
|
||||
G_io_apdu_buffer[0] = 27;
|
||||
if (info & CX_ECCINFO_PARITY_ODD) {
|
||||
@@ -46,7 +45,8 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) {
|
||||
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();
|
||||
G_io_apdu_buffer[0] = 0x69;
|
||||
G_io_apdu_buffer[1] = 0x85;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "shared_context.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 hash[INT256_LENGTH];
|
||||
uint8_t signature[100];
|
||||
uint8_t signatureLength;
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
uint32_t tx = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
@@ -42,14 +42,14 @@ unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) {
|
||||
explicit_bzero(privateKeyData, sizeof(privateKeyData));
|
||||
unsigned int info = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
signatureLength = cx_ecdsa_sign(&privateKey,
|
||||
CX_RND_RFC6979 | CX_LAST,
|
||||
CX_SHA256,
|
||||
hash,
|
||||
sizeof(hash),
|
||||
signature,
|
||||
sizeof(signature),
|
||||
&info);
|
||||
cx_ecdsa_sign(&privateKey,
|
||||
CX_RND_RFC6979 | CX_LAST,
|
||||
CX_SHA256,
|
||||
hash,
|
||||
sizeof(hash),
|
||||
signature,
|
||||
sizeof(signature),
|
||||
&info);
|
||||
explicit_bzero(&privateKey, sizeof(privateKey));
|
||||
G_io_apdu_buffer[0] = 27;
|
||||
if (info & CX_ECCINFO_PARITY_ODD) {
|
||||
@@ -70,7 +70,8 @@ unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) {
|
||||
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();
|
||||
G_io_apdu_buffer[0] = 0x69;
|
||||
G_io_apdu_buffer[1] = 0x85;
|
||||
|
||||
@@ -10,5 +10,5 @@ typedef enum {
|
||||
customStatus_e customProcessor(txContext_t *context);
|
||||
void finalizeParsing(bool direct);
|
||||
void prepareFeeDisplay();
|
||||
void prepareChainIdDisplay();
|
||||
void prepareNetworkDisplay();
|
||||
void ux_approve_tx(bool fromPlugin);
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
#include "utils.h"
|
||||
#include "ui_callbacks.h"
|
||||
#include "ui_flow.h"
|
||||
#include "feature_signTx.h"
|
||||
#ifdef HAVE_STARKWARE
|
||||
#include "stark_utils.h"
|
||||
#endif
|
||||
#include "eth_plugin_handler.h"
|
||||
#include "network.h"
|
||||
|
||||
#define ERR_SILENT_MODE_CHECK_FAILED 0x6001
|
||||
|
||||
@@ -170,7 +172,7 @@ void to_uppercase(char *str, unsigned char size) {
|
||||
}
|
||||
}
|
||||
|
||||
void compareOrCopy(char *preapproved_string, char *parsed_string, bool silent_mode) {
|
||||
void compareOrCopy(char *preapproved_string, size_t size, char *parsed_string, bool silent_mode) {
|
||||
if (silent_mode) {
|
||||
/* ETH address are not fundamentally case sensitive but might
|
||||
have some for checksum purpose, so let's get rid of these diffs */
|
||||
@@ -180,7 +182,7 @@ void compareOrCopy(char *preapproved_string, char *parsed_string, bool silent_mo
|
||||
THROW(ERR_SILENT_MODE_CHECK_FAILED);
|
||||
}
|
||||
} else {
|
||||
strcpy(preapproved_string, parsed_string);
|
||||
strlcpy(preapproved_string, parsed_string, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +210,7 @@ static void computeFees(txInt256_t *BEgasPrice, txInt256_t *BEgasLimit, uint256_
|
||||
}
|
||||
|
||||
static void feesToString(uint256_t *rawFee, char *displayBuffer, uint32_t displayBufferSize) {
|
||||
uint8_t *feeTicker = (uint8_t *) PIC(chainConfig->coinName);
|
||||
char *feeTicker = get_network_ticker();
|
||||
uint8_t tickerOffset = 0;
|
||||
uint32_t i;
|
||||
|
||||
@@ -271,38 +273,58 @@ uint32_t get_chainID() {
|
||||
return chain_id;
|
||||
}
|
||||
|
||||
void prepareChainIdDisplay() {
|
||||
uint32_t chainID = get_chainID();
|
||||
uint8_t res = snprintf(strings.common.chainID, sizeof(strings.common.chainID), "%d", chainID);
|
||||
if (res >= sizeof(strings.common.chainID)) {
|
||||
// If the return value is higher or equal to the size passed in as parameter, then
|
||||
// the output was truncated. Return the appropriate error code.
|
||||
THROW(0x6502);
|
||||
void prepareNetworkDisplay() {
|
||||
char *name = get_network_name();
|
||||
if (name == NULL) {
|
||||
// No network name found so simply copy the chain ID as the network name.
|
||||
uint32_t chain_id = get_chain_id();
|
||||
uint8_t res = snprintf(strings.common.network_name,
|
||||
sizeof(strings.common.network_name),
|
||||
"%d",
|
||||
chain_id);
|
||||
if (res >= sizeof(strings.common.network_name)) {
|
||||
// If the return value is higher or equal to the size passed in as parameter, then
|
||||
// the output was truncated. Return the appropriate error code.
|
||||
THROW(0x6502);
|
||||
}
|
||||
} else {
|
||||
// Network name found, simply copy it.
|
||||
strlcpy(strings.common.network_name, name, sizeof(strings.common.network_name));
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
char displayBuffer[50];
|
||||
uint8_t decimals = WEI_TO_ETHER;
|
||||
uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName);
|
||||
char *ticker = get_network_ticker();
|
||||
ethPluginFinalize_t pluginFinalize;
|
||||
tokenDefinition_t *token1 = NULL, *token2 = NULL;
|
||||
bool genericUI = true;
|
||||
|
||||
// Verify the chain
|
||||
if (chainConfig->chainId != 0) {
|
||||
uint32_t id = 0;
|
||||
|
||||
if (txContext.txType == LEGACY) {
|
||||
id = u32_from_BE(txContext.content->v, txContext.content->vLength, true);
|
||||
} else if (txContext.txType == EIP2930 || txContext.txType == EIP1559) {
|
||||
id = u32_from_BE(txContext.content->chainID.value,
|
||||
txContext.content->chainID.length,
|
||||
false);
|
||||
} else {
|
||||
PRINTF("TxType `%u` not supported while checking for chainID\n", txContext.txType);
|
||||
return;
|
||||
}
|
||||
if (chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) {
|
||||
// TODO: Could we remove above check?
|
||||
uint32_t id = get_chain_id();
|
||||
|
||||
if (chainConfig->chainId != id) {
|
||||
PRINTF("Invalid chainID %u expected %u\n", id, chainConfig->chainId);
|
||||
@@ -325,6 +347,11 @@ void finalizeParsing(bool direct) {
|
||||
if (dataContext.tokenContext.pluginStatus >= ETH_PLUGIN_RESULT_SUCCESSFUL) {
|
||||
genericUI = false;
|
||||
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)) {
|
||||
PRINTF("Plugin finalize call failed\n");
|
||||
reportFinalizeError(direct);
|
||||
@@ -334,22 +361,22 @@ void finalizeParsing(bool direct) {
|
||||
}
|
||||
// Lookup tokens if requested
|
||||
ethPluginProvideToken_t pluginProvideToken;
|
||||
eth_plugin_prepare_provide_token(&pluginProvideToken);
|
||||
if ((pluginFinalize.tokenLookup1 != NULL) || (pluginFinalize.tokenLookup2 != NULL)) {
|
||||
if (pluginFinalize.tokenLookup1 != NULL) {
|
||||
PRINTF("Lookup1: %.*H\n", ADDRESS_LENGTH, pluginFinalize.tokenLookup1);
|
||||
token1 = getKnownToken(pluginFinalize.tokenLookup1);
|
||||
if (token1 != NULL) {
|
||||
PRINTF("Token1 ticker: %s\n", token1->ticker);
|
||||
pluginProvideToken.token1 = getKnownToken(pluginFinalize.tokenLookup1);
|
||||
if (pluginProvideToken.token1 != NULL) {
|
||||
PRINTF("Token1 ticker: %s\n", pluginProvideToken.token1->ticker);
|
||||
}
|
||||
}
|
||||
if (pluginFinalize.tokenLookup2 != NULL) {
|
||||
PRINTF("Lookup2: %.*H\n", ADDRESS_LENGTH, pluginFinalize.tokenLookup2);
|
||||
token2 = getKnownToken(pluginFinalize.tokenLookup2);
|
||||
if (token2 != NULL) {
|
||||
PRINTF("Token2 ticker: %s\n", token2->ticker);
|
||||
pluginProvideToken.token2 = getKnownToken(pluginFinalize.tokenLookup2);
|
||||
if (pluginProvideToken.token2 != NULL) {
|
||||
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) <=
|
||||
ETH_PLUGIN_RESULT_UNSUCCESSFUL) {
|
||||
PRINTF("Plugin provide token call failed\n");
|
||||
@@ -384,9 +411,9 @@ void finalizeParsing(bool direct) {
|
||||
tmpContent.txContent.value.length = 32;
|
||||
memmove(tmpContent.txContent.destination, pluginFinalize.address, 20);
|
||||
tmpContent.txContent.destinationLength = 20;
|
||||
if (token1 != NULL) {
|
||||
decimals = token1->decimals;
|
||||
ticker = token1->ticker;
|
||||
if (pluginProvideToken.token1 != NULL) {
|
||||
decimals = pluginProvideToken.token1->decimals;
|
||||
ticker = pluginProvideToken.token1->ticker;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -407,48 +434,50 @@ void finalizeParsing(bool direct) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare destination address to display
|
||||
if (genericUI) {
|
||||
if (tmpContent.txContent.destinationLength != 0) {
|
||||
displayBuffer[0] = '0';
|
||||
displayBuffer[1] = 'x';
|
||||
getEthAddressStringFromBinary(tmpContent.txContent.destination,
|
||||
(uint8_t *) displayBuffer + 2,
|
||||
displayBuffer + 2,
|
||||
&global_sha3,
|
||||
chainConfig);
|
||||
compareOrCopy(strings.common.fullAddress, displayBuffer, called_from_swap);
|
||||
compareOrCopy(strings.common.fullAddress,
|
||||
sizeof(strings.common.fullAddress),
|
||||
displayBuffer,
|
||||
called_from_swap);
|
||||
} else {
|
||||
strcpy(strings.common.fullAddress, "Contract");
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare amount to display
|
||||
if (genericUI) {
|
||||
amountToString(tmpContent.txContent.value.value,
|
||||
tmpContent.txContent.value.length,
|
||||
decimals,
|
||||
(char *) ticker,
|
||||
ticker,
|
||||
displayBuffer,
|
||||
sizeof(displayBuffer));
|
||||
compareOrCopy(strings.common.fullAmount, displayBuffer, called_from_swap);
|
||||
}
|
||||
// Prepare nonce to display
|
||||
if (genericUI) {
|
||||
uint256_t nonce;
|
||||
convertUint256BE(tmpContent.txContent.nonce.value,
|
||||
tmpContent.txContent.nonce.length,
|
||||
&nonce);
|
||||
tostring256(&nonce, 10, displayBuffer, sizeof(displayBuffer));
|
||||
strncpy(strings.common.nonce, displayBuffer, sizeof(strings.common.nonce));
|
||||
}
|
||||
// Compute maximum fee
|
||||
if (genericUI) {
|
||||
prepareFeeDisplay();
|
||||
compareOrCopy(strings.common.fullAmount,
|
||||
sizeof(strings.common.fullAddress),
|
||||
displayBuffer,
|
||||
called_from_swap);
|
||||
}
|
||||
|
||||
// Prepare nonce to display
|
||||
uint256_t nonce;
|
||||
convertUint256BE(tmpContent.txContent.nonce.value, tmpContent.txContent.nonce.length, &nonce);
|
||||
tostring256(&nonce, 10, displayBuffer, sizeof(displayBuffer));
|
||||
strlcpy(strings.common.nonce, displayBuffer, sizeof(strings.common.nonce));
|
||||
|
||||
// Compute maximum fee
|
||||
prepareFeeDisplay();
|
||||
|
||||
// Prepare chainID field
|
||||
if (genericUI) {
|
||||
prepareChainIdDisplay();
|
||||
}
|
||||
prepareNetworkDisplay();
|
||||
|
||||
bool no_consent;
|
||||
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
#include "utils.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 signature[100];
|
||||
uint8_t signatureLength;
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
uint32_t tx = 0;
|
||||
uint32_t v = u32_from_BE(tmpContent.txContent.v, tmpContent.txContent.vLength, true);
|
||||
@@ -19,14 +18,14 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
|
||||
explicit_bzero(privateKeyData, sizeof(privateKeyData));
|
||||
unsigned int info = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
signatureLength = cx_ecdsa_sign(&privateKey,
|
||||
CX_RND_RFC6979 | CX_LAST,
|
||||
CX_SHA256,
|
||||
tmpCtx.transactionContext.hash,
|
||||
sizeof(tmpCtx.transactionContext.hash),
|
||||
signature,
|
||||
sizeof(signature),
|
||||
&info);
|
||||
cx_ecdsa_sign(&privateKey,
|
||||
CX_RND_RFC6979 | CX_LAST,
|
||||
CX_SHA256,
|
||||
tmpCtx.transactionContext.hash,
|
||||
sizeof(tmpCtx.transactionContext.hash),
|
||||
signature,
|
||||
sizeof(signature),
|
||||
&info);
|
||||
explicit_bzero(&privateKey, sizeof(privateKey));
|
||||
if (txContext.txType == EIP1559 || txContext.txType == EIP2930) {
|
||||
if (info & CX_ECCINFO_PARITY_ODD) {
|
||||
@@ -66,7 +65,7 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
|
||||
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();
|
||||
G_io_apdu_buffer[0] = 0x69;
|
||||
G_io_apdu_buffer[1] = 0x85;
|
||||
@@ -77,7 +76,7 @@ unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) {
|
||||
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;
|
||||
txResult = continueTx(&txContext);
|
||||
switch (txResult) {
|
||||
@@ -108,7 +107,7 @@ unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) {
|
||||
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();
|
||||
io_seproxyhal_send_status(0x6985);
|
||||
// Display back the original UX
|
||||
|
||||
@@ -3,80 +3,9 @@
|
||||
#include "chainConfig.h"
|
||||
#include "utils.h"
|
||||
#include "feature_signTx.h"
|
||||
#include "network.h"
|
||||
#include "eth_plugin_handler.h"
|
||||
|
||||
void plugin_ui_get_id() {
|
||||
ethQueryContractID_t pluginQueryContractID;
|
||||
eth_plugin_prepare_query_contract_ID(&pluginQueryContractID,
|
||||
strings.common.fullAddress,
|
||||
sizeof(strings.common.fullAddress),
|
||||
strings.common.fullAmount,
|
||||
sizeof(strings.common.fullAmount));
|
||||
// Query the original contract for ID if it's not an internal alias
|
||||
if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_ID, (void *) &pluginQueryContractID)) {
|
||||
PRINTF("Plugin query contract ID call failed\n");
|
||||
io_seproxyhal_touch_tx_cancel(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void plugin_ui_get_item() {
|
||||
ethQueryContractUI_t pluginQueryContractUI;
|
||||
eth_plugin_prepare_query_contract_UI(&pluginQueryContractUI,
|
||||
dataContext.tokenContext.pluginUiCurrentItem,
|
||||
strings.common.fullAddress,
|
||||
sizeof(strings.common.fullAddress),
|
||||
strings.common.fullAmount,
|
||||
sizeof(strings.common.fullAmount));
|
||||
if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_UI, (void *) &pluginQueryContractUI)) {
|
||||
PRINTF("Plugin query contract UI call failed\n");
|
||||
io_seproxyhal_touch_tx_cancel(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void display_next_plugin_item(bool entering) {
|
||||
if (entering) {
|
||||
if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) {
|
||||
dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE;
|
||||
dataContext.tokenContext.pluginUiCurrentItem = 0;
|
||||
plugin_ui_get_item();
|
||||
ux_flow_next();
|
||||
} else {
|
||||
if (dataContext.tokenContext.pluginUiCurrentItem > 0) {
|
||||
dataContext.tokenContext.pluginUiCurrentItem--;
|
||||
plugin_ui_get_item();
|
||||
ux_flow_next();
|
||||
} else {
|
||||
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
|
||||
dataContext.tokenContext.pluginUiCurrentItem = 0;
|
||||
ux_flow_prev();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) {
|
||||
dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE;
|
||||
plugin_ui_get_item();
|
||||
ux_flow_prev();
|
||||
} else {
|
||||
if (dataContext.tokenContext.pluginUiCurrentItem <
|
||||
dataContext.tokenContext.pluginUiMaxItems - 1) {
|
||||
dataContext.tokenContext.pluginUiCurrentItem++;
|
||||
plugin_ui_get_item();
|
||||
ux_flow_prev();
|
||||
// Reset multi page layout to the first page
|
||||
G_ux.layout_paging.current = 0;
|
||||
#ifdef TARGET_NANOS
|
||||
ux_layout_paging_redisplay_by_addr(G_ux.stack_count - 1);
|
||||
#else
|
||||
ux_layout_bnnn_paging_redisplay(0);
|
||||
#endif
|
||||
} else {
|
||||
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
|
||||
ux_flow_next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
UX_STEP_NOCB(
|
||||
ux_confirm_selector_flow_1_step,
|
||||
@@ -224,11 +153,11 @@ UX_STEP_NOCB(
|
||||
.text = strings.common.maxFee,
|
||||
});
|
||||
UX_STEP_NOCB(
|
||||
ux_approval_chainid_step,
|
||||
ux_approval_network_step,
|
||||
bnnn_paging,
|
||||
{
|
||||
.title = "Chain ID",
|
||||
.text = strings.common.chainID,
|
||||
.title = "Network",
|
||||
.text = strings.common.network_name,
|
||||
});
|
||||
|
||||
UX_STEP_CB(
|
||||
@@ -277,15 +206,13 @@ void ux_approve_tx(bool fromPlugin) {
|
||||
}
|
||||
|
||||
if (fromPlugin) {
|
||||
// If we're coming from a plugin then we need to prepare the display.
|
||||
prepareChainIdDisplay();
|
||||
prepareFeeDisplay();
|
||||
|
||||
// Add the special dynamic display logic
|
||||
ux_approval_tx_flow[step++] = &ux_plugin_approval_id_step;
|
||||
ux_approval_tx_flow[step++] = &ux_plugin_approval_before_step;
|
||||
ux_approval_tx_flow[step++] = &ux_plugin_approval_display_step;
|
||||
ux_approval_tx_flow[step++] = &ux_plugin_approval_after_step;
|
||||
} else {
|
||||
// We're in a regular transaction, just show the amount and the address
|
||||
ux_approval_tx_flow[step++] = &ux_approval_amount_step;
|
||||
ux_approval_tx_flow[step++] = &ux_approval_address_step;
|
||||
}
|
||||
@@ -294,19 +221,12 @@ void ux_approve_tx(bool fromPlugin) {
|
||||
ux_approval_tx_flow[step++] = &ux_approval_nonce_step;
|
||||
}
|
||||
|
||||
uint32_t id;
|
||||
if (txContext.txType == LEGACY) {
|
||||
id = u32_from_BE(txContext.content->v, txContext.content->vLength, true);
|
||||
} else if (txContext.txType == EIP2930 || txContext.txType == EIP1559) {
|
||||
id =
|
||||
u32_from_BE(txContext.content->chainID.value, txContext.content->chainID.length, false);
|
||||
} else {
|
||||
PRINTF("TxType `%u` not supported while preparing to approve tx\n", txContext.txType);
|
||||
THROW(0x6501);
|
||||
}
|
||||
if (id != ETHEREUM_MAINNET_CHAINID) {
|
||||
ux_approval_tx_flow[step++] = &ux_approval_chainid_step;
|
||||
uint32_t chain_id = get_chain_id();
|
||||
if (chainConfig->chainId == ETHEREUM_MAINNET_CHAINID && chain_id != chainConfig->chainId) {
|
||||
// TODO: do we need the `&&` above?
|
||||
ux_approval_tx_flow[step++] = &ux_approval_network_step;
|
||||
}
|
||||
|
||||
ux_approval_tx_flow[step++] = &ux_approval_fees_step;
|
||||
ux_approval_tx_flow[step++] = &ux_approval_accept_step;
|
||||
ux_approval_tx_flow[step++] = &ux_approval_reject_step;
|
||||
|
||||
82
src_features/signTx/ui_plugin.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "feature_signTx.h"
|
||||
#include "ux.h"
|
||||
#include "eth_plugin_handler.h"
|
||||
#include "ui_callbacks.h"
|
||||
#include "ui_plugin.h"
|
||||
|
||||
#ifdef TARGET_NANOS
|
||||
// This function is not exported by the SDK
|
||||
void ux_layout_paging_redisplay_by_addr(unsigned int stack_slot);
|
||||
#endif
|
||||
|
||||
void plugin_ui_get_id() {
|
||||
ethQueryContractID_t pluginQueryContractID;
|
||||
eth_plugin_prepare_query_contract_ID(&pluginQueryContractID,
|
||||
strings.common.fullAddress,
|
||||
sizeof(strings.common.fullAddress),
|
||||
strings.common.fullAmount,
|
||||
sizeof(strings.common.fullAmount));
|
||||
// Query the original contract for ID if it's not an internal alias
|
||||
if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_ID, (void *) &pluginQueryContractID)) {
|
||||
PRINTF("Plugin query contract ID call failed\n");
|
||||
io_seproxyhal_touch_tx_cancel(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void plugin_ui_get_item() {
|
||||
ethQueryContractUI_t pluginQueryContractUI;
|
||||
eth_plugin_prepare_query_contract_UI(&pluginQueryContractUI,
|
||||
dataContext.tokenContext.pluginUiCurrentItem,
|
||||
strings.common.fullAddress,
|
||||
sizeof(strings.common.fullAddress),
|
||||
strings.common.fullAmount,
|
||||
sizeof(strings.common.fullAmount));
|
||||
if (!eth_plugin_call(ETH_PLUGIN_QUERY_CONTRACT_UI, (void *) &pluginQueryContractUI)) {
|
||||
PRINTF("Plugin query contract UI call failed\n");
|
||||
io_seproxyhal_touch_tx_cancel(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void display_next_plugin_item(bool entering) {
|
||||
if (entering) {
|
||||
if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) {
|
||||
dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE;
|
||||
dataContext.tokenContext.pluginUiCurrentItem = 0;
|
||||
plugin_ui_get_item();
|
||||
ux_flow_next();
|
||||
} else {
|
||||
if (dataContext.tokenContext.pluginUiCurrentItem > 0) {
|
||||
dataContext.tokenContext.pluginUiCurrentItem--;
|
||||
plugin_ui_get_item();
|
||||
ux_flow_next();
|
||||
} else {
|
||||
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
|
||||
dataContext.tokenContext.pluginUiCurrentItem = 0;
|
||||
ux_flow_prev();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) {
|
||||
dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE;
|
||||
plugin_ui_get_item();
|
||||
ux_flow_prev();
|
||||
} else {
|
||||
if (dataContext.tokenContext.pluginUiCurrentItem <
|
||||
dataContext.tokenContext.pluginUiMaxItems - 1) {
|
||||
dataContext.tokenContext.pluginUiCurrentItem++;
|
||||
plugin_ui_get_item();
|
||||
ux_flow_prev();
|
||||
// Reset multi page layout to the first page
|
||||
G_ux.layout_paging.current = 0;
|
||||
#ifdef TARGET_NANOS
|
||||
ux_layout_paging_redisplay_by_addr(G_ux.stack_count - 1);
|
||||
#else
|
||||
ux_layout_bnnn_paging_redisplay(0);
|
||||
#endif
|
||||
} else {
|
||||
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
|
||||
ux_flow_next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
5
src_features/signTx/ui_plugin.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void plugin_ui_get_id();
|
||||
void plugin_ui_get_item();
|
||||
void display_next_plugin_item(bool entering);
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "ui_callbacks.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();
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
#include "ui_flow.h"
|
||||
|
||||
void handleStarkwareProvideQuantum(uint8_t p1,
|
||||
uint8_t p2,
|
||||
__attribute__((unused)) uint8_t p2,
|
||||
uint8_t *dataBuffer,
|
||||
uint16_t dataLength,
|
||||
unsigned int *flags,
|
||||
unsigned int *tx) {
|
||||
__attribute__((unused)) unsigned int *flags,
|
||||
__attribute__((unused)) unsigned int *tx) {
|
||||
size_t i = 0;
|
||||
uint8_t expectedDataSize = 20 + 32;
|
||||
uint8_t addressZero = 0;
|
||||
|
||||
@@ -16,7 +16,7 @@ void handleStarkwareSignMessage(uint8_t p1,
|
||||
uint8_t *dataBuffer,
|
||||
uint16_t dataLength,
|
||||
unsigned int *flags,
|
||||
unsigned int *tx) {
|
||||
__attribute__((unused)) unsigned int *tx) {
|
||||
uint8_t privateKeyData[INT256_LENGTH];
|
||||
uint32_t i;
|
||||
uint8_t bip32PathLength = *(dataBuffer);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "stark_utils.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 signature[72];
|
||||
uint32_t tx = 0;
|
||||
|
||||
@@ -17,7 +17,7 @@ void stark_sign_display_condition_address() {
|
||||
strings.tmp.tmp[0] = '0';
|
||||
strings.tmp.tmp[1] = 'x';
|
||||
getEthAddressStringFromBinary(dataContext.starkContext.conditionAddress,
|
||||
(uint8_t *) (strings.tmp.tmp + 2),
|
||||
strings.tmp.tmp + 2,
|
||||
&global_sha3,
|
||||
chainConfig);
|
||||
strings.tmp.tmp[42] = '\0';
|
||||
|
||||
@@ -11,7 +11,7 @@ void handleStarkwareUnsafeSign(uint8_t p1,
|
||||
uint8_t *dataBuffer,
|
||||
uint16_t dataLength,
|
||||
unsigned int *flags,
|
||||
unsigned int *tx) {
|
||||
__attribute__((unused)) unsigned int *tx) {
|
||||
uint32_t i;
|
||||
uint8_t privateKeyData[INT256_LENGTH];
|
||||
cx_ecfp_public_key_t publicKey;
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#include "stark_utils.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;
|
||||
uint8_t privateKeyData[INT256_LENGTH];
|
||||
uint8_t signature[72];
|
||||
|
||||
@@ -30,7 +30,7 @@ static const uint8_t COMPOUND_EXPECTED_DATA_SIZE[] = {
|
||||
typedef struct compound_parameters_t {
|
||||
uint8_t selectorIndex;
|
||||
uint8_t amount[32];
|
||||
uint8_t ticker_1[MAX_TICKER_LEN];
|
||||
char ticker_1[MAX_TICKER_LEN];
|
||||
uint8_t decimals;
|
||||
} compound_parameters_t;
|
||||
|
||||
@@ -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
|
||||
future, we will have to move to a CAL based architecture instead, as this one doesn't scale well.*/
|
||||
#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},
|
||||
{"CETH", 18},
|
||||
{"CUSDC", 6},
|
||||
@@ -153,15 +153,15 @@ void compound_plugin_call(int message, void *parameters) {
|
||||
compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext;
|
||||
PRINTF("compound plugin provide token: %d\n", (msg->token1 != NULL));
|
||||
if (msg->token1 != NULL) {
|
||||
strcpy((char *) context->ticker_1, (char *) msg->token1->ticker);
|
||||
strlcpy(context->ticker_1, msg->token1->ticker, MAX_TICKER_LEN);
|
||||
switch (context->selectorIndex) {
|
||||
case COMPOUND_REDEEM_UNDERLYING:
|
||||
case COMPOUND_MINT:
|
||||
case CETH_MINT:
|
||||
msg->result = get_underlying_asset_decimals((char *) &context->ticker_1,
|
||||
&context->decimals)
|
||||
? ETH_PLUGIN_RESULT_OK
|
||||
: ETH_PLUGIN_RESULT_FALLBACK;
|
||||
msg->result =
|
||||
get_underlying_asset_decimals(context->ticker_1, &context->decimals)
|
||||
? ETH_PLUGIN_RESULT_OK
|
||||
: ETH_PLUGIN_RESULT_FALLBACK;
|
||||
break;
|
||||
|
||||
// Only case where we use the compound contract decimals
|
||||
@@ -182,22 +182,22 @@ void compound_plugin_call(int message, void *parameters) {
|
||||
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
|
||||
ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
|
||||
compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext;
|
||||
strcpy(msg->name, "Type");
|
||||
strlcpy(msg->name, "Type", msg->nameLength);
|
||||
switch (context->selectorIndex) {
|
||||
case COMPOUND_REDEEM_UNDERLYING:
|
||||
case COMPOUND_REDEEM:
|
||||
strcpy(msg->version, "Redeem");
|
||||
strlcpy(msg->version, "Redeem", msg->versionLength);
|
||||
break;
|
||||
|
||||
case COMPOUND_MINT:
|
||||
case CETH_MINT:
|
||||
strcpy(msg->version, "Lend");
|
||||
strlcpy(msg->version, "Lend", msg->versionLength);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
strcat(msg->version, " Assets");
|
||||
strlcat(msg->version, " Assets", msg->versionLength);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
} break;
|
||||
|
||||
@@ -206,8 +206,8 @@ void compound_plugin_call(int message, void *parameters) {
|
||||
compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext;
|
||||
switch (msg->screenIndex) {
|
||||
case 0: {
|
||||
strcpy(msg->title, "Amount");
|
||||
char *ticker_ptr = (char *) context->ticker_1;
|
||||
strlcpy(msg->title, "Amount", msg->titleLength);
|
||||
char *ticker_ptr = context->ticker_1;
|
||||
/* skip "c" in front of cToken unless we use "redeem", as
|
||||
redeem is the only operation dealing with a cToken amount */
|
||||
if (context->selectorIndex != COMPOUND_REDEEM) {
|
||||
@@ -223,11 +223,11 @@ void compound_plugin_call(int message, void *parameters) {
|
||||
} break;
|
||||
|
||||
case 1:
|
||||
strcpy(msg->title, "Contract");
|
||||
strcpy(msg->msg, "Compound ");
|
||||
strcat(msg->msg,
|
||||
(char *) context->ticker_1 +
|
||||
1); // remove the 'c' char at beginning of compound ticker
|
||||
strlcpy(msg->title, "Contract", msg->titleLength);
|
||||
strlcpy(msg->msg, "Compound ", msg->msgLength);
|
||||
strlcat(msg->msg,
|
||||
context->ticker_1 + 1,
|
||||
msg->msgLength); // remove the 'c' char at beginning of compound ticker
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -16,10 +16,10 @@ typedef struct erc20_parameters_t {
|
||||
uint8_t selectorIndex;
|
||||
uint8_t destinationAddress[21];
|
||||
uint8_t amount[INT256_LENGTH];
|
||||
uint8_t ticker[MAX_TICKER_LEN];
|
||||
char ticker[MAX_TICKER_LEN];
|
||||
uint8_t decimals;
|
||||
uint8_t target;
|
||||
uint8_t contract_name[MAX_CONTRACT_NAME_LEN];
|
||||
char contract_name[MAX_CONTRACT_NAME_LEN];
|
||||
} erc20_parameters_t;
|
||||
|
||||
typedef struct contract_t {
|
||||
@@ -27,8 +27,8 @@ typedef struct contract_t {
|
||||
uint8_t address[ADDRESS_LENGTH];
|
||||
} contract_t;
|
||||
|
||||
#define NUM_CONTRACTS 11
|
||||
const contract_t const CONTRACTS[NUM_CONTRACTS] = {
|
||||
#define NUM_CONTRACTS 13
|
||||
const contract_t CONTRACTS[NUM_CONTRACTS] = {
|
||||
// Compound
|
||||
{"Compound DAI", {0x5d, 0x3a, 0x53, 0x6e, 0x4d, 0x6d, 0xbd, 0x61, 0x14, 0xcc,
|
||||
0x1e, 0xad, 0x35, 0x77, 0x7b, 0xab, 0x94, 0x8e, 0x36, 0x43}},
|
||||
@@ -52,15 +52,21 @@ const contract_t const CONTRACTS[NUM_CONTRACTS] = {
|
||||
0x48, 0x73, 0xd0, 0x0f, 0xf8, 0x5b, 0xcc, 0xde, 0xd5, 0x50}},
|
||||
// Paraswap
|
||||
{"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) {
|
||||
for (size_t i = 0; i < NUM_CONTRACTS; i++) {
|
||||
contract_t *contract = (contract_t *) PIC(&CONTRACTS[i]);
|
||||
if (memcmp(contract->address, context->destinationAddress, ADDRESS_LENGTH) == 0) {
|
||||
strncpy((char *) context->contract_name,
|
||||
contract->name,
|
||||
sizeof(context->contract_name));
|
||||
strlcpy(context->contract_name, contract->name, sizeof(context->contract_name));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -161,7 +167,7 @@ void erc20_plugin_call(int message, void *parameters) {
|
||||
(msg->token2 != NULL));
|
||||
if (msg->token1 != NULL) {
|
||||
context->target = TARGET_ADDRESS;
|
||||
strcpy((char *) context->ticker, (char *) msg->token1->ticker);
|
||||
strlcpy(context->ticker, msg->token1->ticker, MAX_TICKER_LEN);
|
||||
context->decimals = msg->token1->decimals;
|
||||
if (context->selectorIndex == ERC20_APPROVE) {
|
||||
if (check_contract(context)) {
|
||||
@@ -176,8 +182,8 @@ void erc20_plugin_call(int message, void *parameters) {
|
||||
|
||||
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
|
||||
ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
|
||||
strcpy(msg->name, "Type");
|
||||
strcpy(msg->version, "Approve");
|
||||
strlcpy(msg->name, "Type", msg->nameLength);
|
||||
strlcpy(msg->version, "Approve", msg->versionLength);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
} break;
|
||||
|
||||
@@ -186,15 +192,15 @@ void erc20_plugin_call(int message, void *parameters) {
|
||||
erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
|
||||
switch (msg->screenIndex) {
|
||||
case 0:
|
||||
strcpy(msg->title, "Amount");
|
||||
strlcpy(msg->title, "Amount", msg->titleLength);
|
||||
if (ismaxint(context->amount, sizeof(context->amount))) {
|
||||
strcpy(msg->msg, "Unlimited ");
|
||||
strcat(msg->msg, (char *) context->ticker);
|
||||
strlcpy(msg->msg, "Unlimited ", msg->msgLength);
|
||||
strlcat(msg->msg, context->ticker, msg->msgLength);
|
||||
} else {
|
||||
amountToString(context->amount,
|
||||
sizeof(context->amount),
|
||||
context->decimals,
|
||||
(char *) context->ticker,
|
||||
context->ticker,
|
||||
msg->msg,
|
||||
100);
|
||||
}
|
||||
@@ -202,14 +208,14 @@ void erc20_plugin_call(int message, void *parameters) {
|
||||
break;
|
||||
case 1:
|
||||
if (context->target >= TARGET_CONTRACT) {
|
||||
strcpy(msg->title, "Contract");
|
||||
strcpy(msg->msg, (char *) context->contract_name);
|
||||
strlcpy(msg->title, "Contract", msg->titleLength);
|
||||
strlcpy(msg->msg, context->contract_name, msg->msgLength);
|
||||
} else {
|
||||
strcpy(msg->title, "Address");
|
||||
strlcpy(msg->title, "Address", msg->titleLength);
|
||||
msg->msg[0] = '0';
|
||||
msg->msg[1] = 'x';
|
||||
getEthAddressStringFromBinary(context->destinationAddress,
|
||||
(uint8_t *) msg->msg + 2,
|
||||
msg->msg + 2,
|
||||
msg->pluginSharedRW->sha3,
|
||||
chainConfig);
|
||||
}
|
||||
|
||||
@@ -108,8 +108,8 @@ void erc721_plugin_call(int message, void *parameters) {
|
||||
|
||||
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
|
||||
ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
|
||||
strcpy(msg->name, "Allowance");
|
||||
strcpy(msg->version, "");
|
||||
strlcpy(msg->name, "Allowance", msg->nameLength);
|
||||
strlcpy(msg->version, "", msg->versionLength);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
} break;
|
||||
|
||||
@@ -118,19 +118,19 @@ void erc721_plugin_call(int message, void *parameters) {
|
||||
erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
|
||||
switch (msg->screenIndex) {
|
||||
case 0:
|
||||
strcpy(msg->title, "Contract Name");
|
||||
strlcpy(msg->title, "Contract Name", msg->titleLength);
|
||||
starkware_print_eth_address(tmpContent.txContent.destination, msg->msg);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
strcpy(msg->title, "NFT Contract");
|
||||
strlcpy(msg->title, "NFT Contract", msg->titleLength);
|
||||
starkware_print_eth_address(context->address, msg->msg);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
strcpy(msg->title, "TokenID");
|
||||
strlcpy(msg->title, "TokenID", msg->titleLength);
|
||||
starkware_print_stark_key(context->tokenId, msg->msg);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
break;
|
||||
|
||||
@@ -32,21 +32,13 @@ typedef struct eth2_deposit_parameters_t {
|
||||
char deposit_address[ETH2_DEPOSIT_PUBKEY_LENGTH];
|
||||
} 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
|
||||
// format by `in`. Does not check the size, so expects `out` to be big enough to hold the string
|
||||
// representation. Returns the length of string (counting the null terminating character).
|
||||
static int getEthDisplayableAddress(char *out, uint8_t *in, cx_sha3_t *sha3) {
|
||||
out[0] = '0';
|
||||
out[1] = 'x';
|
||||
getEthAddressStringFromBinary(in, (uint8_t *) out + 2, sha3, chainConfig);
|
||||
getEthAddressStringFromBinary(in, out + 2, sha3, chainConfig);
|
||||
|
||||
uint8_t destinationLen = strlen(out) + 1; // Adding one to account for \0.
|
||||
|
||||
@@ -143,7 +135,7 @@ void eth2_plugin_call(int message, void *parameters) {
|
||||
msg->pluginSharedRW->sha3);
|
||||
|
||||
// Copy back the string to the global variable.
|
||||
strcpy(context->deposit_address, tmp);
|
||||
strlcpy(context->deposit_address, tmp, ETH2_DEPOSIT_PUBKEY_LENGTH);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
break;
|
||||
}
|
||||
@@ -206,8 +198,8 @@ void eth2_plugin_call(int message, void *parameters) {
|
||||
|
||||
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
|
||||
ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
|
||||
strcpy(msg->name, "ETH2");
|
||||
strcpy(msg->version, "Deposit");
|
||||
strlcpy(msg->name, "ETH2", msg->nameLength);
|
||||
strlcpy(msg->version, "Deposit", msg->versionLength);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
} break;
|
||||
|
||||
@@ -217,19 +209,19 @@ void eth2_plugin_call(int message, void *parameters) {
|
||||
switch (msg->screenIndex) {
|
||||
case 0: { // Amount screen
|
||||
uint8_t decimals = WEI_TO_ETHER;
|
||||
uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName);
|
||||
strcpy(msg->title, "Amount");
|
||||
char *ticker = chainConfig->coinName;
|
||||
strlcpy(msg->title, "Amount", msg->titleLength);
|
||||
amountToString(tmpContent.txContent.value.value,
|
||||
tmpContent.txContent.value.length,
|
||||
decimals,
|
||||
(char *) ticker,
|
||||
ticker,
|
||||
msg->msg,
|
||||
100);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
} break;
|
||||
case 1: { // Deposit pubkey screen
|
||||
strcpy(msg->title, "Validator");
|
||||
strcpy(msg->msg, context->deposit_address);
|
||||
strlcpy(msg->title, "Validator", msg->titleLength);
|
||||
strlcpy(msg->msg, context->deposit_address, msg->msgLength);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -280,21 +280,25 @@ void starkware_print_stark_key(uint8_t *starkKey, char *destination) {
|
||||
}
|
||||
|
||||
// TODO : rewrite as independant code
|
||||
void starkware_print_eth_address(uint8_t *address, char *destination) {
|
||||
void starkware_print_eth_address(uint8_t *address, char *destination, size_t destinationLength) {
|
||||
if (destinationLength < 43) {
|
||||
strlcpy(destination, "ERROR", destinationLength);
|
||||
return;
|
||||
}
|
||||
destination[0] = '0';
|
||||
destination[1] = 'x';
|
||||
getEthAddressStringFromBinary(address,
|
||||
(uint8_t *) (destination + 2),
|
||||
&global_sha3,
|
||||
chainConfig);
|
||||
getEthAddressStringFromBinary(address, destination + 2, &global_sha3, chainConfig);
|
||||
destination[42] = '\0';
|
||||
}
|
||||
|
||||
// TODO : rewrite as independant code
|
||||
void starkware_print_amount(uint8_t *amountData, char *destination, bool forEscape) {
|
||||
void starkware_print_amount(uint8_t *amountData,
|
||||
char *destination,
|
||||
size_t destinationLength,
|
||||
bool forEscape) {
|
||||
uint256_t amount, amountPre, quantum;
|
||||
uint8_t decimals;
|
||||
char *ticker = (char *) PIC(chainConfig->coinName);
|
||||
char *ticker = chainConfig->coinName;
|
||||
|
||||
if ((amountData == NULL) ||
|
||||
(forEscape && (dataContext.tokenContext.quantumIndex == MAX_TOKEN))) {
|
||||
@@ -310,7 +314,7 @@ void starkware_print_amount(uint8_t *amountData, char *destination, bool forEsca
|
||||
tokenDefinition_t *token =
|
||||
&tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex];
|
||||
decimals = token->decimals;
|
||||
ticker = (char *) token->ticker;
|
||||
ticker = token->ticker;
|
||||
readu256BE(amountData, &amountPre);
|
||||
}
|
||||
if (amountData != NULL) {
|
||||
@@ -318,35 +322,35 @@ void starkware_print_amount(uint8_t *amountData, char *destination, bool forEsca
|
||||
mul256(&amountPre, &quantum, &amount);
|
||||
}
|
||||
tostring256(&amount, 10, (char *) (G_io_apdu_buffer + 100), 100);
|
||||
strcpy(destination, ticker);
|
||||
strlcpy(destination, ticker, destinationLength);
|
||||
adjustDecimals((char *) (G_io_apdu_buffer + 100),
|
||||
strlen((char *) (G_io_apdu_buffer + 100)),
|
||||
destination + strlen(ticker),
|
||||
50 - strlen(ticker),
|
||||
destinationLength - strlen(ticker),
|
||||
decimals);
|
||||
}
|
||||
|
||||
// TODO : rewrite as independant code
|
||||
void starkware_print_ticker(char *destination) {
|
||||
char *ticker = (char *) PIC(chainConfig->coinName);
|
||||
void starkware_print_ticker(char *destination, size_t destinationLength) {
|
||||
char *ticker = chainConfig->coinName;
|
||||
|
||||
if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) {
|
||||
tokenDefinition_t *token =
|
||||
&tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex];
|
||||
ticker = (char *) token->ticker;
|
||||
ticker = token->ticker;
|
||||
}
|
||||
strcpy(destination, ticker);
|
||||
strlcpy(destination, ticker, destinationLength);
|
||||
}
|
||||
|
||||
// TODO : rewrite as independant code
|
||||
void starkware_print_asset_contract(char *destination) {
|
||||
void starkware_print_asset_contract(char *destination, size_t destinationLength) {
|
||||
// token has been validated to be present previously
|
||||
if (dataContext.tokenContext.quantumIndex != MAX_TOKEN) {
|
||||
tokenDefinition_t *token =
|
||||
&tmpCtx.transactionContext.tokens[dataContext.tokenContext.quantumIndex];
|
||||
starkware_print_eth_address(token->address, destination);
|
||||
starkware_print_eth_address(token->address, destination, destinationLength);
|
||||
} else {
|
||||
strcpy(destination, "UNKNOWN");
|
||||
strlcpy(destination, "UNKNOWN", destinationLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,10 +372,7 @@ void starkware_get_source_address(char *destination) {
|
||||
io_seproxyhal_io_heartbeat();
|
||||
destination[0] = '0';
|
||||
destination[1] = 'x';
|
||||
getEthAddressStringFromKey(&publicKey,
|
||||
(uint8_t *) (destination + 2),
|
||||
&global_sha3,
|
||||
chainConfig);
|
||||
getEthAddressStringFromKey(&publicKey, destination + 2, &global_sha3, chainConfig);
|
||||
destination[42] = '\0';
|
||||
}
|
||||
|
||||
@@ -646,54 +647,55 @@ void starkware_plugin_call(int message, void *parameters) {
|
||||
PRINTF("starkware query contract id\n");
|
||||
switch (context->selectorIndex) {
|
||||
case STARKWARE_REGISTER:
|
||||
strcpy(msg->name, "Register");
|
||||
strlcpy(msg->name, "Register", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_DEPOSIT_TOKEN:
|
||||
case STARKWARE_DEPOSIT_ETH:
|
||||
case STARKWARE_DEPOSIT_NFT:
|
||||
case STARKWARE_PROXY_DEPOSIT_TOKEN:
|
||||
case STARKWARE_PROXY_DEPOSIT_ETH:
|
||||
strcpy(msg->name, "Deposit");
|
||||
strlcpy(msg->name, "Deposit", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_DEPOSIT_CANCEL:
|
||||
strcpy(msg->name, "Cancel Deposit");
|
||||
strlcpy(msg->name, "Cancel Deposit", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_DEPOSIT_RECLAIM:
|
||||
case STARKWARE_DEPOSIT_NFT_RECLAIM:
|
||||
strcpy(msg->name, "Reclaim Deposit");
|
||||
strlcpy(msg->name, "Reclaim Deposit", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_WITHDRAW:
|
||||
case STARKWARE_WITHDRAW_NFT:
|
||||
case STARKWARE_WITHDRAW_AND_MINT:
|
||||
strcpy(msg->name, "Withdrawal");
|
||||
strlcpy(msg->name, "Withdrawal", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_FULL_WITHDRAW:
|
||||
strcpy(msg->name, "Full Withdrawal");
|
||||
strlcpy(msg->name, "Full Withdrawal", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_FREEZE:
|
||||
strcpy(msg->name, "Freeze");
|
||||
strlcpy(msg->name, "Freeze", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_ESCAPE:
|
||||
strcpy(msg->name, "Escape");
|
||||
strlcpy(msg->name, "Escape", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_VERIFY_ESCAPE:
|
||||
strcpy(msg->name, "Verify Escape");
|
||||
strlcpy(msg->name, "Verify Escape", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_WITHDRAW_TO:
|
||||
case STARKWARE_WITHDRAW_NFT_TO:
|
||||
strcpy(msg->name, "Withdrawal To");
|
||||
strlcpy(msg->name, "Withdrawal To", msg->nameLength);
|
||||
break;
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN:
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_ETH:
|
||||
strcpy(msg->name, "Register&Deposit");
|
||||
strlcpy(msg->name, "Register&Deposit", msg->nameLength);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
strcpy(msg->version,
|
||||
is_deversify_contract(tmpContent.txContent.destination) ? "DeversiFi"
|
||||
: "Starkware");
|
||||
strlcpy(
|
||||
msg->version,
|
||||
is_deversify_contract(tmpContent.txContent.destination) ? "DeversiFi" : "Starkware",
|
||||
msg->versionLength);
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
} break;
|
||||
|
||||
@@ -702,11 +704,13 @@ void starkware_plugin_call(int message, void *parameters) {
|
||||
starkware_parameters_t *context = (starkware_parameters_t *) msg->pluginContext;
|
||||
switch (msg->screenIndex) {
|
||||
case 0:
|
||||
strcpy(msg->title, "Contract Name");
|
||||
strlcpy(msg->title, "Contract Name", msg->titleLength);
|
||||
if (is_deversify_contract(tmpContent.txContent.destination)) {
|
||||
strcpy(msg->msg, "DeversiFi");
|
||||
strlcpy(msg->msg, "DeversiFi", msg->msgLength);
|
||||
} else {
|
||||
starkware_print_eth_address(tmpContent.txContent.destination, msg->msg);
|
||||
starkware_print_eth_address(tmpContent.txContent.destination,
|
||||
msg->msg,
|
||||
msg->msgLength);
|
||||
}
|
||||
msg->result = ETH_PLUGIN_RESULT_OK;
|
||||
break;
|
||||
@@ -715,12 +719,12 @@ void starkware_plugin_call(int message, void *parameters) {
|
||||
case STARKWARE_REGISTER:
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN:
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_ETH:
|
||||
strcpy(msg->title, "From ETH Address");
|
||||
starkware_print_eth_address(context->amount, msg->msg);
|
||||
strlcpy(msg->title, "From ETH Address", msg->titleLength);
|
||||
starkware_print_eth_address(context->amount, msg->msg, msg->msgLength);
|
||||
break;
|
||||
case STARKWARE_ESCAPE:
|
||||
strcpy(msg->title, "Amount");
|
||||
starkware_print_amount(context->amount, msg->msg, true);
|
||||
strlcpy(msg->title, "Amount", msg->titleLength);
|
||||
starkware_print_amount(context->amount, msg->msg, msg->msgLength, true);
|
||||
break;
|
||||
case STARKWARE_DEPOSIT_TOKEN:
|
||||
case STARKWARE_DEPOSIT_ETH:
|
||||
@@ -738,7 +742,7 @@ void starkware_plugin_call(int message, void *parameters) {
|
||||
case STARKWARE_WITHDRAW_AND_MINT:
|
||||
case STARKWARE_WITHDRAW_NFT:
|
||||
case STARKWARE_WITHDRAW_NFT_TO:
|
||||
strcpy(msg->title, "Master Account");
|
||||
strlcpy(msg->title, "Master Account", msg->titleLength);
|
||||
starkware_print_stark_key(context->starkKey, msg->msg);
|
||||
break;
|
||||
default:
|
||||
@@ -755,7 +759,7 @@ void starkware_plugin_call(int message, void *parameters) {
|
||||
case STARKWARE_ESCAPE:
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN:
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_ETH:
|
||||
strcpy(msg->title, "Master Account");
|
||||
strlcpy(msg->title, "Master Account", msg->titleLength);
|
||||
starkware_print_stark_key(context->starkKey, msg->msg);
|
||||
break;
|
||||
|
||||
@@ -769,22 +773,22 @@ void starkware_plugin_call(int message, void *parameters) {
|
||||
case STARKWARE_FREEZE:
|
||||
case STARKWARE_DEPOSIT_NFT:
|
||||
case STARKWARE_DEPOSIT_NFT_RECLAIM:
|
||||
strcpy(msg->title, "Token Account");
|
||||
strlcpy(msg->title, "Token Account", msg->titleLength);
|
||||
starkware_print_vault_id(U4BE(context->vaultId, 0), msg->msg);
|
||||
break;
|
||||
case STARKWARE_WITHDRAW:
|
||||
case STARKWARE_WITHDRAW_NFT:
|
||||
strcpy(msg->title, "To ETH Address");
|
||||
strlcpy(msg->title, "To ETH Address", msg->titleLength);
|
||||
starkware_get_source_address(msg->msg);
|
||||
break;
|
||||
case STARKWARE_WITHDRAW_TO:
|
||||
case STARKWARE_WITHDRAW_NFT_TO:
|
||||
strcpy(msg->title, "To ETH Address");
|
||||
starkware_print_eth_address(context->amount, msg->msg);
|
||||
strlcpy(msg->title, "To ETH Address", msg->titleLength);
|
||||
starkware_print_eth_address(context->amount, msg->msg, msg->msgLength);
|
||||
break;
|
||||
case STARKWARE_WITHDRAW_AND_MINT:
|
||||
strcpy(msg->title, "Asset Contract");
|
||||
starkware_print_asset_contract(msg->msg);
|
||||
strlcpy(msg->title, "Asset Contract", msg->titleLength);
|
||||
starkware_print_asset_contract(msg->msg, msg->msgLength);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -799,39 +803,40 @@ void starkware_plugin_call(int message, void *parameters) {
|
||||
case 3:
|
||||
switch (context->selectorIndex) {
|
||||
case STARKWARE_ESCAPE:
|
||||
strcpy(msg->title, "Token Account");
|
||||
strlcpy(msg->title, "Token Account", msg->titleLength);
|
||||
starkware_print_vault_id(U4BE(context->vaultId, 0), msg->msg);
|
||||
break;
|
||||
case STARKWARE_DEPOSIT_TOKEN:
|
||||
case STARKWARE_DEPOSIT_ETH:
|
||||
case STARKWARE_PROXY_DEPOSIT_TOKEN:
|
||||
case STARKWARE_PROXY_DEPOSIT_ETH:
|
||||
strcpy(msg->title, "Amount");
|
||||
strlcpy(msg->title, "Amount", msg->titleLength);
|
||||
starkware_print_amount(
|
||||
(((context->selectorIndex == STARKWARE_DEPOSIT_ETH) ||
|
||||
(context->selectorIndex == STARKWARE_PROXY_DEPOSIT_ETH))
|
||||
? NULL
|
||||
: context->amount),
|
||||
msg->msg,
|
||||
msg->msgLength,
|
||||
false);
|
||||
break;
|
||||
case STARKWARE_WITHDRAW:
|
||||
case STARKWARE_WITHDRAW_TO:
|
||||
strcpy(msg->title, "Token Symbol");
|
||||
starkware_print_ticker(msg->msg);
|
||||
strlcpy(msg->title, "Token Symbol", msg->titleLength);
|
||||
starkware_print_ticker(msg->msg, msg->msgLength);
|
||||
break;
|
||||
|
||||
case STARKWARE_WITHDRAW_NFT:
|
||||
case STARKWARE_WITHDRAW_NFT_TO:
|
||||
case STARKWARE_DEPOSIT_NFT:
|
||||
case STARKWARE_DEPOSIT_NFT_RECLAIM:
|
||||
strcpy(msg->title, "NFT Contract");
|
||||
starkware_print_asset_contract(msg->msg);
|
||||
strlcpy(msg->title, "NFT Contract", msg->titleLength);
|
||||
starkware_print_asset_contract(msg->msg, msg->msgLength);
|
||||
break;
|
||||
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN:
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_ETH:
|
||||
strcpy(msg->title, "Token Account");
|
||||
strlcpy(msg->title, "Token Account", msg->titleLength);
|
||||
starkware_print_vault_id(U4BE(context->vaultId, 0), msg->msg);
|
||||
break;
|
||||
|
||||
@@ -850,18 +855,19 @@ void starkware_plugin_call(int message, void *parameters) {
|
||||
case STARKWARE_WITHDRAW_NFT_TO:
|
||||
case STARKWARE_DEPOSIT_NFT:
|
||||
case STARKWARE_DEPOSIT_NFT_RECLAIM:
|
||||
strcpy(msg->title, "TokenID");
|
||||
strlcpy(msg->title, "TokenID", msg->titleLength);
|
||||
starkware_print_stark_key(dataContext.tokenContext.quantum, msg->msg);
|
||||
break;
|
||||
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_TOKEN:
|
||||
case STARKWARE_REGISTER_AND_DEPOSIT_ETH:
|
||||
strcpy(msg->title, "Amount");
|
||||
strlcpy(msg->title, "Amount", msg->titleLength);
|
||||
starkware_print_amount(
|
||||
((context->selectorIndex == STARKWARE_REGISTER_AND_DEPOSIT_ETH)
|
||||
? NULL
|
||||
: context->amount),
|
||||
msg->msg,
|
||||
msg->msgLength,
|
||||
false);
|
||||
break;
|
||||
|
||||
|
||||
BIN
tests/snapshots/send/nanos/network.png
Normal file
|
After Width: | Height: | Size: 477 B |
BIN
tests/snapshots/send/nanox/network.png
Normal file
|
After Width: | Height: | Size: 585 B |
|
Before Width: | Height: | Size: 474 B After Width: | Height: | Size: 499 B |
|
Before Width: | Height: | Size: 382 B |
|
Before Width: | Height: | Size: 545 B After Width: | Height: | Size: 569 B |
BIN
tests/snapshots/send_bsc/nanos/network.png
Normal file
|
After Width: | Height: | Size: 449 B |
|
Before Width: | Height: | Size: 860 B After Width: | Height: | Size: 884 B |
|
Before Width: | Height: | Size: 473 B |
|
Before Width: | Height: | Size: 669 B After Width: | Height: | Size: 692 B |
BIN
tests/snapshots/send_bsc/nanox/network.png
Normal file
|
After Width: | Height: | Size: 555 B |
BIN
tests/snapshots/send_etc/nanos/accept.png
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
tests/snapshots/send_etc/nanos/address_1.png
Normal file
|
After Width: | Height: | Size: 809 B |
BIN
tests/snapshots/send_etc/nanos/address_2.png
Normal file
|
After Width: | Height: | Size: 837 B |
BIN
tests/snapshots/send_etc/nanos/address_3.png
Normal file
|
After Width: | Height: | Size: 567 B |
BIN
tests/snapshots/send_etc/nanos/amount_1.png
Normal file
|
After Width: | Height: | Size: 475 B |
BIN
tests/snapshots/send_etc/nanos/amount_2.png
Normal file
|
After Width: | Height: | Size: 759 B |
BIN
tests/snapshots/send_etc/nanos/amount_3.png
Normal file
|
After Width: | Height: | Size: 479 B |
BIN
tests/snapshots/send_etc/nanos/fees.png
Normal file
|
After Width: | Height: | Size: 557 B |
BIN
tests/snapshots/send_etc/nanos/review.png
Normal file
|
After Width: | Height: | Size: 541 B |
BIN
tests/snapshots/send_etc/nanox/accept.png
Normal file
|
After Width: | Height: | Size: 667 B |
BIN
tests/snapshots/send_etc/nanox/address.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
tests/snapshots/send_etc/nanox/amount.png
Normal file
|
After Width: | Height: | Size: 869 B |
BIN
tests/snapshots/send_etc/nanox/fees.png
Normal file
|
After Width: | Height: | Size: 688 B |
BIN
tests/snapshots/send_etc/nanox/review.png
Normal file
|
After Width: | Height: | Size: 633 B |
@@ -18,11 +18,21 @@ const Resolve = require("path").resolve;
|
||||
const NANOS_ELF_PATH = Resolve("elfs/ethereum_nanos.elf");
|
||||
const NANOX_ELF_PATH = Resolve("elfs/ethereum_nanox.elf");
|
||||
|
||||
const NANOS_ETH_LIB = { "Ethereum": NANOS_ELF_PATH };
|
||||
const NANOX_ETH_LIB = { "Ethereum": NANOX_ELF_PATH };
|
||||
|
||||
const NANOS_CLONE_ELF_PATH = Resolve("elfs/ethereum_classic_nanos.elf");
|
||||
const NANOX_CLONE_ELF_PATH = Resolve("elfs/ethereum_classic_nanox.elf");
|
||||
|
||||
const TIMEOUT = 1000000;
|
||||
|
||||
module.exports = {
|
||||
NANOS_ELF_PATH,
|
||||
NANOX_ELF_PATH,
|
||||
NANOS_ETH_LIB,
|
||||
NANOX_ETH_LIB,
|
||||
NANOS_CLONE_ELF_PATH,
|
||||
NANOX_CLONE_ELF_PATH,
|
||||
sim_options_nanos,
|
||||
sim_options_nanox,
|
||||
TIMEOUT,
|
||||
|
||||
@@ -17,7 +17,7 @@ const ORIGINAL_SNAPSHOT_PATH_NANOX = ORIGINAL_SNAPSHOT_PATH_PREFIX + "nanox/";
|
||||
const SNAPSHOT_PATH_NANOS = SNAPSHOT_PATH_PREFIX + "nanos/";
|
||||
const SNAPSHOT_PATH_NANOX = SNAPSHOT_PATH_PREFIX + "nanox/";
|
||||
|
||||
test("Transfer nanos", async () => {
|
||||
test("Transfer Ether on Ethereum app nanos", async () => {
|
||||
jest.setTimeout(TIMEOUT);
|
||||
const sim = new Zemu(NANOS_ELF_PATH);
|
||||
|
||||
@@ -106,7 +106,103 @@ test("Transfer nanos", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("Transfer nanox", async () => {
|
||||
test("Transfer on network 5234 on Ethereum nanos", async () => {
|
||||
jest.setTimeout(TIMEOUT);
|
||||
const sim = new Zemu(NANOS_ELF_PATH);
|
||||
|
||||
try {
|
||||
await sim.start(sim_options_nanos);
|
||||
|
||||
let transport = await sim.getTransport();
|
||||
|
||||
let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex");
|
||||
|
||||
// Send transaction
|
||||
let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer);
|
||||
let filename;
|
||||
|
||||
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
|
||||
// Review tx
|
||||
filename = "review.png";
|
||||
await sim.snapshot(SNAPSHOT_PATH_NANOS + filename);
|
||||
const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(review).toEqual(expected_review);
|
||||
|
||||
// Amount 1/3
|
||||
filename = "amount_1.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const amount_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_amount_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(amount_1).toEqual(expected_amount_1);
|
||||
|
||||
// Amount 2/3
|
||||
filename = "amount_2.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const amount_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_amount_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(amount_2).toEqual(expected_amount_2);
|
||||
|
||||
// Amount 3/3
|
||||
filename = "amount_3.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const amount_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_amount_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(amount_3).toEqual(expected_amount_3);
|
||||
|
||||
// Address 1/3
|
||||
filename = "address_1.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const address_1 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_address_1 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(address_1).toEqual(expected_address_1);
|
||||
|
||||
// Address 2/3
|
||||
filename = "address_2.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const address_2 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_address_2 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(address_2).toEqual(expected_address_2);
|
||||
|
||||
// Address 3/3
|
||||
filename = "address_3.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const address_3 = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(address_3).toEqual(expected_address_3);
|
||||
|
||||
// Network
|
||||
filename = "network.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const network = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(network).toEqual(expected_network);
|
||||
|
||||
// Max Fees
|
||||
filename = "fees.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(fees).toEqual(expected_fees);
|
||||
|
||||
// Accept
|
||||
filename = "accept.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(accept).toEqual(expected_accept);
|
||||
|
||||
await sim.clickBoth();
|
||||
|
||||
await expect(tx).resolves.toEqual(
|
||||
Buffer.from("08f3449bbc245669e26dd076986e11aa3117e2405ffe2ddc7a7e220f81326fbd91150515605c78119367be311345e9ff40c4e4ddb9ec0fd81f37035c3828f4c8b29000", 'hex')
|
||||
);
|
||||
} finally {
|
||||
await sim.close();
|
||||
}
|
||||
});
|
||||
|
||||
test("Transfer Ether on Ethereum nanox", async () => {
|
||||
jest.setTimeout(TIMEOUT);
|
||||
const sim = new Zemu(NANOX_ELF_PATH);
|
||||
|
||||
@@ -164,4 +260,73 @@ test("Transfer nanox", async () => {
|
||||
} finally {
|
||||
await sim.close();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("Transfer on network 5234 on Ethereum nanox", async () => {
|
||||
jest.setTimeout(TIMEOUT);
|
||||
const sim = new Zemu(NANOX_ELF_PATH);
|
||||
|
||||
try {
|
||||
await sim.start(sim_options_nanox);
|
||||
|
||||
let transport = await sim.getTransport();
|
||||
|
||||
let buffer = Buffer.from("058000002C8000003C800000010000000000000000EB44850306DC4200825208945A321744667052AFFA8386ED49E00EF223CBFFC3876F9C9E7BF61818808214728080", "hex");
|
||||
|
||||
// Send transaction
|
||||
let tx = transport.send(0xe0, 0x04, 0x00, 0x00, buffer);
|
||||
let filename;
|
||||
|
||||
await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot());
|
||||
// Review tx
|
||||
filename = "review.png";
|
||||
await sim.snapshot(SNAPSHOT_PATH_NANOX + filename);
|
||||
const review = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
|
||||
const expected_review = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
|
||||
expect(review).toEqual(expected_review);
|
||||
|
||||
// Amount
|
||||
filename = "amount.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
|
||||
const amount = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
|
||||
const expected_amount = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
|
||||
expect(amount).toEqual(expected_amount);
|
||||
|
||||
// Address
|
||||
filename = "address.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
|
||||
const address = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
|
||||
const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
|
||||
expect(address).toEqual(expected_address);
|
||||
|
||||
// Network
|
||||
filename = "network.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
|
||||
const network = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
|
||||
const expected_network = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
|
||||
expect(network).toEqual(expected_network);
|
||||
|
||||
// Max Fees
|
||||
filename = "fees.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
|
||||
const fees = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
|
||||
const expected_fees = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
|
||||
expect(fees).toEqual(expected_fees);
|
||||
|
||||
// Accept
|
||||
filename = "accept.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
|
||||
const accept = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
|
||||
const expected_accept = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
|
||||
expect(accept).toEqual(expected_accept);
|
||||
|
||||
await sim.clickBoth();
|
||||
|
||||
await expect(tx).resolves.toEqual(
|
||||
Buffer.from("08f3449bbc245669e26dd076986e11aa3117e2405ffe2ddc7a7e220f81326fbd91150515605c78119367be311345e9ff40c4e4ddb9ec0fd81f37035c3828f4c8b29000", 'hex')
|
||||
);
|
||||
} finally {
|
||||
await sim.close();
|
||||
}
|
||||
});
|
||||
@@ -83,8 +83,8 @@ test("Transfer bsc nanos", async () => {
|
||||
const expected_address_3 = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
expect(address_3).toEqual(expected_address_3);
|
||||
|
||||
// Chain ID
|
||||
filename = "chainid.png";
|
||||
// Network name
|
||||
filename = "network.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOS + filename);
|
||||
const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOS + filename);
|
||||
const expected_chainid = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOS + filename);
|
||||
@@ -151,8 +151,8 @@ test("Transfer bsc nanox", async () => {
|
||||
const expected_address = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
|
||||
expect(address).toEqual(expected_address);
|
||||
|
||||
// Chain ID
|
||||
filename = "chainid.png";
|
||||
// Network name
|
||||
filename = "network.png";
|
||||
await sim.clickRight(SNAPSHOT_PATH_NANOX + filename);
|
||||
const chainid = Zemu.LoadPng2RGB(SNAPSHOT_PATH_NANOX + filename);
|
||||
const expected_chainid = Zemu.LoadPng2RGB(ORIGINAL_SNAPSHOT_PATH_NANOX + filename);
|
||||
|
||||
208
tests/src/send_etc.test.js
Normal file
@@ -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();
|
||||
}
|
||||
});
|
||||